Mercurial > hg > svcore
comparison base/MatrixFileCache.cpp @ 95:040a151d0897
* Add file reader thread, and make the matrix file code use it to preload
fft cache data without glitching
author | Chris Cannam |
---|---|
date | Thu, 04 May 2006 13:59:57 +0000 |
parents | 27d726916ab3 |
children |
comparison
equal
deleted
inserted
replaced
94:5b8392e80ed6 | 95:040a151d0897 |
---|---|
25 #include <iostream> | 25 #include <iostream> |
26 | 26 |
27 #include <cstdio> | 27 #include <cstdio> |
28 | 28 |
29 #include <QFileInfo> | 29 #include <QFileInfo> |
30 #include <QFile> | |
31 #include <QDir> | 30 #include <QDir> |
32 | 31 |
33 std::map<QString, int> MatrixFileCache::m_refcount; | 32 std::map<QString, int> MatrixFileCache::m_refcount; |
34 QMutex MatrixFileCache::m_refcountMutex; | 33 QMutex MatrixFileCache::m_refcountMutex; |
35 | |
36 //!!! This class is a work in progress -- it does only as much as we | |
37 // need for the current SpectrogramLayer. Slated for substantial | |
38 // refactoring and extension. | |
39 | 34 |
40 MatrixFileCache::MatrixFileCache(QString fileBase, Mode mode) : | 35 MatrixFileCache::MatrixFileCache(QString fileBase, Mode mode) : |
41 m_fd(-1), | 36 m_fd(-1), |
42 m_mode(mode), | 37 m_mode(mode), |
43 m_width(0), | 38 m_width(0), |
44 m_height(0), | 39 m_height(0), |
45 m_headerSize(2 * sizeof(size_t)), | 40 m_headerSize(2 * sizeof(size_t)), |
46 m_autoRegionWidth(256), | 41 m_defaultCacheWidth(2048), |
47 m_off(-1), | 42 m_prevX(0), |
48 m_rx(0), | 43 m_requestToken(-1) |
49 m_rw(0), | 44 { |
50 m_userRegion(false), | 45 m_cache.data = 0; |
51 m_region(0) | |
52 { | |
53 // Ensure header size is a multiple of the size of our data (for | |
54 // alignment purposes) | |
55 size_t hs = ((m_headerSize / sizeof(float)) * sizeof(float)); | |
56 if (hs != m_headerSize) m_headerSize = hs + sizeof(float); | |
57 | 46 |
58 QDir tempDir(TempDirectory::instance()->getPath()); | 47 QDir tempDir(TempDirectory::instance()->getPath()); |
59 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase))); | 48 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase))); |
60 bool newFile = !QFileInfo(fileName).exists(); | 49 bool newFile = !QFileInfo(fileName).exists(); |
61 | 50 |
99 m_height = header[1]; | 88 m_height = header[1]; |
100 seekTo(0, 0); | 89 seekTo(0, 0); |
101 } | 90 } |
102 | 91 |
103 m_fileName = fileName; | 92 m_fileName = fileName; |
93 | |
94 //!!! why isn't this signal being delivered? | |
95 connect(&m_readThread, SIGNAL(cancelled(int)), | |
96 this, SLOT(requestCancelled(int))); | |
97 | |
98 m_readThread.start(); | |
99 | |
104 QMutexLocker locker(&m_refcountMutex); | 100 QMutexLocker locker(&m_refcountMutex); |
105 ++m_refcount[fileName]; | 101 ++m_refcount[fileName]; |
106 | 102 |
107 std::cerr << "MatrixFileCache::MatrixFileCache: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; | 103 std::cerr << "MatrixFileCache::MatrixFileCache: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; |
108 | 104 |
109 } | 105 } |
110 | 106 |
111 MatrixFileCache::~MatrixFileCache() | 107 MatrixFileCache::~MatrixFileCache() |
112 { | 108 { |
113 if (m_rw > 0) { | 109 float *requestData = 0; |
114 delete[] m_region; | 110 |
115 } | 111 if (m_requestToken >= 0) { |
112 FileReadThread::Request request; | |
113 if (m_readThread.getRequest(m_requestToken, request)) { | |
114 requestData = (float *)request.data; | |
115 } | |
116 } | |
117 | |
118 m_readThread.finish(); | |
119 m_readThread.wait(); | |
120 | |
121 if (requestData) delete[] requestData; | |
122 if (m_cache.data) delete[] m_cache.data; | |
116 | 123 |
117 if (m_fd >= 0) { | 124 if (m_fd >= 0) { |
118 if (::close(m_fd) < 0) { | 125 if (::close(m_fd) < 0) { |
119 ::perror("MatrixFileCache::~MatrixFileCache: close failed"); | 126 ::perror("MatrixFileCache::~MatrixFileCache: close failed"); |
120 } | 127 } |
121 } | 128 } |
122 | 129 |
123 if (m_fileName != "") { | 130 if (m_fileName != "") { |
124 QMutexLocker locker(&m_refcountMutex); | 131 QMutexLocker locker(&m_refcountMutex); |
125 if (--m_refcount[m_fileName] == 0) { | 132 if (--m_refcount[m_fileName] == 0) { |
126 if (!QFile(m_fileName).remove()) { | 133 if (::unlink(m_fileName.toLocal8Bit())) { |
134 ::perror("Unlink failed"); | |
127 std::cerr << "WARNING: MatrixFileCache::~MatrixFileCache: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; | 135 std::cerr << "WARNING: MatrixFileCache::~MatrixFileCache: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; |
128 } else { | 136 } else { |
129 std::cerr << "deleted " << m_fileName.toStdString() << std::endl; | 137 std::cerr << "deleted " << m_fileName.toStdString() << std::endl; |
130 } | 138 } |
131 } | 139 } |
151 std::cerr << "ERROR: MatrixFileCache::resize called on read-only cache" | 159 std::cerr << "ERROR: MatrixFileCache::resize called on read-only cache" |
152 << std::endl; | 160 << std::endl; |
153 return; | 161 return; |
154 } | 162 } |
155 | 163 |
164 QMutexLocker locker(&m_fdMutex); | |
165 | |
156 off_t off = m_headerSize + (w * h * sizeof(float)); | 166 off_t off = m_headerSize + (w * h * sizeof(float)); |
157 | 167 |
158 if (w * h > m_width * m_height) { | 168 if (w * h > m_width * m_height) { |
159 | 169 |
160 /*!!! | 170 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) { |
161 // If we're going to mmap the file, we need to ensure it's long | 171 ::perror("Seek failed"); |
162 // enough beforehand | 172 std::cerr << "ERROR: MatrixFileCache::resize(" << w << ", " |
173 << h << "): seek failed, cannot resize" << std::endl; | |
174 return; | |
175 } | |
176 | |
177 // guess this requires efficient support for sparse files | |
163 | 178 |
164 if (m_preferMmap) { | 179 float f(0); |
165 | 180 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) { |
166 if (::lseek(m_fd, off - sizeof(float), SEEK_SET) == (off_t)-1) { | 181 ::perror("WARNING: MatrixFileCache::resize: write failed"); |
167 ::perror("Seek failed"); | 182 } |
168 std::cerr << "ERROR: MatrixFileCache::resize(" << w << ", " | 183 |
169 << h << "): seek failed, cannot resize" << std::endl; | |
170 return; | |
171 } | |
172 | |
173 // guess this requires efficient support for sparse files | |
174 | |
175 float f(0); | |
176 if (::write(m_fd, &f, sizeof(float)) != sizeof(float)) { | |
177 ::perror("WARNING: MatrixFileCache::resize: write failed"); | |
178 } | |
179 } | |
180 */ | |
181 } else { | 184 } else { |
182 | 185 |
183 if (::ftruncate(m_fd, off) < 0) { | 186 if (::ftruncate(m_fd, off) < 0) { |
184 ::perror("WARNING: MatrixFileCache::resize: ftruncate failed"); | 187 ::perror("WARNING: MatrixFileCache::resize: ftruncate failed"); |
185 } | 188 } |
186 } | 189 } |
187 | 190 |
188 m_width = 0; | 191 m_width = 0; |
189 m_height = 0; | 192 m_height = 0; |
190 m_off = 0; | |
191 | 193 |
192 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) { | 194 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) { |
193 ::perror("ERROR: MatrixFileCache::resize: Seek to write header failed"); | 195 ::perror("ERROR: MatrixFileCache::resize: Seek to write header failed"); |
194 return; | 196 return; |
195 } | 197 } |
215 std::cerr << "ERROR: MatrixFileCache::reset called on read-only cache" | 217 std::cerr << "ERROR: MatrixFileCache::reset called on read-only cache" |
216 << std::endl; | 218 << std::endl; |
217 return; | 219 return; |
218 } | 220 } |
219 | 221 |
222 QMutexLocker locker(&m_fdMutex); | |
223 | |
220 float *emptyCol = new float[m_height]; | 224 float *emptyCol = new float[m_height]; |
221 for (size_t y = 0; y < m_height; ++y) emptyCol[y] = 0.f; | 225 for (size_t y = 0; y < m_height; ++y) emptyCol[y] = 0.f; |
222 | 226 |
223 seekTo(0, 0); | 227 seekTo(0, 0); |
224 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); | 228 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); |
225 | 229 |
226 delete[] emptyCol; | 230 delete[] emptyCol; |
227 } | 231 } |
228 | 232 |
229 void | |
230 MatrixFileCache::setRegionOfInterest(size_t x, size_t width) | |
231 { | |
232 setRegion(x, width, true); | |
233 } | |
234 | |
235 void | |
236 MatrixFileCache::clearRegionOfInterest() | |
237 { | |
238 m_userRegion = false; | |
239 } | |
240 | |
241 float | 233 float |
242 MatrixFileCache::getValueAt(size_t x, size_t y) const | 234 MatrixFileCache::getValueAt(size_t x, size_t y) |
243 { | 235 { |
244 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) { | 236 float value = 0.f; |
245 float *rp = getRegionPtr(x, y); | 237 if (getValuesFromCache(x, y, 1, &value)) return value; |
246 if (rp) return *rp; | 238 |
247 } else if (!m_userRegion) { | 239 ssize_t r = 0; |
248 if (autoSetRegion(x)) { | 240 |
249 float *rp = getRegionPtr(x, y); | 241 // std::cout << "MatrixFileCache::getValueAt(" << x << ", " << y << ")" |
250 if (rp) return *rp; | 242 // << ": reading the slow way" << std::endl; |
251 else return 0.f; | 243 |
252 } | 244 m_fdMutex.lock(); |
253 } | 245 |
254 | 246 if (seekTo(x, y)) { |
255 if (!seekTo(x, y)) return 0.f; | 247 r = ::read(m_fd, &value, sizeof(float)); |
256 float value; | 248 } |
257 ssize_t r = ::read(m_fd, &value, sizeof(float)); | 249 |
250 m_fdMutex.unlock(); | |
251 | |
258 if (r < 0) { | 252 if (r < 0) { |
259 ::perror("MatrixFileCache::getValueAt: Read failed"); | 253 ::perror("MatrixFileCache::getValueAt: Read failed"); |
260 } | 254 } |
261 if (r != sizeof(float)) { | 255 if (r != sizeof(float)) { |
262 value = 0.f; | 256 value = 0.f; |
263 } | 257 } |
264 if (r > 0) m_off += r; | 258 |
265 return value; | 259 return value; |
266 } | 260 } |
267 | 261 |
268 void | 262 void |
269 MatrixFileCache::getColumnAt(size_t x, float *values) const | 263 MatrixFileCache::getColumnAt(size_t x, float *values) |
270 { | 264 { |
271 if (m_rw > 0 && x >= m_rx && x < m_rx + m_rw) { | 265 if (getValuesFromCache(x, 0, m_height, values)) return; |
272 float *rp = getRegionPtr(x, 0); | 266 |
273 if (rp) { | 267 ssize_t r = 0; |
274 for (size_t y = 0; y < m_height; ++y) { | 268 |
275 values[y] = rp[y]; | 269 std::cout << "MatrixFileCache::getColumnAt(" << x << ")" |
276 } | 270 << ": reading the slow way" << std::endl; |
277 } | 271 |
278 return; | 272 m_fdMutex.lock(); |
279 } else if (!m_userRegion) { | 273 |
280 if (autoSetRegion(x)) { | 274 if (seekTo(x, 0)) { |
281 float *rp = getRegionPtr(x, 0); | 275 r = ::read(m_fd, values, m_height * sizeof(float)); |
282 if (rp) { | 276 } |
283 for (size_t y = 0; y < m_height; ++y) { | 277 |
284 values[y] = rp[y]; | 278 m_fdMutex.unlock(); |
285 } | 279 |
286 return; | |
287 } | |
288 } | |
289 } | |
290 | |
291 if (!seekTo(x, 0)) return; | |
292 ssize_t r = ::read(m_fd, values, m_height * sizeof(float)); | |
293 if (r < 0) { | 280 if (r < 0) { |
294 ::perror("MatrixFileCache::getColumnAt: read failed"); | 281 ::perror("MatrixFileCache::getColumnAt: read failed"); |
295 } | 282 } |
296 if (r > 0) m_off += r; | 283 } |
284 | |
285 bool | |
286 MatrixFileCache::getValuesFromCache(size_t x, size_t ystart, size_t ycount, | |
287 float *values) | |
288 { | |
289 m_cacheMutex.lock(); | |
290 | |
291 if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) { | |
292 bool left = (m_cache.data && x < m_cache.x); | |
293 m_cacheMutex.unlock(); | |
294 primeCache(x, left); // this doesn't take effect until a later callback | |
295 m_prevX = x; | |
296 return false; | |
297 } | |
298 | |
299 for (size_t y = ystart; y < ystart + ycount; ++y) { | |
300 values[y - ystart] = m_cache.data[(x - m_cache.x) * m_height + y]; | |
301 } | |
302 m_cacheMutex.unlock(); | |
303 | |
304 if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) { | |
305 primeCache(x, true); | |
306 } | |
307 | |
308 if (m_cache.x + m_cache.width < m_width && | |
309 x > m_prevX && | |
310 x > m_cache.x + (m_cache.width * 3) / 4) { | |
311 primeCache(x, false); | |
312 } | |
313 | |
314 m_prevX = x; | |
315 return true; | |
297 } | 316 } |
298 | 317 |
299 void | 318 void |
300 MatrixFileCache::setValueAt(size_t x, size_t y, float value) | 319 MatrixFileCache::setValueAt(size_t x, size_t y, float value) |
301 { | 320 { |
303 std::cerr << "ERROR: MatrixFileCache::setValueAt called on read-only cache" | 322 std::cerr << "ERROR: MatrixFileCache::setValueAt called on read-only cache" |
304 << std::endl; | 323 << std::endl; |
305 return; | 324 return; |
306 } | 325 } |
307 | 326 |
308 if (!seekTo(x, y)) return; | 327 ssize_t w = 0; |
309 ssize_t w = ::write(m_fd, &value, sizeof(float)); | 328 bool seekFailed = false; |
310 if (w != sizeof(float)) { | 329 |
330 m_fdMutex.lock(); | |
331 | |
332 if (seekTo(x, y)) { | |
333 w = ::write(m_fd, &value, sizeof(float)); | |
334 } else { | |
335 seekFailed = true; | |
336 } | |
337 | |
338 m_fdMutex.unlock(); | |
339 | |
340 if (!seekFailed && w != sizeof(float)) { | |
311 ::perror("WARNING: MatrixFileCache::setValueAt: write failed"); | 341 ::perror("WARNING: MatrixFileCache::setValueAt: write failed"); |
312 } | 342 } |
313 if (w > 0) m_off += w; | 343 |
314 | 344 //... update cache as appropriate |
315 //... update region as appropriate | |
316 } | 345 } |
317 | 346 |
318 void | 347 void |
319 MatrixFileCache::setColumnAt(size_t x, float *values) | 348 MatrixFileCache::setColumnAt(size_t x, float *values) |
320 { | 349 { |
322 std::cerr << "ERROR: MatrixFileCache::setColumnAt called on read-only cache" | 351 std::cerr << "ERROR: MatrixFileCache::setColumnAt called on read-only cache" |
323 << std::endl; | 352 << std::endl; |
324 return; | 353 return; |
325 } | 354 } |
326 | 355 |
327 if (!seekTo(x, 0)) return; | 356 ssize_t w = 0; |
328 ssize_t w = ::write(m_fd, values, m_height * sizeof(float)); | 357 bool seekFailed = false; |
329 if (w != ssize_t(m_height * sizeof(float))) { | 358 |
359 m_fdMutex.lock(); | |
360 | |
361 if (seekTo(x, 0)) { | |
362 w = ::write(m_fd, values, m_height * sizeof(float)); | |
363 } else { | |
364 seekFailed = true; | |
365 } | |
366 | |
367 m_fdMutex.unlock(); | |
368 | |
369 if (!seekFailed && w != ssize_t(m_height * sizeof(float))) { | |
330 ::perror("WARNING: MatrixFileCache::setColumnAt: write failed"); | 370 ::perror("WARNING: MatrixFileCache::setColumnAt: write failed"); |
331 } | 371 } |
332 if (w > 0) m_off += w; | 372 |
333 | 373 //... update cache as appropriate |
334 //... update region as appropriate | 374 } |
335 } | 375 |
336 | 376 void |
337 float * | 377 MatrixFileCache::primeCache(size_t x, bool goingLeft) |
338 MatrixFileCache::getRegionPtr(size_t x, size_t y) const | 378 { |
339 { | 379 // std::cerr << "MatrixFileCache::primeCache(" << x << ", " << goingLeft << ")" << std::endl; |
340 if (m_rw == 0) return 0; | 380 |
341 | |
342 float *region = m_region; | |
343 | |
344 float *ptr = &(region[(x - m_rx) * m_height + y]); | |
345 | |
346 // std::cerr << "getRegionPtr(" << x << "," << y << "): region is " << m_region << ", returning " << ptr << std::endl; | |
347 return ptr; | |
348 } | |
349 | |
350 bool | |
351 MatrixFileCache::autoSetRegion(size_t x) const | |
352 { | |
353 size_t rx = x; | 381 size_t rx = x; |
354 size_t rw = m_autoRegionWidth; | 382 size_t rw = m_defaultCacheWidth; |
355 size_t left = rw / 4; | 383 |
356 if (x < m_rx) left = (rw * 3) / 4; | 384 size_t left = rw / 3; |
385 if (goingLeft) left = (rw * 2) / 3; | |
386 | |
357 if (rx > left) rx -= left; | 387 if (rx > left) rx -= left; |
358 else rx = 0; | 388 else rx = 0; |
389 | |
359 if (rx + rw > m_width) rw = m_width - rx; | 390 if (rx + rw > m_width) rw = m_width - rx; |
360 return setRegion(rx, rw, false); | 391 |
392 QMutexLocker locker(&m_cacheMutex); | |
393 | |
394 if (m_requestToken >= 0) { | |
395 | |
396 if (x >= m_requestingX && | |
397 x < m_requestingX + m_requestingWidth) { | |
398 | |
399 if (m_readThread.isReady(m_requestToken)) { | |
400 | |
401 std::cerr << "last request is ready! (" << m_requestingX << ", "<< m_requestingWidth << ")" << std::endl; | |
402 | |
403 FileReadThread::Request request; | |
404 if (m_readThread.getRequest(m_requestToken, request)) { | |
405 | |
406 m_cache.x = (request.start - m_headerSize) / (m_height * sizeof(float)); | |
407 m_cache.width = request.size / (m_height * sizeof(float)); | |
408 | |
409 std::cerr << "actual: " << m_cache.x << ", " << m_cache.width << std::endl; | |
410 | |
411 if (m_cache.data) delete[] m_cache.data; | |
412 m_cache.data = (float *)request.data; | |
413 } | |
414 | |
415 m_readThread.done(m_requestToken); | |
416 m_requestToken = -1; | |
417 } | |
418 | |
419 return; | |
420 } | |
421 | |
422 std::cerr << "cancelling last request" << std::endl; | |
423 m_readThread.cancel(m_requestToken); | |
424 //!!! | |
425 m_requestToken = -1; | |
426 } | |
427 | |
428 FileReadThread::Request request; | |
429 request.fd = m_fd; | |
430 request.mutex = &m_fdMutex; | |
431 request.start = m_headerSize + rx * m_height * sizeof(float); | |
432 request.size = rw * m_height * sizeof(float); | |
433 request.data = (char *)(new float[rw * m_height]); | |
434 | |
435 m_requestingX = rx; | |
436 m_requestingWidth = rw; | |
437 | |
438 int token = m_readThread.request(request); | |
439 std::cerr << "MatrixFileCache::primeCache: request token is " | |
440 << token << std::endl; | |
441 | |
442 m_requestToken = token; | |
443 } | |
444 | |
445 void | |
446 MatrixFileCache::requestCancelled(int token) | |
447 { | |
448 std::cerr << "MatrixFileCache::requestCancelled(" << token << ")" << std::endl; | |
449 | |
450 FileReadThread::Request request; | |
451 if (m_readThread.getRequest(token, request)) { | |
452 delete[] ((float *)request.data); | |
453 m_readThread.done(token); | |
454 } | |
361 } | 455 } |
362 | 456 |
363 bool | 457 bool |
364 MatrixFileCache::setRegion(size_t x, size_t width, bool user) const | 458 MatrixFileCache::seekTo(size_t x, size_t y) |
365 { | |
366 if (!user && m_userRegion) return false; | |
367 if (m_rw > 0 && x >= m_rx && x + width <= m_rx + m_rw) return true; | |
368 | |
369 if (m_rw > 0) { | |
370 delete[] m_region; | |
371 m_region = 0; | |
372 m_rw = 0; | |
373 } | |
374 | |
375 if (width == 0) { | |
376 return true; | |
377 } | |
378 | |
379 if (!seekTo(x, 0)) return false; | |
380 | |
381 m_region = new float[width * m_height]; | |
382 MUNLOCK(m_region, width * m_height * sizeof(float)); | |
383 | |
384 ssize_t r = ::read(m_fd, m_region, width * m_height * sizeof(float)); | |
385 if (r < 0) { | |
386 ::perror("Read failed"); | |
387 std::cerr << "ERROR: MatrixFileCache::setRegion(" << x << ", " << width | |
388 << ") failed" << std::endl; | |
389 delete[] m_region; | |
390 m_region = 0; | |
391 return false; | |
392 } | |
393 | |
394 m_off += r; | |
395 | |
396 if (r < ssize_t(width * m_height * sizeof(float))) { | |
397 // didn't manage to read the whole thing, but did get something | |
398 std::cerr << "WARNING: MatrixFileCache::setRegion(" << x << ", " << width | |
399 << "): "; | |
400 width = r / (m_height * sizeof(float)); | |
401 std::cerr << "Only got " << width << " columns" << std::endl; | |
402 } | |
403 | |
404 m_rx = x; | |
405 m_rw = width; | |
406 if (m_rw == 0) { | |
407 delete[] m_region; | |
408 m_region = 0; | |
409 } | |
410 | |
411 std::cerr << "MatrixFileCache::setRegion: set region to " << x << ", " << width << std::endl; | |
412 | |
413 if (user) m_userRegion = true; | |
414 return true; | |
415 } | |
416 | |
417 bool | |
418 MatrixFileCache::seekTo(size_t x, size_t y) const | |
419 { | 459 { |
420 off_t off = m_headerSize + (x * m_height + y) * sizeof(float); | 460 off_t off = m_headerSize + (x * m_height + y) * sizeof(float); |
421 if (off == m_off) return true; | |
422 | |
423 if (m_mode == ReadWrite) { | |
424 std::cerr << "writer: "; | |
425 std::cerr << "seek required (from " << m_off << " to " << off << ")" << std::endl; | |
426 } | |
427 | 461 |
428 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) { | 462 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) { |
429 ::perror("Seek failed"); | 463 ::perror("Seek failed"); |
430 std::cerr << "ERROR: MatrixFileCache::seekTo(" << x << ", " << y | 464 std::cerr << "ERROR: MatrixFileCache::seekTo(" << x << ", " << y |
431 << ") failed" << std::endl; | 465 << ") failed" << std::endl; |
432 return false; | 466 return false; |
433 } | 467 } |
434 | 468 |
435 m_off = off; | |
436 return true; | 469 return true; |
437 } | 470 } |
438 | 471 |