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