Mercurial > hg > easaier-soundaccess
comparison data/fileio/MatrixFile.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children | 61681a2bc1e6 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006 Chris Cannam. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "MatrixFile.h" | |
17 #include "base/TempDirectory.h" | |
18 #include "system/System.h" | |
19 #include "base/Profiler.h" | |
20 #include "base/Exceptions.h" | |
21 | |
22 #include <sys/types.h> | |
23 #include <sys/stat.h> | |
24 #include <fcntl.h> | |
25 //#include <unistd.h> | |
26 | |
27 #include <iostream> | |
28 | |
29 #include <cstdio> | |
30 #include <cassert> | |
31 | |
32 #include <QFileInfo> | |
33 #include <QDir> | |
34 | |
35 //#define DEBUG_MATRIX_FILE 1 | |
36 //#define DEBUG_MATRIX_FILE_READ_SET 1 | |
37 | |
38 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
39 #ifndef DEBUG_MATRIX_FILE | |
40 #define DEBUG_MATRIX_FILE 1 | |
41 #endif | |
42 #endif | |
43 | |
44 std::map<QString, int> MatrixFile::m_refcount; | |
45 QMutex MatrixFile::m_refcountMutex; | |
46 | |
47 MatrixFile::ResizeableBitsetMap MatrixFile::m_columnBitsets; | |
48 QMutex MatrixFile::m_columnBitsetWriteMutex; | |
49 | |
50 FileReadThread *MatrixFile::m_readThread = 0; | |
51 | |
52 static size_t totalStorage = 0; | |
53 static size_t totalMemory = 0; | |
54 static size_t totalCount = 0; | |
55 | |
56 MatrixFile::MatrixFile(QString fileBase, Mode mode, | |
57 size_t cellSize, bool eagerCache) : | |
58 m_fd(-1), | |
59 m_mode(mode), | |
60 m_flags(0), | |
61 m_fmode(0), | |
62 m_cellSize(cellSize), | |
63 m_width(0), | |
64 m_height(0), | |
65 m_headerSize(2 * sizeof(size_t)), | |
66 m_defaultCacheWidth(1024), | |
67 m_prevX(0), | |
68 m_eagerCache(eagerCache), | |
69 m_requestToken(-1), | |
70 m_spareData(0), | |
71 m_columnBitset(0) | |
72 { | |
73 Profiler profiler("MatrixFile::MatrixFile", true); | |
74 | |
75 if (!m_readThread) { | |
76 m_readThread = new FileReadThread; | |
77 m_readThread->start(); | |
78 } | |
79 | |
80 m_cache.data = 0; | |
81 | |
82 QDir tempDir(TempDirectory::getInstance()->getPath()); | |
83 QString fileName(tempDir.filePath(QString("%1.mfc").arg(fileBase))); | |
84 bool newFile = !QFileInfo(fileName).exists(); | |
85 | |
86 if (newFile && m_mode == ReadOnly) { | |
87 std::cerr << "ERROR: MatrixFile::MatrixFile: Read-only mode " | |
88 << "specified, but cache file does not exist" << std::endl; | |
89 throw FileNotFound(fileName); | |
90 } | |
91 | |
92 if (!newFile && m_mode == ReadWrite) { | |
93 std::cerr << "Note: MatrixFile::MatrixFile: Read/write mode " | |
94 << "specified, but file already exists; falling back to " | |
95 << "read-only mode" << std::endl; | |
96 m_mode = ReadOnly; | |
97 } | |
98 | |
99 if (!eagerCache && m_mode == ReadOnly) { | |
100 std::cerr << "WARNING: MatrixFile::MatrixFile: Eager cacheing not " | |
101 << "specified, but file is open in read-only mode -- cache " | |
102 << "will not be used" << std::endl; | |
103 } | |
104 | |
105 m_flags = 0; | |
106 m_fmode = S_IRUSR | S_IWUSR; | |
107 | |
108 if (m_mode == ReadWrite) { | |
109 m_flags = O_RDWR | O_CREAT; | |
110 } else { | |
111 m_flags = O_RDONLY; | |
112 } | |
113 | |
114 #ifdef _WIN32 | |
115 m_flags |= O_BINARY; | |
116 #endif | |
117 | |
118 #ifdef DEBUG_MATRIX_FILE | |
119 std::cerr << "MatrixFile::MatrixFile: opening " << fileName.toStdString() << "..." << std::endl; | |
120 #endif | |
121 | |
122 if ((m_fd = ::open(fileName.toLocal8Bit(), m_flags, m_fmode)) < 0) { | |
123 ::perror("Open failed"); | |
124 std::cerr << "ERROR: MatrixFile::MatrixFile: " | |
125 << "Failed to open cache file \"" | |
126 << fileName.toStdString() << "\""; | |
127 if (m_mode == ReadWrite) std::cerr << " for writing"; | |
128 std::cerr << std::endl; | |
129 throw FailedToOpenFile(fileName); | |
130 } | |
131 | |
132 if (newFile) { | |
133 resize(0, 0); // write header | |
134 } else { | |
135 size_t header[2]; | |
136 if (::read(m_fd, header, 2 * sizeof(size_t)) < 0) { | |
137 ::perror("MatrixFile::MatrixFile: read failed"); | |
138 std::cerr << "ERROR: MatrixFile::MatrixFile: " | |
139 << "Failed to read header (fd " << m_fd << ", file \"" | |
140 << fileName.toStdString() << "\")" << std::endl; | |
141 throw FileReadFailed(fileName); | |
142 } | |
143 m_width = header[0]; | |
144 m_height = header[1]; | |
145 seekTo(0, 0); | |
146 } | |
147 | |
148 m_fileName = fileName; | |
149 | |
150 m_columnBitsetWriteMutex.lock(); | |
151 | |
152 if (m_columnBitsets.find(m_fileName) == m_columnBitsets.end()) { | |
153 m_columnBitsets[m_fileName] = new ResizeableBitset; | |
154 } | |
155 m_columnBitset = m_columnBitsets[m_fileName]; | |
156 | |
157 m_columnBitsetWriteMutex.unlock(); | |
158 | |
159 QMutexLocker locker(&m_refcountMutex); | |
160 ++m_refcount[fileName]; | |
161 | |
162 // std::cerr << "MatrixFile(" << this << "): fd " << m_fd << ", file " << fileName.toStdString() << ", ref " << m_refcount[fileName] << std::endl; | |
163 | |
164 // std::cerr << "MatrixFile::MatrixFile: Done, size is " << "(" << m_width << ", " << m_height << ")" << std::endl; | |
165 | |
166 ++totalCount; | |
167 | |
168 } | |
169 | |
170 MatrixFile::~MatrixFile() | |
171 { | |
172 char *requestData = 0; | |
173 | |
174 if (m_requestToken >= 0) { | |
175 FileReadThread::Request request; | |
176 if (m_readThread->getRequest(m_requestToken, request)) { | |
177 requestData = request.data; | |
178 } | |
179 m_readThread->cancel(m_requestToken); | |
180 } | |
181 | |
182 if (requestData) free(requestData); | |
183 if (m_cache.data) free(m_cache.data); | |
184 if (m_spareData) free(m_spareData); | |
185 | |
186 if (m_fd >= 0) { | |
187 if (::close(m_fd) < 0) { | |
188 ::perror("MatrixFile::~MatrixFile: close failed"); | |
189 } | |
190 } | |
191 | |
192 if (m_fileName != "") { | |
193 | |
194 QMutexLocker locker(&m_refcountMutex); | |
195 | |
196 if (--m_refcount[m_fileName] == 0) { | |
197 | |
198 if (::unlink(m_fileName.toLocal8Bit())) { | |
199 // ::perror("Unlink failed"); | |
200 // std::cerr << "WARNING: MatrixFile::~MatrixFile: reference count reached 0, but failed to unlink file \"" << m_fileName.toStdString() << "\"" << std::endl; | |
201 } else { | |
202 // std::cerr << "deleted " << m_fileName.toStdString() << std::endl; | |
203 } | |
204 | |
205 QMutexLocker locker2(&m_columnBitsetWriteMutex); | |
206 m_columnBitsets.erase(m_fileName); | |
207 delete m_columnBitset; | |
208 } | |
209 } | |
210 | |
211 totalStorage -= (m_headerSize + (m_width * m_height * m_cellSize)); | |
212 totalMemory -= (2 * m_defaultCacheWidth * m_height * m_cellSize); | |
213 totalCount --; | |
214 | |
215 // std::cerr << "MatrixFile::~MatrixFile: " << std::endl; | |
216 // std::cerr << "Total storage now " << totalStorage/1024 << "K, theoretical max memory " | |
217 // << totalMemory/1024 << "K in " << totalCount << " instances" << std::endl; | |
218 | |
219 } | |
220 | |
221 void | |
222 MatrixFile::resize(size_t w, size_t h) | |
223 { | |
224 Profiler profiler("MatrixFile::resize", true); | |
225 | |
226 assert(m_mode == ReadWrite); | |
227 | |
228 QMutexLocker locker(&m_fdMutex); | |
229 | |
230 totalStorage -= (m_headerSize + (m_width * m_height * m_cellSize)); | |
231 totalMemory -= (2 * m_defaultCacheWidth * m_height * m_cellSize); | |
232 | |
233 off_t off = m_headerSize + (w * h * m_cellSize); | |
234 | |
235 #ifdef DEBUG_MATRIX_FILE | |
236 std::cerr << "MatrixFile::resize(" << w << ", " << h << "): resizing file" << std::endl; | |
237 #endif | |
238 | |
239 if (w * h < m_width * m_height) { | |
240 if (::ftruncate(m_fd, off) < 0) { | |
241 ::perror("WARNING: MatrixFile::resize: ftruncate failed"); | |
242 throw FileOperationFailed(m_fileName, "ftruncate"); | |
243 } | |
244 } | |
245 | |
246 m_width = 0; | |
247 m_height = 0; | |
248 | |
249 if (::lseek(m_fd, 0, SEEK_SET) == (off_t)-1) { | |
250 ::perror("ERROR: MatrixFile::resize: Seek to write header failed"); | |
251 throw FileOperationFailed(m_fileName, "lseek"); | |
252 } | |
253 | |
254 size_t header[2]; | |
255 header[0] = w; | |
256 header[1] = h; | |
257 if (::write(m_fd, header, 2 * sizeof(size_t)) != 2 * sizeof(size_t)) { | |
258 ::perror("ERROR: MatrixFile::resize: Failed to write header"); | |
259 throw FileOperationFailed(m_fileName, "write"); | |
260 } | |
261 | |
262 if (w > 0 && m_defaultCacheWidth > w) { | |
263 m_defaultCacheWidth = w; | |
264 } | |
265 | |
266 static size_t maxCacheMB = 16; | |
267 if (2 * m_defaultCacheWidth * h * m_cellSize > maxCacheMB * 1024 * 1024) { //!!! | |
268 m_defaultCacheWidth = (maxCacheMB * 1024 * 1024) / (2 * h * m_cellSize); | |
269 if (m_defaultCacheWidth < 16) m_defaultCacheWidth = 16; | |
270 } | |
271 | |
272 if (m_columnBitset) { | |
273 QMutexLocker locker(&m_columnBitsetWriteMutex); | |
274 m_columnBitset->resize(w); | |
275 } | |
276 | |
277 if (m_cache.data) { | |
278 free(m_cache.data); | |
279 m_cache.data = 0; | |
280 } | |
281 | |
282 if (m_spareData) { | |
283 free(m_spareData); | |
284 m_spareData = 0; | |
285 } | |
286 | |
287 m_width = w; | |
288 m_height = h; | |
289 | |
290 totalStorage += (m_headerSize + (m_width * m_height * m_cellSize)); | |
291 totalMemory += (2 * m_defaultCacheWidth * m_height * m_cellSize); | |
292 | |
293 #ifdef DEBUG_MATRIX_FILE | |
294 std::cerr << "MatrixFile::resize(" << w << ", " << h << "): cache width " | |
295 << m_defaultCacheWidth << ", storage " | |
296 << (m_headerSize + w * h * m_cellSize) << ", mem " | |
297 << (2 * h * m_defaultCacheWidth * m_cellSize) << std::endl; | |
298 | |
299 std::cerr << "Total storage " << totalStorage/1024 << "K, theoretical max memory " | |
300 << totalMemory/1024 << "K in " << totalCount << " instances" << std::endl; | |
301 #endif | |
302 | |
303 seekTo(0, 0); | |
304 } | |
305 | |
306 void | |
307 MatrixFile::reset() | |
308 { | |
309 Profiler profiler("MatrixFile::reset", true); | |
310 | |
311 assert (m_mode == ReadWrite); | |
312 | |
313 if (m_eagerCache) { | |
314 void *emptyCol = calloc(m_height, m_cellSize); | |
315 for (size_t x = 0; x < m_width; ++x) setColumnAt(x, emptyCol); | |
316 free(emptyCol); | |
317 } | |
318 | |
319 if (m_columnBitset) { | |
320 QMutexLocker locker(&m_columnBitsetWriteMutex); | |
321 m_columnBitset->resize(m_width); | |
322 } | |
323 } | |
324 | |
325 void | |
326 MatrixFile::getColumnAt(size_t x, void *data) | |
327 { | |
328 // Profiler profiler("MatrixFile::getColumnAt"); | |
329 | |
330 // assert(haveSetColumnAt(x)); | |
331 | |
332 if (getFromCache(x, 0, m_height, data)) return; | |
333 | |
334 // Profiler profiler2("MatrixFile::getColumnAt (uncached)"); | |
335 | |
336 ssize_t r = 0; | |
337 | |
338 #ifdef DEBUG_MATRIX_FILE | |
339 std::cerr << "MatrixFile::getColumnAt(" << x << ")" | |
340 << ": reading the slow way"; | |
341 | |
342 if (m_requestToken >= 0 && | |
343 x >= m_requestingX && | |
344 x < m_requestingX + m_requestingWidth) { | |
345 | |
346 std::cerr << " (awaiting " << m_requestingX << ", " << m_requestingWidth << " from disk)"; | |
347 } | |
348 | |
349 std::cerr << std::endl; | |
350 #endif | |
351 | |
352 m_fdMutex.lock(); | |
353 | |
354 if (seekTo(x, 0)) { | |
355 r = ::read(m_fd, data, m_height * m_cellSize); | |
356 } | |
357 | |
358 m_fdMutex.unlock(); | |
359 | |
360 if (r < 0) { | |
361 ::perror("MatrixFile::getColumnAt: read failed"); | |
362 std::cerr << "ERROR: MatrixFile::getColumnAt: " | |
363 << "Failed to read column " << x << " (height " << m_height << ", cell size " << m_cellSize << ", fd " << m_fd << ", file \"" | |
364 << m_fileName.toStdString() << "\")" << std::endl; | |
365 throw FileReadFailed(m_fileName); | |
366 } | |
367 | |
368 return; | |
369 } | |
370 | |
371 bool | |
372 MatrixFile::getFromCache(size_t x, size_t ystart, size_t ycount, void *data) | |
373 { | |
374 m_cacheMutex.lock(); | |
375 | |
376 if (!m_cache.data || x < m_cache.x || x >= m_cache.x + m_cache.width) { | |
377 bool left = (m_cache.data && x < m_cache.x); | |
378 m_cacheMutex.unlock(); | |
379 primeCache(x, left); // this doesn't take effect until a later callback | |
380 m_prevX = x; | |
381 return false; | |
382 } | |
383 | |
384 memcpy(data, | |
385 m_cache.data + m_cellSize * ((x - m_cache.x) * m_height + ystart), | |
386 ycount * m_cellSize); | |
387 | |
388 m_cacheMutex.unlock(); | |
389 | |
390 if (m_cache.x > 0 && x < m_prevX && x < m_cache.x + m_cache.width/4) { | |
391 primeCache(x, true); | |
392 } | |
393 | |
394 if (m_cache.x + m_cache.width < m_width && | |
395 x > m_prevX && | |
396 x > m_cache.x + (m_cache.width * 3) / 4) { | |
397 primeCache(x, false); | |
398 } | |
399 | |
400 m_prevX = x; | |
401 return true; | |
402 } | |
403 | |
404 void | |
405 MatrixFile::setColumnAt(size_t x, const void *data) | |
406 { | |
407 assert(m_mode == ReadWrite); | |
408 | |
409 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
410 std::cerr << "MatrixFile::setColumnAt(" << x << ")" << std::endl; | |
411 #endif | |
412 | |
413 ssize_t w = 0; | |
414 bool seekFailed = false; | |
415 | |
416 m_fdMutex.lock(); | |
417 | |
418 if (seekTo(x, 0)) { | |
419 w = ::write(m_fd, data, m_height * m_cellSize); | |
420 } else { | |
421 seekFailed = true; | |
422 } | |
423 | |
424 m_fdMutex.unlock(); | |
425 | |
426 if (!seekFailed && w != ssize_t(m_height * m_cellSize)) { | |
427 ::perror("WARNING: MatrixFile::setColumnAt: write failed"); | |
428 throw FileOperationFailed(m_fileName, "write"); | |
429 } else if (seekFailed) { | |
430 throw FileOperationFailed(m_fileName, "seek"); | |
431 } else { | |
432 QMutexLocker locker(&m_columnBitsetWriteMutex); | |
433 m_columnBitset->set(x); | |
434 } | |
435 } | |
436 | |
437 void | |
438 MatrixFile::suspend() | |
439 { | |
440 QMutexLocker locker(&m_fdMutex); | |
441 QMutexLocker locker2(&m_cacheMutex); | |
442 | |
443 if (m_fd < 0) return; // already suspended | |
444 | |
445 #ifdef DEBUG_MATRIX_FILE | |
446 std::cerr << "MatrixFile(" << this << ":" << m_fileName.toStdString() << ")::suspend(): fd was " << m_fd << std::endl; | |
447 #endif | |
448 | |
449 if (m_requestToken >= 0) { | |
450 void *data = 0; | |
451 FileReadThread::Request request; | |
452 if (m_readThread->getRequest(m_requestToken, request)) { | |
453 data = request.data; | |
454 } | |
455 m_readThread->cancel(m_requestToken); | |
456 if (data) free(data); | |
457 m_requestToken = -1; | |
458 } | |
459 | |
460 if (m_cache.data) { | |
461 free(m_cache.data); | |
462 m_cache.data = 0; | |
463 } | |
464 | |
465 if (m_spareData) { | |
466 free(m_spareData); | |
467 m_spareData = 0; | |
468 } | |
469 | |
470 if (::close(m_fd) < 0) { | |
471 ::perror("WARNING: MatrixFile::suspend: close failed"); | |
472 throw FileOperationFailed(m_fileName, "close"); | |
473 } | |
474 | |
475 m_fd = -1; | |
476 } | |
477 | |
478 void | |
479 MatrixFile::resume() | |
480 { | |
481 if (m_fd >= 0) return; | |
482 | |
483 #ifdef DEBUG_MATRIX_FILE | |
484 std::cerr << "MatrixFile(" << this << ")::resume()" << std::endl; | |
485 #endif | |
486 | |
487 if ((m_fd = ::open(m_fileName.toLocal8Bit(), m_flags, m_fmode)) < 0) { | |
488 ::perror("Open failed"); | |
489 std::cerr << "ERROR: MatrixFile::resume: " | |
490 << "Failed to open cache file \"" | |
491 << m_fileName.toStdString() << "\""; | |
492 if (m_mode == ReadWrite) std::cerr << " for writing"; | |
493 std::cerr << std::endl; | |
494 throw FailedToOpenFile(m_fileName); | |
495 } | |
496 | |
497 std::cerr << "MatrixFile(" << this << ":" << m_fileName.toStdString() << ")::resume(): fd is " << m_fd << std::endl; | |
498 } | |
499 | |
500 void | |
501 MatrixFile::primeCache(size_t x, bool goingLeft) | |
502 { | |
503 // Profiler profiler("MatrixFile::primeCache"); | |
504 | |
505 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
506 std::cerr << "MatrixFile::primeCache(" << x << ", " << goingLeft << ")" << std::endl; | |
507 #endif | |
508 | |
509 size_t rx = x; | |
510 size_t rw = m_defaultCacheWidth; | |
511 | |
512 size_t left = rw / 3; | |
513 if (goingLeft) left = (rw * 2) / 3; | |
514 | |
515 if (rx > left) rx -= left; | |
516 else rx = 0; | |
517 | |
518 if (rx + rw > m_width) rw = m_width - rx; | |
519 | |
520 if (!m_eagerCache) { | |
521 | |
522 size_t ti = 0; | |
523 | |
524 for (ti = 0; ti < rw; ++ti) { | |
525 if (!m_columnBitset->get(rx + ti)) break; | |
526 } | |
527 | |
528 #ifdef DEBUG_MATRIX_FILE | |
529 if (ti < rw) { | |
530 std::cerr << "eagerCache is false and there's a hole at " | |
531 << rx + ti << ", reducing rw from " << rw << " to " | |
532 << ti << std::endl; | |
533 } | |
534 #endif | |
535 | |
536 rw = min(rw, ti); | |
537 if (rw < 10 || rx + rw <= x) return; | |
538 } | |
539 | |
540 QMutexLocker locker(&m_cacheMutex); | |
541 | |
542 FileReadThread::Request request; | |
543 | |
544 if (m_requestToken >= 0 && | |
545 m_readThread->getRequest(m_requestToken, request)) { | |
546 | |
547 if (x >= m_requestingX && | |
548 x < m_requestingX + m_requestingWidth) { | |
549 | |
550 if (m_readThread->isReady(m_requestToken)) { | |
551 | |
552 if (!request.successful) { | |
553 std::cerr << "ERROR: MatrixFile::primeCache: Last request was unsuccessful" << std::endl; | |
554 throw FileReadFailed(m_fileName); | |
555 } | |
556 | |
557 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
558 std::cerr << "last request is ready! (" << m_requestingX << ", "<< m_requestingWidth << ")" << std::endl; | |
559 #endif | |
560 | |
561 m_cache.x = (request.start - m_headerSize) / (m_height * m_cellSize); | |
562 m_cache.width = request.size / (m_height * m_cellSize); | |
563 | |
564 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
565 std::cerr << "received last request: actual size is: " << m_cache.x << ", " << m_cache.width << std::endl; | |
566 #endif | |
567 | |
568 if (m_cache.data) { | |
569 if (m_spareData) free(m_spareData); | |
570 m_spareData = m_cache.data; | |
571 } | |
572 m_cache.data = request.data; | |
573 | |
574 m_readThread->done(m_requestToken); | |
575 m_requestToken = -1; | |
576 } | |
577 | |
578 // already requested something covering this area; wait for it | |
579 return; | |
580 } | |
581 | |
582 // the current request is no longer of any use | |
583 m_readThread->cancel(m_requestToken); | |
584 | |
585 // crude way to avoid leaking the data | |
586 while (!m_readThread->isCancelled(m_requestToken)) { | |
587 usleep(10000); | |
588 } | |
589 | |
590 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
591 std::cerr << "cancelled " << m_requestToken << std::endl; | |
592 #endif | |
593 | |
594 if (m_spareData) free(m_spareData); | |
595 m_spareData = request.data; | |
596 m_readThread->done(m_requestToken); | |
597 | |
598 m_requestToken = -1; | |
599 } | |
600 | |
601 if (m_fd < 0) { | |
602 m_fdMutex.lock(); | |
603 if (m_fd < 0) resume(); | |
604 m_fdMutex.unlock(); | |
605 } | |
606 | |
607 request.fd = m_fd; | |
608 request.mutex = &m_fdMutex; | |
609 request.start = m_headerSize + rx * m_height * m_cellSize; | |
610 request.size = rw * m_height * m_cellSize; | |
611 request.data = (char *)realloc(m_spareData, rw * m_height * m_cellSize); | |
612 MUNLOCK(request.data, rw * m_height * m_cellSize); | |
613 m_spareData = 0; | |
614 | |
615 m_requestingX = rx; | |
616 m_requestingWidth = rw; | |
617 | |
618 int token = m_readThread->request(request); | |
619 #ifdef DEBUG_MATRIX_FILE_READ_SET | |
620 std::cerr << "MatrixFile::primeCache: request token is " | |
621 << token << " (x = [" << rx << "], w = [" << rw << "], left = [" << goingLeft << "])" << std::endl; | |
622 #endif | |
623 m_requestToken = token; | |
624 } | |
625 | |
626 bool | |
627 MatrixFile::seekTo(size_t x, size_t y) | |
628 { | |
629 if (m_fd < 0) resume(); | |
630 | |
631 off_t off = m_headerSize + (x * m_height + y) * m_cellSize; | |
632 | |
633 if (::lseek(m_fd, off, SEEK_SET) == (off_t)-1) { | |
634 ::perror("Seek failed"); | |
635 std::cerr << "ERROR: MatrixFile::seekTo(" << x << ", " << y | |
636 << ") failed" << std::endl; | |
637 return false; | |
638 } | |
639 | |
640 return true; | |
641 } | |
642 |