Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/store.cpp

Source at commit 1322 created 12 years 8 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 * $Id:$
4 *
5 *
6 * Copyright (C) 1997-2011 by Dimitri van Heesch.
7 *
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation under the terms of the GNU General Public License is hereby
10 * granted. No representations are made about the suitability of this software
11 * for any purpose. It is provided "as is" without express or implied warranty.
12 * See the GNU General Public License for more details.
13 *
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
16 *
17 */
18
19#include "store.h"
20#include "portable.h"
21
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#include <assert.h>
28
29#define BLOCK_SIZE 512 // should be >8 and a multiple of 8
30#define BLOCK_POINTER_SIZE sizeof(portable_off_t)
31
32
33#define ASSERTS_ENABLED
34
35#ifdef ASSERTS_ENABLED
36#define STORE_ASSERT(x) assert(x)
37#else
38#define STORE_ASSERT(x)
39#endif
40
41//------------------------------------------------------------------------------------
42
43Store::Store()
44{
45 m_file = 0;
46 m_front = 0;
47 m_head = 0;
48 m_state = Init;
49 m_reads = 0;
50 m_writes = 0;
51}
52
53Store::~Store()
54{
55 if (m_file) fclose(m_file);
56
57 // clean up free list
58 while (m_head)
59 {
60 Node *node = m_head;
61 m_head = node->next;
62 delete node;
63 }
64}
65
66int Store::open(const char *name)
67{
68 int i;
69 STORE_ASSERT(m_state==Init);
70 if (m_file) return 0; // already open
71 m_file = portable_fopen(name,"w+b");
72 if (m_file==0) return -1;
73
74 // first block serves as header, so offset=0 can be used as the end of the list.
75 for (i=0;i<BLOCK_SIZE/8;i++)
76 {
77 fputc('D',m_file);
78 fputc('O',m_file);
79 fputc('X',m_file);
80 fputc('Y',m_file);
81 fputc('G',m_file);
82 fputc('E',m_file);
83 fputc('N',m_file);
84 fputc(0,m_file);
85 }
86 m_front = BLOCK_SIZE;
87 m_head = 0;
88 m_state = Reading;
89 return 0;
90}
91
92void Store::close()
93{
94 if (m_file) fclose(m_file);
95 m_file=0;
96 m_state = Init;
97}
98
99portable_off_t Store::alloc()
100{
101 STORE_ASSERT(m_state==Reading);
102 m_state=Writing;
103 portable_off_t pos;
104 if (m_head==0) // allocate new block
105 {
106 //printf("alloc: new block\n");
107 if (portable_fseek(m_file,0,SEEK_END)==-1) // go to end of the file
108 {
109 fprintf(stderr,"Store::alloc: Error seeking to end of file: %s\n",strerror(errno));
110 exit(1);
111 }
112 pos = portable_ftell(m_file);
113 STORE_ASSERT( (pos & (BLOCK_SIZE-1))==0 );
114 m_front = pos + BLOCK_SIZE; // move front to end of this block
115 }
116 else // reuse freed block
117 {
118 //printf("alloc: reuse block: m_head=%d\n",(int)m_head);
119 Node *node = m_head;
120 pos = node->pos;
121 // point head to next free item
122 m_head = node->next;
123 delete node;
124 // move to start of the block
125 if (portable_fseek(m_file,pos,SEEK_SET)==-1)
126 {
127 fprintf(stderr,"Store::alloc: Error seeking to position %d: %s\n",
128 (int)pos,strerror(errno));
129 exit(1);
130 }
131 STORE_ASSERT( (pos & (BLOCK_SIZE-1))==0 );
132 }
133 //printf("%x: Store::alloc\n",(int)pos);
134 return pos;
135}
136
137int Store::write(const char *buf,uint size)
138{
139 STORE_ASSERT(m_state==Writing);
140 //printf("%x: Store::write\n",(int)portable_ftell(m_file));
141 do
142 {
143 portable_off_t curPos = portable_ftell(m_file);
144 int bytesInBlock = BLOCK_SIZE - BLOCK_POINTER_SIZE - (curPos & (BLOCK_SIZE-1));
145 int bytesLeft = bytesInBlock<(int)size ? (int)size-bytesInBlock : 0;
146 int numBytes = size - bytesLeft;
147 STORE_ASSERT(bytesInBlock>=0);
148 STORE_ASSERT(numBytes<=(int)(BLOCK_SIZE-BLOCK_POINTER_SIZE));
149 if (numBytes>0)
150 {
151 if ((int)fwrite(buf,1,numBytes,m_file)!=numBytes)
152 {
153 fprintf(stderr,"Error writing: %s\n",strerror(errno));
154 exit(1);
155 }
156 m_writes++;
157 }
158 if (bytesLeft>0) // still more bytes to write
159 {
160 STORE_ASSERT(((portable_ftell(m_file)+BLOCK_POINTER_SIZE)&(BLOCK_SIZE-1))==0);
161 // allocate new block
162 if (m_head==0) // no free blocks to reuse
163 {
164 //printf("%x: Store::write: new: pos=%x\n",(int)m_front,(int)portable_ftell(m_file));
165 // write pointer to next block
166 if (fwrite(&m_front,BLOCK_POINTER_SIZE,1,m_file)!=1)
167 {
168 fprintf(stderr,"Error writing to store: %s\n",strerror(errno));
169 exit(1);
170 }
171 STORE_ASSERT(portable_ftell(m_file)==(curPos&~(BLOCK_SIZE-1))+BLOCK_SIZE);
172
173 // move to next block
174 if (portable_fseek(m_file,0,SEEK_END)==-1) // go to end of the file
175 {
176 fprintf(stderr,"Store::alloc: Error seeking to end of file: %s\n",strerror(errno));
177 exit(1);
178 }
179 STORE_ASSERT(portable_ftell(m_file)==m_front);
180 // move front to the next of the block
181 m_front+=BLOCK_SIZE;
182 }
183 else // reuse block from the free list
184 {
185 // write pointer to next block
186 if (fwrite(&m_head->pos,BLOCK_POINTER_SIZE,1,m_file)!=1)
187 {
188 fprintf(stderr,"Error writing to store: %s\n",strerror(errno));
189 exit(1);
190 }
191 Node *node = m_head;
192 portable_off_t pos = node->pos;
193 // point head to next free item
194 m_head = node->next;
195 delete node;
196 // move to start of the block
197 if (portable_fseek(m_file,pos,SEEK_SET)==-1)
198 {
199 fprintf(stderr,"Store::write: Error seeking to position %d: %s\n",
200 (int)pos,strerror(errno));
201 exit(1);
202 }
203 //printf("%x: Store::write: reuse\n",(int)pos);
204 }
205 }
206 size-=numBytes;
207 buf+=numBytes;
208 }
209 while (size>0);
210 return size;
211}
212
213void Store::end()
214{
215 STORE_ASSERT(m_state==Writing);
216 portable_off_t curPos = portable_ftell(m_file);
217 int bytesInBlock = BLOCK_SIZE - (curPos & (BLOCK_SIZE-1));
218 //printf("%x: Store::end erasing %x bytes\n",(int)curPos&~(BLOCK_SIZE-1),bytesInBlock);
219 //printf("end: bytesInBlock=%x\n",bytesInBlock);
220 // zero out rest of the block
221 int i;
222 for (i=0;i<bytesInBlock;i++)
223 {
224 fputc(0,m_file);
225 }
226 m_state=Reading;
227}
228
229void Store::release(portable_off_t pos)
230{
231 STORE_ASSERT(m_state==Reading);
232 //printf("%x: Store::release\n",(int)pos);
233 STORE_ASSERT(pos>0 && (pos & (BLOCK_SIZE-1))==0);
234 // goto end of the block
235 portable_off_t cur = pos, next;
236 while (1)
237 {
238 // add new node to the free list
239 Node *node = new Node;
240 node->next = m_head;
241 node->pos = cur;
242
243 m_head = node;
244 // goto the end of cur block
245 if (portable_fseek(m_file,cur+BLOCK_SIZE-BLOCK_POINTER_SIZE,SEEK_SET)==-1)
246 {
247 fprintf(stderr,"Store::release: Error seeking to position %d: %s\n",
248 (int)(cur+BLOCK_SIZE-BLOCK_POINTER_SIZE),strerror(errno));
249 exit(1);
250 }
251 // read pointer to next block
252 if (fread(&next,BLOCK_POINTER_SIZE,1,m_file)!=1)
253 {
254 fprintf(stderr,"Store::release: Error reading from store: %s\n",strerror(errno));
255 exit(1);
256 }
257 if (next==0) break; // found end of list -> cur is last element
258 STORE_ASSERT((next & (BLOCK_SIZE-1))==0);
259 cur = next;
260 //printf("%x: Store::release\n",(int)cur);
261 }
262}
263
264void Store::seek(portable_off_t pos)
265{
266 STORE_ASSERT(m_state==Reading);
267 //printf("%x: Store::seek\n",(int)pos);
268 if (portable_fseek(m_file,pos,SEEK_SET)==-1)
269 {
270 fprintf(stderr,"Store::seek: Error seeking to position %d: %s\n",
271 (int)pos,strerror(errno));
272 exit(1);
273 }
274 STORE_ASSERT((pos&(BLOCK_SIZE-1))==0);
275}
276
277int Store::read(char *buf,uint size)
278{
279 STORE_ASSERT(m_state==Reading);
280 //printf("%x: Store::read total=%d\n",(int)portable_ftell(m_file),size);
281 do
282 {
283 portable_off_t curPos = portable_ftell(m_file);
284 int bytesInBlock = BLOCK_SIZE - BLOCK_POINTER_SIZE - (curPos & (BLOCK_SIZE-1));
285 int bytesLeft = bytesInBlock<(int)size ? (int)size-bytesInBlock : 0;
286 int numBytes = size - bytesLeft;
287 //printf(" Store::read: pos=%x num=%d left=%d\n",(int)curPos,numBytes,bytesLeft);
288
289 if (numBytes>0)
290 {
291 //printf("%x: Store::read: %d out of %d bytes\n",(int)portable_ftell(m_file),numBytes,size);
292 if ((int)fread(buf,1,numBytes,m_file)!=numBytes)
293 {
294 fprintf(stderr,"Error reading from store: %s\n",strerror(errno));
295 exit(1);
296 }
297 m_reads++;
298 }
299 if (bytesLeft>0)
300 {
301 portable_off_t newPos;
302 // read offset of the next block
303 STORE_ASSERT(((portable_ftell(m_file)+BLOCK_POINTER_SIZE)&(BLOCK_SIZE-1))==0);
304 if (fread((char *)&newPos,BLOCK_POINTER_SIZE,1,m_file)!=1)
305 {
306 fprintf(stderr,"Error reading from store: %s\n",strerror(errno));
307 exit(1);
308 }
309 //printf("%x: Store::read: continue in next block, %d bytes to go\n",(int)newPos,bytesLeft);
310 //printf(" Store::read: next block=%x\n",(int)newPos);
311 STORE_ASSERT(newPos!=0);
312 STORE_ASSERT((newPos&(BLOCK_SIZE-1))==0);
313 curPos = newPos;
314 // move to next block
315 if (portable_fseek(m_file,curPos,SEEK_SET)==-1)
316 {
317 fprintf(stderr,"Store::read: Error seeking to position %d: %s\n",
318 (int)curPos,strerror(errno));
319 exit(1);
320 }
321 }
322
323 size-=numBytes;
324 buf+=numBytes;
325 }
326 while (size>0);
327 return size;
328}
329
330void Store::printFreeList()
331{
332 printf("FreeList: ");
333 portable_off_t pos = m_head->pos;
334 while (pos)
335 {
336 printf("%x ",(int)pos);
337 m_head = m_head->next;
338 }
339 printf("\n");
340}
341
342void Store::printStats()
343{
344 printf("ObjStore: block size %d bytes, total size %ld blocks, wrote %d blocks, read %d blocks\n",
345 BLOCK_SIZE,(long)(m_front/BLOCK_SIZE),m_reads,m_writes);
346}
347
348#ifdef STORE_TEST
349
350int main()
351{
352 printf("sizeof(portable_off_t)=%d\n",(int)sizeof(portable_off_t));
353 Store s;
354 if (s.open("test.db")==0)
355 {
356 const char *str1 = "This is a test message... ";
357 const char *str2 = "Another message. ";
358
359 int i,j;
360 for (j=0;j<5;j++)
361 {
362 char buf[100];
363
364 portable_off_t handle = s.alloc();
365 for (i=0;i<1000000000;i++)
366 {
367 s.write(str1,strlen(str1)+1);
368 }
369 s.end();
370 portable_off_t handle2 = s.alloc();
371 for (i=0;i<10;i++)
372 {
373 s.write(str2,strlen(str2)+1);
374 }
375 s.end();
376
377 s.seek(handle);
378 for (i=0;i<3;i++)
379 {
380 s.read(buf,strlen(str1)+1);
381 printf("i=%d Read: %s\n",i,buf);
382 }
383
384 s.release(handle);
385
386 s.seek(handle2);
387 for (i=0;i<3;i++)
388 {
389 s.read(buf,strlen(str2)+1);
390 printf("i=%d Read: %s\n",i,buf);
391 }
392
393 s.release(handle2);
394 }
395
396 s.close();
397 }
398 else
399 {
400 printf("Open failed! %s\n",strerror(errno));
401 }
402}
403
404#endif
405
406

Archive Download this file

Revision: 1322