GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
BlockArray.cpp
Go to the documentation of this file.
1 /*
2  This file is part of Konsole, an X terminal.
3  Copyright (C) 2000, 2013 by Stephan Kulow <coolo@kde.org>
4 
5  Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  02110-1301 USA.
21 
22 */
23 
24 // Own
25 #include "unix/BlockArray.h"
26 
27 #include <QtCore>
28 
29 // System
30 #include <assert.h>
31 #include <sys/mman.h>
32 #include <sys/param.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 
36 
37 static int blocksize = 0;
38 
40  : size(0),
41  current(size_t(-1)),
42  index(size_t(-1)),
43  lastmap(0),
44  lastmap_index(size_t(-1)),
45  lastblock(0), ion(-1),
46  length(0)
47 {
48  // lastmap_index = index = current = size_t(-1);
49  if (blocksize == 0)
50  blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize();
51 
52 }
53 
55 {
56  setHistorySize(0);
57  assert(!lastblock);
58 }
59 
60 size_t BlockArray::append(Block *block)
61 {
62  if (!size)
63  return size_t(-1);
64 
65  ++current;
66  if (current >= size) current = 0;
67 
68  int rc;
69  rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); }
70  rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); }
71 
72  length++;
73  if (length > size) length = size;
74 
75  ++index;
76 
77  delete block;
78  return current;
79 }
80 
82 {
83  if (!size)
84  return size_t(-1);
86 
87  lastblock = new Block();
88  return index + 1;
89 }
90 
92 {
93  return lastblock;
94 }
95 
96 bool BlockArray::has(size_t i) const
97 {
98  if (i == index + 1)
99  return true;
100 
101  if (i > index)
102  return false;
103  if (index - i >= length)
104  return false;
105  return true;
106 }
107 
108 const Block* BlockArray::at(size_t i)
109 {
110  if (i == index + 1)
111  return lastblock;
112 
113  if (i == lastmap_index)
114  return lastmap;
115 
116  if (i > index) {
117  qDebug() << "BlockArray::at() i > index\n";
118  return 0;
119  }
120 
121 // if (index - i >= length) {
122 // kDebug(1211) << "BlockArray::at() index - i >= length\n";
123 // return 0;
124 // }
125 
126  size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ;
127 
128  assert(j < size);
129  unmap();
130 
131  Block *block = (Block*)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
132 
133  if (block == (Block*)-1) { perror("mmap"); return 0; }
134 
135  lastmap = block;
136  lastmap_index = i;
137 
138  return block;
139 }
140 
142 {
143  if (lastmap) {
144  int res = munmap((char*)lastmap, blocksize);
145  if (res < 0) perror("munmap");
146  }
147  lastmap = 0;
148  lastmap_index = size_t(-1);
149 }
150 
151 bool BlockArray::setSize(size_t newsize)
152 {
153  return setHistorySize(newsize * 1024 / blocksize);
154 }
155 
156 bool BlockArray::setHistorySize(size_t newsize)
157 {
158 // kDebug(1211) << "setHistorySize " << size << " " << newsize;
159 
160  if (size == newsize)
161  return false;
162 
163  unmap();
164 
165  if (!newsize) {
166  delete lastblock;
167  lastblock = 0;
168  if (ion >= 0) close(ion);
169  ion = -1;
170  current = size_t(-1);
171  return true;
172  }
173 
174  if (!size) {
175  FILE* tmp = tmpfile();
176  if (!tmp) {
177  perror("konsole: cannot open temp file.\n");
178  } else {
179  ion = dup(fileno(tmp));
180  if (ion<0) {
181  perror("konsole: cannot dup temp file.\n");
182  fclose(tmp);
183  }
184  }
185  if (ion < 0)
186  return false;
187 
188  assert(!lastblock);
189 
190  lastblock = new Block();
191  size = newsize;
192  return false;
193  }
194 
195  if (newsize > size) {
196  increaseBuffer();
197  size = newsize;
198  return false;
199  } else {
200  decreaseBuffer(newsize);
201  if (ftruncate(ion, length*blocksize) == -1)
202  perror("ftruncate");
203  size = newsize;
204 
205  return true;
206  }
207 }
208 
209 void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
210 {
211  int res = fseek(fion, cursor * blocksize, SEEK_SET);
212  if (res)
213  perror("fseek");
214  res = fread(buffer2, blocksize, 1, fion);
215  if (res != 1)
216  perror("fread");
217 
218  res = fseek(fion, newpos * blocksize, SEEK_SET);
219  if (res)
220  perror("fseek");
221  res = fwrite(buffer2, blocksize, 1, fion);
222  if (res != 1)
223  perror("fwrite");
224  // printf("moving block %d to %d\n", cursor, newpos);
225 }
226 
227 void BlockArray::decreaseBuffer(size_t newsize)
228 {
229  if (index < newsize) // still fits in whole
230  return;
231 
232  int offset = (current - (newsize - 1) + size) % size;
233 
234  if (!offset)
235  return;
236 
237  // The Block constructor could do somthing in future...
238  char *buffer1 = new char[blocksize];
239 
240  FILE *fion = fdopen(dup(ion), "w+b");
241  if (!fion) {
242  delete [] buffer1;
243  perror("fdopen/dup");
244  return;
245  }
246 
247  int firstblock;
248  if (current <= newsize) {
249  firstblock = current + 1;
250  } else {
251  firstblock = 0;
252  }
253 
254  size_t oldpos;
255  for (size_t i = 0, cursor=firstblock; i < newsize; i++) {
256  oldpos = (size + cursor + offset) % size;
257  moveBlock(fion, oldpos, cursor, buffer1);
258  if (oldpos < newsize) {
259  cursor = oldpos;
260  } else
261  cursor++;
262  }
263 
264  current = newsize - 1;
265  length = newsize;
266 
267  delete [] buffer1;
268 
269  fclose(fion);
270 
271 }
272 
274 {
275  if (index < size) // not even wrapped once
276  return;
277 
278  int offset = (current + size + 1) % size;
279  if (!offset) // no moving needed
280  return;
281 
282  // The Block constructor could do somthing in future...
283  char *buffer1 = new char[blocksize];
284  char *buffer2 = new char[blocksize];
285 
286  int runs = 1;
287  int bpr = size; // blocks per run
288 
289  if (size % offset == 0) {
290  bpr = size / offset;
291  runs = offset;
292  }
293 
294  FILE *fion = fdopen(dup(ion), "w+b");
295  if (!fion) {
296  perror("fdopen/dup");
297  delete [] buffer1;
298  delete [] buffer2;
299  return;
300  }
301 
302  int res;
303  for (int i = 0; i < runs; i++)
304  {
305  // free one block in chain
306  int firstblock = (offset + i) % size;
307  res = fseek(fion, firstblock * blocksize, SEEK_SET);
308  if (res)
309  perror("fseek");
310  res = fread(buffer1, blocksize, 1, fion);
311  if (res != 1)
312  perror("fread");
313  int newpos = 0;
314  for (int j = 1, cursor=firstblock; j < bpr; j++)
315  {
316  cursor = (cursor + offset) % size;
317  newpos = (cursor - offset + size) % size;
318  moveBlock(fion, cursor, newpos, buffer2);
319  }
320  res = fseek(fion, i * blocksize, SEEK_SET);
321  if (res)
322  perror("fseek");
323  res = fwrite(buffer1, blocksize, 1, fion);
324  if (res != 1)
325  perror("fwrite");
326  }
327  current = size - 1;
328  length = size;
329 
330  delete [] buffer1;
331  delete [] buffer2;
332 
333  fclose(fion);
334 
335 }
336