GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
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(nullptr),
44  lastmap_index(size_t(-1)),
45  lastblock(nullptr), 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 nullptr;
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(nullptr, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize);
132 
133  if (block == (Block*)-1) { perror("mmap"); return nullptr; }
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 = nullptr;
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 = nullptr;
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 }
static int blocksize
Definition: BlockArray.cpp:37
void moveBlock(FILE *fion, int cursor, int newpos, char *buffer2)
Definition: BlockArray.cpp:209
#define SEEK_SET
bool has(size_t index) const
Definition: BlockArray.cpp:96
size_t current
Definition: BlockArray.h:106
size_t length
Definition: BlockArray.h:114
void decreaseBuffer(size_t newsize)
Definition: BlockArray.cpp:227
size_t newBlock()
Definition: BlockArray.cpp:81
Block * lastblock
Definition: BlockArray.h:111
void increaseBuffer()
Definition: BlockArray.cpp:273
void unmap()
Definition: BlockArray.cpp:141
size_t index
Definition: BlockArray.h:107
BlockArray()
Creates a history file for holding maximal size blocks.
Definition: BlockArray.cpp:39
const Block * at(size_t index)
gets the block at the index.
Definition: BlockArray.cpp:108
~BlockArray()
destructor
Definition: BlockArray.cpp:54
Block * lastBlock() const
Definition: BlockArray.cpp:91
bool setSize(size_t newsize)
Convenient function to set the size in KBytes instead of blocks.
Definition: BlockArray.cpp:151
bool setHistorySize(size_t newsize)
reorders blocks as needed.
Definition: BlockArray.cpp:156
size_t lastmap_index
Definition: BlockArray.h:110
size_t append(Block *block)
adds the Block at the end of history.
Definition: BlockArray.cpp:60
size_t size
Definition: BlockArray.h:104
Block * lastmap
Definition: BlockArray.h:109