Chris@87
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@87
|
2
|
Chris@87
|
3 /*
|
Chris@87
|
4 Sonic Visualiser
|
Chris@87
|
5 An audio file viewer and annotation editor.
|
Chris@87
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@87
|
7 This file copyright 2006 Chris Cannam.
|
Chris@87
|
8
|
Chris@87
|
9 This program is free software; you can redistribute it and/or
|
Chris@87
|
10 modify it under the terms of the GNU General Public License as
|
Chris@87
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@87
|
12 License, or (at your option) any later version. See the file
|
Chris@87
|
13 COPYING included with this distribution for more information.
|
Chris@87
|
14 */
|
Chris@87
|
15
|
Chris@87
|
16 #include "MatrixFileCache.h"
|
Chris@87
|
17 #include "base/TempDirectory.h"
|
Chris@90
|
18 #include "base/System.h"
|
Chris@87
|
19
|
Chris@87
|
20 #include <sys/types.h>
|
Chris@87
|
21 #include <sys/stat.h>
|
Chris@87
|
22 #include <fcntl.h>
|
Chris@87
|
23 #include <unistd.h>
|
Chris@87
|
24
|
Chris@87
|
25 #include <iostream>
|
Chris@87
|
26
|
Chris@87
|
27 #include <cstdio>
|
Chris@87
|
28
|
Chris@87
|
29 #include <QFileInfo>
|
Chris@91
|
30 #include <QFile>
|
Chris@87
|
31 #include <QDir>
|
Chris@87
|
32
|
Chris@91
|
33 //#define HAVE_MMAP 1
|
Chris@90
|
34
|
Chris@90
|
35 #ifdef HAVE_MMAP
|
Chris@90
|
36 #include <sys/mman.h>
|
Chris@90
|
37 #endif
|
Chris@90
|
38
|
Chris@91
|
39 std::map<QString, int> MatrixFileCache::m_refcount;
|
Chris@91
|
40 QMutex MatrixFileCache::m_refcountMutex;
|
Chris@91
|
41
|
Chris@90
|
42 //!!! This class is a work in progress -- it does only as much as we
|
Chris@90
|
43 // need for the current SpectrogramLayer. Slated for substantial
|
Chris@90
|
44 // refactoring and extension.
|
Chris@90
|
45
|
Chris@87
|
46 MatrixFileCache::MatrixFileCache(QString fileBase, Mode mode) :
|
Chris@87
|
47 m_fd(-1),
|
Chris@87
|
48 m_mode(mode),
|
Chris@87
|
49 m_width(0),
|
Chris@87
|
50 m_height(0),
|
Chris@90
|
51 m_headerSize(2 * sizeof(size_t)),
|
Chris@91
|
52 m_autoRegionWidth(256),
|
Chris@90
|
53 m_off(-1),
|
Chris@87
|
54 m_rx(0),
|
Chris@87
|
55 m_rw(0),
|
Chris@90
|
56 m_userRegion(false),
|
Chris@90
|
57 m_region(0),
|
Chris@90
|
58 m_mmapped(false),
|
Chris@90
|
59 m_mmapSize(0),
|
Chris@90
|
60 m_mmapOff(0),
|
Chris@91
|
61 m_preferMmap(false)
|
Chris@87
|
62 {
|
Chris@90
|
63 // Ensure header size is a multiple of the size of our data (for
|
Chris@90
|
64 // alignment purposes)
|
Chris@90
|
65 size_t hs = ((m_headerSize / sizeof(float)) * sizeof(float));
|
Chris@90
|
66 if (hs != m_headerSize) m_headerSize = hs + sizeof(float);
|
Chris@90
|
67
|
Chris@87
|
68 QDir tempDir(TempDirectory::instance()->getPath());
|
Chris@87
|
69 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase)));
|
Chris@87
|
70 bool newFile = !QFileInfo(fileName).exists();
|
Chris@87
|
71
|
Chris@87
|
72 if (newFile && mode == ReadOnly) {
|
Chris@87
|
73 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: Read-only mode "
|
Chris@87
|
74 << "specified, but cache file does not exist" << std::endl;
|
Chris@87
|
75 return;
|
Chris@87
|
76 }
|
Chris@87
|
77
|
Chris@87
|
78 int flags = 0;
|
Chris@87
|
79 mode_t fmode = S_IRUSR | S_IWUSR;
|
Chris@87
|
80
|
Chris@87
|
81 if (mode == ReadWrite) {
|
Chris@87
|
82 flags = O_RDWR | O_CREAT;
|
Chris@87
|
83 } else {
|
Chris@87
|
84 flags = O_RDONLY;
|
Chris@87
|
85 }
|
Chris@87
|
86
|
Chris@90
|
87 if ((m_fd = ::open(fileName.toLocal8Bit(), flags, fmode)) < 0) {
|
Chris@87
|
88 ::perror("Open failed");
|
Chris@87
|
89 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: "
|
Chris@87
|
90 << "Failed to open cache file \""
|
Chris@87
|
91 << fileName.toStdString() << "\"";
|
Chris@87
|
92 if (mode == ReadWrite) std::cerr << " for writing";
|
Chris@87
|
93 std::cerr << std::endl;
|
Chris@91
|
94 return;
|
Chris@87
|
95 }
|
Chris@87
|
96
|
Chris@87
|
97 if (newFile) {
|
Chris@87
|
98 resize(0, 0); // write header
|
Chris@87
|
99 } else {
|
Chris@87
|
100 size_t header[2];
|
Chris@90
|
101 if (::read(m_fd, header, 2 * sizeof(size_t)) < 0) {
|
Chris@87
|
102 perror("Read failed");
|
Chris@87
|
103 std::cerr << "ERROR: MatrixFileCache::MatrixFileCache: "
|
Chris@90
|
104 << "Failed to read header (fd " << m_fd << ", file \""
|
Chris@90
|
105 << fileName.toStdString() << "\")" << std::endl;
|
Chris@87
|
106 return;
|
Chris@87
|
107 }
|
Chris@87
|
108 m_width = header[0];
|
Chris@87
|
109 m_height = header[1];
|
Chris@87
|
110 seekTo(0, 0);
|
Chris@87
|
111 }
|
Chris@87
|
112
|
Chris@91
|
113 m_fileName = fileName;
|
Chris@91
|
114 QMutexLocker locker(&m_refcountMutex);
|
Chris@91
|
115 ++m_refcount[fileName];
|
Chris@91
|
116
|
Chris@90
|
117 std::cerr << "MatrixFileCache::MatrixFileCache: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl;
|
Chris@87
|
118
|
Chris@87
|
119 }
|
Chris@87
|
120
|
Chris@87
|
121 MatrixFileCache::~MatrixFileCache()
|
Chris@87
|
122 {
|
Chris@90
|
123 if (m_rw > 0) {
|
Chris@90
|
124 if (m_mmapped) {
|
Chris@90
|
125 #ifdef HAVE_MMAP
|
Chris@90
|
126 ::munmap(m_region, m_mmapSize);
|
Chris@90
|
127 #endif
|
Chris@90
|
128 } else {
|
Chris@90
|
129 delete[] m_region;
|
Chris@90
|
130 }
|
Chris@90
|
131 }
|
Chris@90
|
132
|
Chris@87
|
133 if (m_fd >= 0) {
|
Chris@87
|
134 if (::close(m_fd) < 0) {
|
Chris@87
|
135 ::perror("MatrixFileCache::~MatrixFileCache: close failed");
|
Chris@87
|
136 }
|
Chris@87
|
137 }
|
Chris@90
|
138
|
Chris@91
|
139 if (m_fileName != "") {
|
Chris@91
|
140 QMutexLocker locker(&m_refcountMutex);
|
Chris@91
|
141 if (--m_refcount[m_fileName] == 0) {
|
Chris@91
|
142 if (!QFile(m_fileName).remove()) {
|
Chris@91
|
143 std::cerr << "WARNING: MatrixFileCache::~MatrixFileCache: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl;
|
Chris@91
|
144 } else {
|
Chris@91
|
145 std::cerr << "deleted " << m_fileName.toStdString() << std::endl;
|
Chris@91
|
146 }
|
Chris@91
|
147 }
|
Chris@91
|
148 }
|
Chris@87
|
149 }
|
Chris@87
|
150
|
Chris@87
|
151 size_t
|
Chris@87
|
152 MatrixFileCache::getWidth() const
|
Chris@87
|
153 {
|
Chris@87
|
154 return m_width;
|
Chris@87
|
155 }
|
Chris@87
|
156
|
Chris@87
|
157 size_t
|
Chris@87
|
158 MatrixFileCache::getHeight() const
|
Chris@87
|
159 {
|
Chris@87
|
160 return m_height;
|
Chris@87
|
161 }
|
Chris@87
|
162
|
Chris@87
|
163 void
|
Chris@87
|
164 MatrixFileCache::resize(size_t w, size_t h)
|
Chris@87
|
165 {
|
Chris@87
|
166 if (m_mode != ReadWrite) {
|
Chris@87
|
167 std::cerr << "ERROR: MatrixFileCache::resize called on read-only cache"
|
Chris@87
|
168 << std::endl;
|
Chris@87
|
169 return;
|
Chris@87
|
170 }
|
Chris@87
|
171
|
Chris@87
|
172 off_t off = m_headerSize + (w * h * sizeof(float));
|
Chris@87
|
173
|
Chris@87
|
174 if (w * h > m_width * m_height) {
|
Chris@87
|
175
|
Chris@90
|
176 #ifdef HAVE_MMAP
|
Chris@90
|
177 // If we're going to mmap the file, we need to ensure it's long
|
Chris@90
|
178 // enough beforehand
|
Chris@90
|
179
|
Chris@90
|
180 if (m_preferMmap) {
|
Chris@90
|
181
|
Chris@90
|
182 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) {
|
Chris@90
|
183 ::perror("Seek failed");
|
Chris@90
|
184 std::cerr << "ERROR: MatrixFileCache::resize(" << w << ", "
|
Chris@90
|
185 << h << "): seek failed, cannot resize" << std::endl;
|
Chris@90
|
186 return;
|
Chris@90
|
187 }
|
Chris@90
|
188
|
Chris@90
|
189 // guess this requires efficient support for sparse files
|
Chris@90
|
190
|
Chris@90
|
191 float f(0);
|
Chris@90
|
192 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) {
|
Chris@90
|
193 ::perror("WARNING: MatrixFileCache::resize: write failed");
|
Chris@90
|
194 }
|
Chris@87
|
195 }
|
Chris@90
|
196 #endif
|
Chris@87
|
197
|
Chris@87
|
198 } else {
|
Chris@87
|
199
|
Chris@87
|
200 if (::ftruncate(m_fd, off) < 0) {
|
Chris@90
|
201 ::perror("WARNING: MatrixFileCache::resize: ftruncate failed");
|
Chris@87
|
202 }
|
Chris@87
|
203 }
|
Chris@87
|
204
|
Chris@87
|
205 m_width = 0;
|
Chris@87
|
206 m_height = 0;
|
Chris@87
|
207 m_off = 0;
|
Chris@87
|
208
|
Chris@87
|
209 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) {
|
Chris@87
|
210 ::perror("ERROR: MatrixFileCache::resize: Seek to write header failed");
|
Chris@87
|
211 return;
|
Chris@87
|
212 }
|
Chris@87
|
213
|
Chris@87
|
214 size_t header[2];
|
Chris@87
|
215 header[0] = w;
|
Chris@87
|
216 header[1] = h;
|
Chris@87
|
217 if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) {
|
Chris@87
|
218 ::perror("ERROR: MatrixFileCache::resize: Failed to write header");
|
Chris@87
|
219 return;
|
Chris@87
|
220 }
|
Chris@87
|
221
|
Chris@87
|
222 m_width = w;
|
Chris@87
|
223 m_height = h;
|
Chris@87
|
224
|
Chris@87
|
225 seekTo(0, 0);
|
Chris@87
|
226 }
|
Chris@87
|
227
|
Chris@87
|
228 void
|
Chris@87
|
229 MatrixFileCache::reset()
|
Chris@87
|
230 {
|
Chris@87
|
231 if (m_mode != ReadWrite) {
|
Chris@87
|
232 std::cerr << "ERROR: MatrixFileCache::reset called on read-only cache"
|
Chris@87
|
233 << std::endl;
|
Chris@87
|
234 return;
|
Chris@87
|
235 }
|
Chris@87
|
236
|
Chris@90
|
237 float *emptyCol = new float[m_height];
|
Chris@90
|
238 for (size_t y = 0; y < m_height; ++y) emptyCol[y] = 0.f;
|
Chris@90
|
239
|
Chris@90
|
240 seekTo(0, 0);
|
Chris@90
|
241 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol);
|
Chris@90
|
242
|
Chris@90
|
243 delete[] emptyCol;
|
Chris@87
|
244 }
|
Chris@87
|
245
|
Chris@87
|
246 void
|
Chris@90
|
247 MatrixFileCache::setRegionOfInterest(size_t x, size_t width)
|
Chris@87
|
248 {
|
Chris@90
|
249 setRegion(x, width, true);
|
Chris@90
|
250 }
|
Chris@90
|
251
|
Chris@90
|
252 void
|
Chris@90
|
253 MatrixFileCache::clearRegionOfInterest()
|
Chris@90
|
254 {
|
Chris@90
|
255 m_userRegion = false;
|
Chris@87
|
256 }
|
Chris@87
|
257
|
Chris@87
|
258 float
|
Chris@87
|
259 MatrixFileCache::getValueAt(size_t x, size_t y) const
|
Chris@87
|
260 {
|
Chris@87
|
261 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) {
|
Chris@90
|
262 float *rp = getRegionPtr(x, y);
|
Chris@90
|
263 if (rp) return *rp;
|
Chris@90
|
264 } else if (!m_userRegion) {
|
Chris@90
|
265 if (autoSetRegion(x)) {
|
Chris@90
|
266 float *rp = getRegionPtr(x, y);
|
Chris@90
|
267 if (rp) return *rp;
|
Chris@91
|
268 else return 0.f;
|
Chris@90
|
269 }
|
Chris@87
|
270 }
|
Chris@87
|
271
|
Chris@87
|
272 if (!seekTo(x, y)) return 0.f;
|
Chris@87
|
273 float value;
|
Chris@90
|
274 ssize_t r = ::read(m_fd, &value, sizeof(float));
|
Chris@91
|
275 if (r < 0) {
|
Chris@91
|
276 ::perror("MatrixFileCache::getValueAt: Read failed");
|
Chris@91
|
277 }
|
Chris@90
|
278 if (r != sizeof(float)) {
|
Chris@90
|
279 value = 0.f;
|
Chris@87
|
280 }
|
Chris@90
|
281 if (r > 0) m_off += r;
|
Chris@87
|
282 return value;
|
Chris@87
|
283 }
|
Chris@87
|
284
|
Chris@87
|
285 void
|
Chris@87
|
286 MatrixFileCache::getColumnAt(size_t x, float *values) const
|
Chris@87
|
287 {
|
Chris@87
|
288 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) {
|
Chris@90
|
289 float *rp = getRegionPtr(x, 0);
|
Chris@90
|
290 if (rp) {
|
Chris@90
|
291 for (size_t y = 0; y < m_height; ++y) {
|
Chris@90
|
292 values[y] = rp[y];
|
Chris@90
|
293 }
|
Chris@90
|
294 }
|
Chris@91
|
295 return;
|
Chris@90
|
296 } else if (!m_userRegion) {
|
Chris@90
|
297 if (autoSetRegion(x)) {
|
Chris@90
|
298 float *rp = getRegionPtr(x, 0);
|
Chris@90
|
299 if (rp) {
|
Chris@90
|
300 for (size_t y = 0; y < m_height; ++y) {
|
Chris@90
|
301 values[y] = rp[y];
|
Chris@90
|
302 }
|
Chris@90
|
303 return;
|
Chris@90
|
304 }
|
Chris@87
|
305 }
|
Chris@87
|
306 }
|
Chris@87
|
307
|
Chris@87
|
308 if (!seekTo(x, 0)) return;
|
Chris@90
|
309 ssize_t r = ::read(m_fd, values, m_height * sizeof(float));
|
Chris@91
|
310 if (r < 0) {
|
Chris@87
|
311 ::perror("MatrixFileCache::getColumnAt: read failed");
|
Chris@87
|
312 }
|
Chris@90
|
313 if (r > 0) m_off += r;
|
Chris@87
|
314 }
|
Chris@87
|
315
|
Chris@87
|
316 void
|
Chris@87
|
317 MatrixFileCache::setValueAt(size_t x, size_t y, float value)
|
Chris@87
|
318 {
|
Chris@87
|
319 if (m_mode != ReadWrite) {
|
Chris@87
|
320 std::cerr << "ERROR: MatrixFileCache::setValueAt called on read-only cache"
|
Chris@87
|
321 << std::endl;
|
Chris@87
|
322 return;
|
Chris@87
|
323 }
|
Chris@87
|
324
|
Chris@87
|
325 if (!seekTo(x, y)) return;
|
Chris@90
|
326 ssize_t w = ::write(m_fd, &value, sizeof(float));
|
Chris@90
|
327 if (w != sizeof(float)) {
|
Chris@87
|
328 ::perror("WARNING: MatrixFileCache::setValueAt: write failed");
|
Chris@87
|
329 }
|
Chris@90
|
330 if (w > 0) m_off += w;
|
Chris@87
|
331
|
Chris@90
|
332 //... update region as appropriate
|
Chris@87
|
333 }
|
Chris@87
|
334
|
Chris@87
|
335 void
|
Chris@87
|
336 MatrixFileCache::setColumnAt(size_t x, float *values)
|
Chris@87
|
337 {
|
Chris@87
|
338 if (m_mode != ReadWrite) {
|
Chris@87
|
339 std::cerr << "ERROR: MatrixFileCache::setColumnAt called on read-only cache"
|
Chris@87
|
340 << std::endl;
|
Chris@87
|
341 return;
|
Chris@87
|
342 }
|
Chris@87
|
343
|
Chris@87
|
344 if (!seekTo(x, 0)) return;
|
Chris@90
|
345 ssize_t w = ::write(m_fd, values, m_height * sizeof(float));
|
Chris@91
|
346 if (w != ssize_t(m_height * sizeof(float))) {
|
Chris@87
|
347 ::perror("WARNING: MatrixFileCache::setColumnAt: write failed");
|
Chris@87
|
348 }
|
Chris@90
|
349 if (w > 0) m_off += w;
|
Chris@87
|
350
|
Chris@90
|
351 //... update region as appropriate
|
Chris@90
|
352 }
|
Chris@90
|
353
|
Chris@90
|
354 float *
|
Chris@90
|
355 MatrixFileCache::getRegionPtr(size_t x, size_t y) const
|
Chris@90
|
356 {
|
Chris@90
|
357 if (m_rw == 0) return 0;
|
Chris@90
|
358
|
Chris@90
|
359 float *region = m_region;
|
Chris@90
|
360
|
Chris@90
|
361 if (m_mmapOff > 0) {
|
Chris@90
|
362 char *cr = (char *)m_region;
|
Chris@90
|
363 cr += m_mmapOff;
|
Chris@90
|
364 region = (float *)cr;
|
Chris@90
|
365 }
|
Chris@90
|
366
|
Chris@90
|
367 float *ptr = &(region[(x - m_rx) * m_height + y]);
|
Chris@90
|
368
|
Chris@90
|
369 // std::cerr << "getRegionPtr(" << x << "," << y << "): region is " << m_region << ", returning " << ptr << std::endl;
|
Chris@90
|
370 return ptr;
|
Chris@90
|
371 }
|
Chris@90
|
372
|
Chris@90
|
373 bool
|
Chris@90
|
374 MatrixFileCache::autoSetRegion(size_t x) const
|
Chris@90
|
375 {
|
Chris@90
|
376 size_t rx = x;
|
Chris@90
|
377 size_t rw = m_autoRegionWidth;
|
Chris@90
|
378 size_t left = rw / 4;
|
Chris@90
|
379 if (x < m_rx) left = (rw * 3) / 4;
|
Chris@90
|
380 if (rx > left) rx -= left;
|
Chris@90
|
381 else rx = 0;
|
Chris@90
|
382 if (rx + rw > m_width) rw = m_width - rx;
|
Chris@90
|
383 return setRegion(rx, rw, false);
|
Chris@90
|
384 }
|
Chris@90
|
385
|
Chris@90
|
386 bool
|
Chris@90
|
387 MatrixFileCache::setRegion(size_t x, size_t width, bool user) const
|
Chris@90
|
388 {
|
Chris@90
|
389 if (!user && m_userRegion) return false;
|
Chris@90
|
390 if (m_rw > 0 && x >= m_rx && x + width <= m_rx + m_rw) return true;
|
Chris@90
|
391
|
Chris@90
|
392 if (m_rw > 0) {
|
Chris@90
|
393 if (m_mmapped) {
|
Chris@90
|
394 #ifdef HAVE_MMAP
|
Chris@90
|
395 ::munmap(m_region, m_mmapSize);
|
Chris@90
|
396 std::cerr << "unmapped " << m_mmapSize << " at " << m_region << std::endl;
|
Chris@90
|
397 #endif
|
Chris@90
|
398 } else {
|
Chris@90
|
399 delete[] m_region;
|
Chris@90
|
400 }
|
Chris@90
|
401 m_region = 0;
|
Chris@90
|
402 m_mmapped = false;
|
Chris@90
|
403 m_mmapSize = 0;
|
Chris@90
|
404 m_mmapOff = 0;
|
Chris@90
|
405 m_rw = 0;
|
Chris@90
|
406 }
|
Chris@90
|
407
|
Chris@90
|
408 if (width == 0) {
|
Chris@90
|
409 return true;
|
Chris@90
|
410 }
|
Chris@90
|
411
|
Chris@90
|
412 #ifdef HAVE_MMAP
|
Chris@90
|
413
|
Chris@90
|
414 if (m_preferMmap) {
|
Chris@90
|
415
|
Chris@90
|
416 size_t mmapSize = m_height * width * sizeof(float);
|
Chris@90
|
417 off_t offset = m_headerSize + (x * m_height) * sizeof(float);
|
Chris@90
|
418 int pagesize = getpagesize();
|
Chris@90
|
419 off_t aligned = (offset / pagesize) * pagesize;
|
Chris@90
|
420 size_t mmapOff = offset - aligned;
|
Chris@90
|
421 mmapSize += mmapOff;
|
Chris@90
|
422
|
Chris@90
|
423 m_region = (float *)
|
Chris@90
|
424 ::mmap(0, mmapSize, PROT_READ, MAP_PRIVATE, m_fd, aligned);
|
Chris@90
|
425
|
Chris@90
|
426 if (m_region == MAP_FAILED) {
|
Chris@90
|
427
|
Chris@90
|
428 ::perror("Mmap failed");
|
Chris@90
|
429 std::cerr << "ERROR: MatrixFileCache::setRegion(" << x << ", "
|
Chris@90
|
430 << width << "): Mmap(0, " << mmapSize
|
Chris@90
|
431 << ", " << PROT_READ << ", " << MAP_SHARED << ", " << m_fd
|
Chris@90
|
432 << ", " << aligned << ") failed, falling back to "
|
Chris@90
|
433 << "non-mmapping code for this cache" << std::endl;
|
Chris@90
|
434 m_preferMmap = false;
|
Chris@90
|
435
|
Chris@90
|
436 } else {
|
Chris@90
|
437
|
Chris@90
|
438 std::cerr << "mmap succeeded (offset " << aligned << ", size " << mmapSize << ", m_mmapOff " << mmapOff << ") = " << m_region << std::endl;
|
Chris@90
|
439
|
Chris@90
|
440 m_mmapped = true;
|
Chris@90
|
441 m_mmapSize = mmapSize;
|
Chris@90
|
442 m_mmapOff = mmapOff;
|
Chris@90
|
443 m_rx = x;
|
Chris@90
|
444 m_rw = width;
|
Chris@90
|
445 if (user) m_userRegion = true;
|
Chris@91
|
446 MUNLOCK(m_region, m_mmapSize);
|
Chris@90
|
447 return true;
|
Chris@90
|
448 }
|
Chris@90
|
449 }
|
Chris@90
|
450 #endif
|
Chris@90
|
451
|
Chris@90
|
452 if (!seekTo(x, 0)) return false;
|
Chris@90
|
453
|
Chris@90
|
454 m_region = new float[width * m_height];
|
Chris@91
|
455 MUNLOCK(m_region, width * m_height * sizeof(float));
|
Chris@90
|
456
|
Chris@90
|
457 ssize_t r = ::read(m_fd, m_region, width * m_height * sizeof(float));
|
Chris@90
|
458 if (r < 0) {
|
Chris@90
|
459 ::perror("Read failed");
|
Chris@90
|
460 std::cerr << "ERROR: MatrixFileCache::setRegion(" << x << ", " << width
|
Chris@90
|
461 << ") failed" << std::endl;
|
Chris@90
|
462 delete[] m_region;
|
Chris@90
|
463 m_region = 0;
|
Chris@90
|
464 return false;
|
Chris@90
|
465 }
|
Chris@90
|
466
|
Chris@90
|
467 m_off += r;
|
Chris@90
|
468
|
Chris@91
|
469 if (r < ssize_t(width * m_height * sizeof(float))) {
|
Chris@90
|
470 // didn't manage to read the whole thing, but did get something
|
Chris@90
|
471 std::cerr << "WARNING: MatrixFileCache::setRegion(" << x << ", " << width
|
Chris@90
|
472 << "): ";
|
Chris@90
|
473 width = r / (m_height * sizeof(float));
|
Chris@90
|
474 std::cerr << "Only got " << width << " columns" << std::endl;
|
Chris@90
|
475 }
|
Chris@90
|
476
|
Chris@90
|
477 m_rx = x;
|
Chris@90
|
478 m_rw = width;
|
Chris@90
|
479 if (m_rw == 0) {
|
Chris@90
|
480 delete[] m_region;
|
Chris@90
|
481 m_region = 0;
|
Chris@90
|
482 }
|
Chris@90
|
483
|
Chris@90
|
484 std::cerr << "MatrixFileCache::setRegion: set region to " << x << ", " << width << std::endl;
|
Chris@90
|
485
|
Chris@90
|
486 if (user) m_userRegion = true;
|
Chris@90
|
487 return true;
|
Chris@87
|
488 }
|
Chris@87
|
489
|
Chris@87
|
490 bool
|
Chris@87
|
491 MatrixFileCache::seekTo(size_t x, size_t y) const
|
Chris@87
|
492 {
|
Chris@87
|
493 off_t off = m_headerSize + (x * m_height + y) * sizeof(float);
|
Chris@87
|
494 if (off == m_off) return true;
|
Chris@87
|
495
|
Chris@90
|
496 if (m_mode == ReadWrite) {
|
Chris@90
|
497 std::cerr << "writer: ";
|
Chris@90
|
498 std::cerr << "seek required (from " << m_off << " to " << off << ")" << std::endl;
|
Chris@90
|
499 }
|
Chris@90
|
500
|
Chris@87
|
501 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) {
|
Chris@87
|
502 ::perror("Seek failed");
|
Chris@87
|
503 std::cerr << "ERROR: MatrixFileCache::seekTo(" << x << ", " << y
|
Chris@87
|
504 << ") failed" << std::endl;
|
Chris@87
|
505 return false;
|
Chris@87
|
506 }
|
Chris@87
|
507
|
Chris@87
|
508 m_off = off;
|
Chris@87
|
509 return true;
|
Chris@87
|
510 }
|
Chris@87
|
511
|