~ubuntu-branches/ubuntu/warty/swish-e/warty

« back to all changes in this revision

Viewing changes to src/worddata.c

  • Committer: Bazaar Package Importer
  • Author(s): Ludovic Drolez
  • Date: 2004-03-11 08:41:07 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040311084107-7vp0mu82blq1qjvo
Tags: 2.4.1-3
Oops ! A comment was not removed to disable interactive compilation.
Closes: Bug#237332

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <stdio.h>
 
2
#include <stdlib.h>
 
3
#include <string.h>
 
4
 
 
5
/*
 
6
#define DEBUG
 
7
*/
 
8
 
 
9
#include "swish.h"
 
10
#include "mem.h"
 
11
#include "compress.h"
 
12
#include "worddata.h"
 
13
 
 
14
/* WORDDATA page size */
 
15
/* !!!! Must no be less than 4096 and not greater than 65536*/
 
16
#define WORDDATA_PageSize 4096
 
17
/* WORDDATA Block size */
 
18
#define WORDDATA_BlockSize (WORDDATA_PageSize >> 8)
 
19
 
 
20
#define SizeInt32 4
 
21
 
 
22
/* Round to WORDDATA_PageSize */
 
23
#define WORDDATA_RoundPageSize(n) (((n) + WORDDATA_PageSize - 1) & (~(WORDDATA_PageSize - 1)))
 
24
 
 
25
/* Round a number to the upper BlockSize */
 
26
#define WORDDATA_RoundBlockSize(n) (((n) + WORDDATA_BlockSize - 1) & (~(WORDDATA_BlockSize - 1)))
 
27
 
 
28
/* Let's asign the first block for the header */
 
29
#define WORDDATA_PageHeaderSize (WORDDATA_BlockSize) 
 
30
 
 
31
/* Max data size to fit in a single page */
 
32
#define WORDDATA_MaxDataSize (WORDDATA_PageSize - WORDDATA_PageHeaderSize)
 
33
 
 
34
#define WORDDATA_PageData(pg) ((pg)->data + WORDDATA_PageHeaderSize)
 
35
#define WORDDATA_Data(pg,i) (WORDDATA_PageData((pg)) + (i) * SizeInt32)
 
36
 
 
37
#define WORDDATA_SetBlocksInUse(pg,num) ( *(int *)((pg)->data + 0 * SizeInt32) = PACKLONG(num))
 
38
#define WORDDATA_GetBlocksInUse(pg,num) ( (num) = UNPACKLONG(*(int *)((pg)->data + 0 * SizeInt32)))
 
39
 
 
40
#define WORDDATA_SetNumRecords(pg,num) ( *(int *)((pg)->data + 1 * SizeInt32) = PACKLONG(num))
 
41
#define WORDDATA_GetNumRecords(pg,num) ( (num) = UNPACKLONG(*(int *)((pg)->data + 1 * SizeInt32)))
 
42
 
 
43
 
 
44
int WORDDATA_WritePageToDisk(FILE *fp, WORDDATA_Page *pg)
 
45
{
 
46
    WORDDATA_SetBlocksInUse(pg,pg->used_blocks);
 
47
    WORDDATA_SetNumRecords(pg,pg->n);
 
48
    fseek(fp,pg->page_number * WORDDATA_PageSize,SEEK_SET);
 
49
    if ( fwrite(pg->data,WORDDATA_PageSize,1,fp) != 1 )
 
50
        progerrno("Failed to write page to disk: "); 
 
51
    return 1;
 
52
}
 
53
 
 
54
int WORDDATA_WritePage(WORDDATA *b, WORDDATA_Page *pg)
 
55
{
 
56
int hash = pg->page_number % WORDDATA_CACHE_SIZE;
 
57
WORDDATA_Page *tmp;
 
58
    pg->modified =1;
 
59
    if((tmp = b->cache[hash]))
 
60
    {
 
61
        while(tmp)
 
62
        {
 
63
            if(tmp->page_number == pg->page_number)
 
64
            {
 
65
                return 0;
 
66
            }
 
67
            tmp = tmp->next_cache;
 
68
        }
 
69
    }
 
70
    pg->next_cache = b->cache[hash];
 
71
    b->cache[hash] = pg;
 
72
    return 0;
 
73
}
 
74
 
 
75
int WORDDATA_FlushCache(WORDDATA *b)
 
76
{
 
77
int i;
 
78
WORDDATA_Page *tmp, *next;
 
79
    for(i = 0; i < WORDDATA_CACHE_SIZE; i++)
 
80
    {
 
81
        if((tmp = b->cache[i]))
 
82
        {
 
83
            while(tmp)
 
84
            {
 
85
                next = tmp->next_cache;
 
86
                if(tmp->modified)
 
87
                {
 
88
                    WORDDATA_WritePageToDisk(b->fp, tmp);
 
89
                    tmp->modified = 0;
 
90
                }
 
91
                if(tmp != b->cache[i])
 
92
                    efree(tmp);
 
93
 
 
94
                tmp = next;
 
95
            }
 
96
            b->cache[i]->next_cache = NULL;
 
97
        }
 
98
    }
 
99
    return 0;
 
100
}
 
101
 
 
102
int WORDDATA_CleanCache(WORDDATA *b)
 
103
{
 
104
int i;
 
105
WORDDATA_Page *tmp,*next;
 
106
    for(i = 0; i < WORDDATA_CACHE_SIZE; i++)
 
107
    {
 
108
        if((tmp = b->cache[i]))
 
109
        {
 
110
            while(tmp)
 
111
            {
 
112
                next = tmp->next_cache;
 
113
                efree(tmp);
 
114
                tmp = next;
 
115
            }
 
116
            b->cache[i] = NULL;
 
117
        }
 
118
    }
 
119
    return 0;
 
120
}
 
121
 
 
122
WORDDATA_Page *WORDDATA_ReadPageFromDisk(FILE *fp, unsigned long page_number)
 
123
{
 
124
WORDDATA_Page *pg = (WORDDATA_Page *)emalloc(sizeof(WORDDATA_Page) + WORDDATA_PageSize);
 
125
 
 
126
    fseek(fp,page_number * WORDDATA_PageSize,SEEK_SET);
 
127
    fread(pg->data,WORDDATA_PageSize, 1, fp);
 
128
 
 
129
    WORDDATA_GetBlocksInUse(pg,pg->used_blocks);
 
130
    WORDDATA_GetNumRecords(pg,pg->n);
 
131
 
 
132
    pg->page_number = page_number;
 
133
    pg->modified = 0;
 
134
    return pg;
 
135
}
 
136
 
 
137
WORDDATA_Page *WORDDATA_ReadPage(WORDDATA *b, unsigned long page_number)
 
138
{
 
139
int hash = page_number % WORDDATA_CACHE_SIZE;
 
140
WORDDATA_Page *tmp;
 
141
    if((tmp = b->cache[hash]))
 
142
    {
 
143
        while(tmp)
 
144
        {
 
145
            if(tmp->page_number == page_number)
 
146
            {
 
147
                return tmp;
 
148
            }
 
149
            tmp = tmp->next_cache;
 
150
        }
 
151
    }
 
152
 
 
153
    tmp = WORDDATA_ReadPageFromDisk(b->fp, page_number);
 
154
    tmp->modified = 0;
 
155
    tmp->in_use = 1;
 
156
    tmp->next_cache = b->cache[hash];
 
157
    b->cache[hash] = tmp;
 
158
    return tmp;
 
159
}
 
160
 
 
161
 
 
162
WORDDATA_Page *WORDDATA_NewPage(WORDDATA *b)
 
163
{
 
164
WORDDATA_Page *pg;
 
165
long offset;
 
166
FILE *fp = b->fp;
 
167
int hash;
 
168
int size = WORDDATA_PageSize;
 
169
int i;
 
170
unsigned long page_number =0;
 
171
    /* Let's see if we have a previous available page */
 
172
    if(b->num_Reusable_Pages)
 
173
    {
 
174
        /* First, look for a page of the same size */
 
175
        for(i = 0; i < b->num_Reusable_Pages ; i++)
 
176
        {
 
177
            if(size == b->Reusable_Pages[i].page_size)
 
178
                break;
 
179
        }
 
180
        /* If not found, let's try with a bigger one if exits */
 
181
        if(i == b->num_Reusable_Pages)
 
182
        {
 
183
            for(i = 0; i < b->num_Reusable_Pages ; i++)
 
184
            {
 
185
                if(size < b->Reusable_Pages[i].page_size)
 
186
                    break;
 
187
            }
 
188
        }
 
189
        /* If we got one page return it */
 
190
        if(i != b->num_Reusable_Pages)
 
191
        {
 
192
            page_number = b->Reusable_Pages[i].page_number;
 
193
            if(size == b->Reusable_Pages[i].page_size)
 
194
            {
 
195
                for(++i;i<b->num_Reusable_Pages;i++)
 
196
                {
 
197
                    /* remove page */
 
198
                    b->Reusable_Pages[i-1].page_number=b->Reusable_Pages[i].page_number;
 
199
                    b->Reusable_Pages[i-1].page_size=b->Reusable_Pages[i].page_size;
 
200
                }
 
201
                b->num_Reusable_Pages--;
 
202
            }
 
203
            else
 
204
            {
 
205
                b->Reusable_Pages[i].page_number += size/WORDDATA_PageSize;
 
206
                b->Reusable_Pages[i].page_size -= size;
 
207
            }
 
208
        }
 
209
    }
 
210
    /* If there is not any reusable page let's get it from disk */
 
211
    if(! page_number)
 
212
    {
 
213
        /* Get file pointer */
 
214
        if(fseek(fp,0,SEEK_END) !=0)
 
215
            progerrno("Internal error seeking: "); 
 
216
 
 
217
 
 
218
        offset = ftell(fp);
 
219
        /* Round up file pointer */
 
220
        offset = WORDDATA_RoundPageSize(offset);
 
221
 
 
222
        /* Set new file pointer - data will be aligned */
 
223
        if(fseek(fp,offset, SEEK_SET)!=0 || offset != ftell(fp))
 
224
            progerrno("Internal error seeking: "); 
 
225
 
 
226
        if(fwrite("\0",1,size,fp)!=size || ((long)size + offset) != ftell(fp))
 
227
            progerrno("Faild to write page data: ");
 
228
 
 
229
        page_number = offset/WORDDATA_PageSize;
 
230
    }
 
231
 
 
232
    pg = (WORDDATA_Page *)emalloc(sizeof(WORDDATA_Page) + size);
 
233
    memset(pg,0,sizeof(WORDDATA_Page) + size);
 
234
        /* Reserve space in file */
 
235
 
 
236
    pg->used_blocks = 0;
 
237
    pg->n = 0; /* Number of records */
 
238
 
 
239
    pg->page_number = page_number;
 
240
 
 
241
    /* add to cache */
 
242
    pg->modified = 1;
 
243
    pg->in_use = 1;
 
244
    hash = pg->page_number % WORDDATA_CACHE_SIZE;
 
245
    pg->next_cache = b->cache[hash];
 
246
    b->cache[hash] = pg;
 
247
    return pg;
 
248
}
 
249
 
 
250
void WORDDATA_FreePage(WORDDATA *b, WORDDATA_Page *pg)
 
251
{
 
252
int hash = pg->page_number % WORDDATA_CACHE_SIZE;
 
253
WORDDATA_Page *tmp;
 
254
 
 
255
    tmp = b->cache[hash];
 
256
 
 
257
    while(tmp)
 
258
    {
 
259
        if (tmp->page_number != pg->page_number)
 
260
            tmp = tmp->next_cache;
 
261
        else
 
262
        {
 
263
            tmp->in_use = 0;
 
264
            break;
 
265
        }
 
266
    }
 
267
}
 
268
 
 
269
WORDDATA *WORDDATA_New(FILE *fp)
 
270
{
 
271
WORDDATA *b;
 
272
int i;
 
273
    b = (WORDDATA *) emalloc(sizeof(WORDDATA));
 
274
    b->fp = fp;
 
275
    b->last_put_page = 0;
 
276
    b->last_del_page = 0;
 
277
    b->last_get_page = 0;
 
278
    b->page_counter = 0;
 
279
    for(i = 0; i < WORDDATA_CACHE_SIZE; i++)
 
280
        b->cache[i] = NULL;
 
281
 
 
282
    b->num_Reusable_Pages = 0;
 
283
    return b;
 
284
}
 
285
 
 
286
 
 
287
WORDDATA *WORDDATA_Open(FILE *fp)
 
288
{
 
289
WORDDATA *b;
 
290
 
 
291
    b = WORDDATA_New(fp);
 
292
 
 
293
    return b;
 
294
}
 
295
 
 
296
void WORDDATA_Close(WORDDATA *bt)
 
297
{
 
298
    WORDDATA_FlushCache(bt);
 
299
    WORDDATA_CleanCache(bt);
 
300
    efree(bt);
 
301
}
 
302
 
 
303
 
 
304
unsigned long WORDDATA_PutBig(WORDDATA *b, unsigned int len, unsigned char *data)
 
305
{
 
306
long offset;
 
307
int size = WORDDATA_RoundPageSize(sizeof(unsigned long) + len);
 
308
unsigned long p_len = (unsigned long)PACKLONG((unsigned long)len);
 
309
FILE *fp = b->fp;
 
310
unsigned long id;
 
311
unsigned long page_number = 0;
 
312
int i;
 
313
    /* Let's see if we have a previous available page */
 
314
    if(b->num_Reusable_Pages)
 
315
    {
 
316
        /* First, look for a page of the same size */
 
317
        for(i = 0; i < b->num_Reusable_Pages ; i++)
 
318
        {
 
319
            if(size == b->Reusable_Pages[i].page_size)
 
320
                break;
 
321
        }
 
322
        /* If not found, let's try with a bigger one if exits */
 
323
        if(i == b->num_Reusable_Pages)
 
324
        {
 
325
            for(i = 0; i < b->num_Reusable_Pages ; i++)
 
326
            {
 
327
                if(size < b->Reusable_Pages[i].page_size)
 
328
                    break;
 
329
            }
 
330
        }
 
331
        /* If we got one page return it */
 
332
        if(i != b->num_Reusable_Pages)
 
333
        {
 
334
            page_number = b->Reusable_Pages[i].page_number;
 
335
            if(size == b->Reusable_Pages[i].page_size)
 
336
            {
 
337
                for(++i;i<b->num_Reusable_Pages;i++)
 
338
                {
 
339
                    /* remove page */
 
340
                    b->Reusable_Pages[i-1].page_number=b->Reusable_Pages[i].page_number;
 
341
                    b->Reusable_Pages[i-1].page_size=b->Reusable_Pages[i].page_size;
 
342
                }
 
343
                b->num_Reusable_Pages--;
 
344
            }
 
345
            else
 
346
            {
 
347
                b->Reusable_Pages[i].page_number += size/WORDDATA_PageSize;
 
348
                b->Reusable_Pages[i].page_size -= size;
 
349
            }
 
350
        }
 
351
    }
 
352
    if(! page_number)
 
353
    {
 
354
        /* Get file pointer */
 
355
        if(fseek(fp,0,SEEK_END) !=0)
 
356
            progerrno("Internal error seeking: "); 
 
357
 
 
358
        offset = ftell(fp);
 
359
        /* Round up file pointer */
 
360
        offset = WORDDATA_RoundPageSize(offset);
 
361
    }
 
362
    else
 
363
    {
 
364
        offset = page_number * WORDDATA_PageSize;
 
365
    }
 
366
    /* Set new file pointer - data will be aligned */
 
367
    if(fseek(fp,offset, SEEK_SET)!=0 || offset != ftell(fp))
 
368
        progerrno("Internal error seeking: "); 
 
369
 
 
370
    id = ((unsigned long) (offset / WORDDATA_PageSize)) << 8;
 
371
 
 
372
    /* Write packed length */
 
373
    fwrite(&p_len,1,SizeInt32,fp);
 
374
    /* Write data */
 
375
    fwrite(data,1,len,fp);
 
376
 
 
377
    /* New offset */
 
378
    offset = ftell(fp);
 
379
    /* Round up file pointer */
 
380
    offset = WORDDATA_RoundPageSize(offset);
 
381
    /* Set new file pointer - data will be aligned */
 
382
    if(fseek(fp,offset, SEEK_SET)!=0 || offset != ftell(fp))
 
383
        progerrno("Internal error seeking: "); 
 
384
 
 
385
    b->lastid = id;
 
386
    return id;
 
387
}
 
388
 
 
389
 
 
390
unsigned long WORDDATA_Put(WORDDATA *b, unsigned int len, unsigned char *data)
 
391
{
 
392
int required_length;
 
393
int free_blocks;
 
394
int i, r_id, r_len, tmp;
 
395
int last_id, free_id;
 
396
unsigned char *p,*q;
 
397
unsigned char buffer[WORDDATA_PageSize];
 
398
WORDDATA_Page *last_page=NULL;
 
399
    /* Check if data fits in a single page */
 
400
    /* We need 1 byte for the id plus two bytes for the size */ 
 
401
    required_length = len + 1 + 2;
 
402
    /* Round it to the upper block size */
 
403
    required_length = WORDDATA_RoundBlockSize(required_length);
 
404
    if(required_length > WORDDATA_MaxDataSize)
 
405
    {
 
406
        /* Store long record in file */
 
407
        return WORDDATA_PutBig(b,len,data);
 
408
    }
 
409
 
 
410
    /* let's see if the data fits in the last page */
 
411
    /* First - Check for a page with a Del Operation */
 
412
    if(b->last_del_page)
 
413
    {
 
414
        free_blocks = 255 - b->last_del_page->used_blocks;
 
415
        if(!(required_length > (free_blocks * WORDDATA_BlockSize)))
 
416
        {
 
417
            last_page = b->last_del_page;
 
418
        }
 
419
    }
 
420
    if(!last_page)
 
421
    {
 
422
        if( b->last_put_page)
 
423
        {
 
424
            /* Now check for the last page in a put operation */
 
425
            free_blocks = 255 - b->last_put_page->used_blocks;
 
426
            if(required_length > (free_blocks * WORDDATA_BlockSize))
 
427
            {
 
428
                WORDDATA_FreePage(b,b->last_put_page);
 
429
 
 
430
                /* Save some memory - Do some flush flush of the data */
 
431
                if(!(b->page_counter % WORDDATA_CACHE_SIZE))
 
432
                {
 
433
                    WORDDATA_FlushCache(b);
 
434
                    WORDDATA_CleanCache(b);
 
435
                    b->page_counter = 0;
 
436
                    b->last_get_page = b->last_put_page = b->last_del_page =  0;
 
437
                }
 
438
                b->page_counter++;
 
439
                b->last_put_page = WORDDATA_NewPage(b);
 
440
            }
 
441
        }
 
442
        else
 
443
        {
 
444
            /* Save some memory - Do some flush flush of the data */
 
445
            if(!(b->page_counter % WORDDATA_CACHE_SIZE))
 
446
            {
 
447
                WORDDATA_FlushCache(b);
 
448
                WORDDATA_CleanCache(b);
 
449
                b->page_counter = 0;
 
450
                b->last_get_page = b->last_put_page = b->last_del_page =  0;
 
451
            }
 
452
            b->page_counter++;
 
453
            b->last_put_page = WORDDATA_NewPage(b);
 
454
        }
 
455
        last_page = b->last_put_page;
 
456
    }
 
457
    
 
458
    for(i = 0, free_id = 0, last_id = 0, p = WORDDATA_PageData(last_page); i < last_page->n; i++)
 
459
    {
 
460
        /* Get the record id */
 
461
        r_id = (int) (p[0]);
 
462
        /* Get the record length */
 
463
        r_len = ((((int)(p[1])) << 8) + (int)(p[2]));
 
464
        if((r_id - last_id) > 1)   /* find a reusable id */
 
465
        {
 
466
            free_id = last_id + 1;
 
467
            break;
 
468
        }
 
469
        last_id = r_id;
 
470
        p += WORDDATA_RoundBlockSize((3 + r_len));
 
471
    }
 
472
    if(!free_id)
 
473
        free_id = last_id + 1;
 
474
 
 
475
    q = buffer;
 
476
    memcpy(q,WORDDATA_PageData(last_page), p - WORDDATA_PageData(last_page));
 
477
    q += p - WORDDATA_PageData(last_page);
 
478
    q[0] = (unsigned char) free_id;
 
479
    q[1] = (unsigned char) (len >> 8);
 
480
    q[2] = (unsigned char) (len & 0xff);
 
481
    memcpy(q+3,data,len);
 
482
    q += WORDDATA_RoundBlockSize((3 + len));
 
483
    for(;i < last_page->n; i++)
 
484
    {
 
485
        /* Get the record length */
 
486
        r_len = ((((int)(p[1])) << 8) + (int)(p[2]));
 
487
        tmp = WORDDATA_RoundBlockSize((3 + r_len));
 
488
        memcpy(q,p,tmp);
 
489
        p += tmp;
 
490
        q += tmp;
 
491
    }
 
492
    memcpy(WORDDATA_PageData(last_page),buffer,q - buffer);
 
493
    last_page->n++;
 
494
    last_page->used_blocks += required_length / WORDDATA_BlockSize;
 
495
    WORDDATA_WritePage(b,last_page);
 
496
    return (unsigned long)(b->lastid=(unsigned long)((last_page->page_number << 8) + free_id));
 
497
}
 
498
 
 
499
unsigned char *WORDDATA_GetBig(WORDDATA *b, unsigned long page_number, unsigned int *len)
 
500
{
 
501
long offset = (long) (page_number * WORDDATA_PageSize);
 
502
unsigned long p_len;
 
503
unsigned char *data;
 
504
    fseek(b->fp, offset, SEEK_SET);
 
505
    fread(&p_len,1,SizeInt32,b->fp);
 
506
    *len = UNPACKLONG(p_len);
 
507
    data = (unsigned char *)emalloc(*len);
 
508
    fread(data,1,*len,b->fp);
 
509
    return data;
 
510
}
 
511
 
 
512
unsigned char *WORDDATA_Get(WORDDATA *b, unsigned long global_id, unsigned int *len)
 
513
{
 
514
unsigned long page_number = global_id >> 8;
 
515
int id = (int)(global_id & 0xff);
 
516
int r_id=-1,r_len=-1;
 
517
int i;
 
518
unsigned char *p;
 
519
unsigned char *data;
 
520
 
 
521
    if(!id)
 
522
    {
 
523
        return WORDDATA_GetBig(b,page_number,len);
 
524
    }
 
525
    if(b->last_get_page)
 
526
        WORDDATA_FreePage(b,b->last_get_page);
 
527
 
 
528
    b->last_get_page = WORDDATA_ReadPage(b,page_number);
 
529
 
 
530
    for(i = 0, p = WORDDATA_PageData(b->last_get_page); i < b->last_get_page->n; i++)
 
531
    {
 
532
        /* Get the id */
 
533
        r_id = (int) (p[0]);
 
534
        /* Get the record length */
 
535
        r_len = ((((int)(p[1])) << 8) + (int)(p[2]));
 
536
        if(r_id == id)   /* find the id */
 
537
            break;
 
538
        p += WORDDATA_RoundBlockSize((3 + r_len));
 
539
    }
 
540
 
 
541
    if(id == r_id)
 
542
    {
 
543
        data = (unsigned char *) emalloc(r_len);
 
544
        memcpy(data , p + 3 , r_len);
 
545
        *len = r_len;
 
546
    }
 
547
    else   /* Error */
 
548
    {
 
549
        data = NULL;
 
550
        *len = 0;
 
551
    }
 
552
 
 
553
    return data;
 
554
}
 
555
 
 
556
void WORDDATA_DelBig(WORDDATA *b, unsigned long page_number, unsigned int *len)
 
557
{
 
558
long offset = (long) (page_number * WORDDATA_PageSize);
 
559
unsigned long p_len;
 
560
    fseek(b->fp, offset, SEEK_SET);
 
561
    fread(&p_len,1,SizeInt32,b->fp);
 
562
    *len = UNPACKLONG(p_len) + sizeof(unsigned long);
 
563
 
 
564
    if(b->num_Reusable_Pages < WORDDATA_MAX_REUSABLE_PAGES)
 
565
    {
 
566
       b->Reusable_Pages[b->num_Reusable_Pages].page_number = page_number;
 
567
       b->Reusable_Pages[b->num_Reusable_Pages++].page_size = WORDDATA_RoundPageSize(*len);
 
568
    }
 
569
}
 
570
 
 
571
void WORDDATA_Del(WORDDATA *b, unsigned long global_id, unsigned int *len)
 
572
{
 
573
unsigned long page_number = global_id >> 8;
 
574
int id = (int)(global_id & 0xff);
 
575
int r_id=-1,r_len=-1,tmp;
 
576
int i;
 
577
unsigned char *p, *q;
 
578
int deleted_length;
 
579
 
 
580
    if(!id)
 
581
    {
 
582
        WORDDATA_DelBig(b,page_number,len);
 
583
        return;
 
584
    }
 
585
    if(b->last_del_page)
 
586
        WORDDATA_FreePage(b,b->last_del_page);
 
587
 
 
588
    b->last_del_page = WORDDATA_ReadPage(b,page_number);
 
589
 
 
590
    for(i = 0, p = WORDDATA_PageData(b->last_del_page); i < b->last_del_page->n; i++)
 
591
    {
 
592
        /* Get the id */
 
593
        r_id = (int) (p[0]);
 
594
        /* Get the record length */
 
595
        r_len = ((((int)(p[1])) << 8) + (int)(p[2]));
 
596
        if(r_id == id)   /* id found */
 
597
            break;
 
598
        p += WORDDATA_RoundBlockSize((3 + r_len));
 
599
    }
 
600
 
 
601
    if(id == r_id)
 
602
    {
 
603
        *len = r_len;
 
604
        deleted_length = WORDDATA_RoundBlockSize(r_len);
 
605
        /* Move rest of worddata to put them contigous (Remove the hole) */
 
606
        /* q points to the hole, p to the next record */
 
607
        q = p;
 
608
        p += WORDDATA_RoundBlockSize((3 + r_len));
 
609
        for(++i;i < b->last_del_page->n; i++)
 
610
        {
 
611
           /* Get the record length */
 
612
           r_len = ((((int)(p[1])) << 8) + (int)(p[2]));
 
613
           tmp = WORDDATA_RoundBlockSize((3 + r_len));
 
614
           memcpy(q,p,tmp);
 
615
           p += tmp;
 
616
           q += tmp;
 
617
        }
 
618
        b->last_del_page->n--;
 
619
        b->last_del_page->used_blocks -= deleted_length / WORDDATA_BlockSize;
 
620
        if(!b->last_del_page->n)
 
621
        {
 
622
            if(b->num_Reusable_Pages < WORDDATA_MAX_REUSABLE_PAGES)
 
623
            {
 
624
                b->Reusable_Pages[b->num_Reusable_Pages].page_number = page_number;
 
625
                b->Reusable_Pages[b->num_Reusable_Pages++].page_size = WORDDATA_PageSize;
 
626
            }
 
627
            b->last_del_page = 0;
 
628
        }
 
629
        else
 
630
        {
 
631
            WORDDATA_WritePage(b,b->last_del_page);
 
632
        }
 
633
    }
 
634
    else   /* Error */
 
635
    {
 
636
        *len = 0;
 
637
    }
 
638
 
 
639
    return;
 
640
}
 
641
 
 
642
 
 
643
#ifdef DEBUG
 
644
 
 
645
#include <time.h>
 
646
 
 
647
#define N_TEST 5000
 
648
 
 
649
#ifdef _WIN32
 
650
#define FILEMODE_READ           "rb"
 
651
#define FILEMODE_WRITE          "wb"
 
652
#define FILEMODE_READWRITE      "rb+"
 
653
#elif defined(__VMS)
 
654
#define FILEMODE_READ           "rb"
 
655
#define FILEMODE_WRITE          "wb"
 
656
#define FILEMODE_READWRITE      "rb+"
 
657
#else
 
658
#define FILEMODE_READ           "r"
 
659
#define FILEMODE_WRITE          "w"
 
660
#define FILEMODE_READWRITE      "r+"
 
661
#endif
 
662
 
 
663
int main()
 
664
{
 
665
FILE *fp;
 
666
WORDDATA *bt;
 
667
int i,len;
 
668
static unsigned long nums[N_TEST];
 
669
    srand(time(NULL));
 
670
 
 
671
 
 
672
 
 
673
    fp = fopen("kkkkk",FILEMODE_WRITE);
 
674
    fclose(fp);
 
675
    fp = fopen("kkkkk",FILEMODE_READWRITE);
 
676
 
 
677
    fwrite("aaa",1,3,fp);
 
678
 
 
679
printf("\n\nIndexing\n\n");
 
680
 
 
681
    bt = WORDDATA_Open(fp);
 
682
    for(i=0;i<N_TEST;i++)
 
683
    {
 
684
        nums[i] = WORDDATA_Put(bt,16,"1234567890123456");
 
685
        if(memcmp(WORDDATA_Get(bt,nums[i],&len),"1234567890123456",16)!=0)
 
686
            printf("\n\nmal %d\n\n",i);
 
687
        if(!(i%1000))
 
688
        {
 
689
            WORDDATA_FlushCache(bt);
 
690
            printf("%d            \r",i);
 
691
        }
 
692
    }
 
693
 
 
694
    WORDDATA_Close(bt);
 
695
    fclose(fp);
 
696
 
 
697
printf("\n\nUnfreed %d\n\n",num);
 
698
printf("\n\nSearching\n\n");
 
699
 
 
700
    fp = fopen("kkkkk",FILEMODE_READ);
 
701
    bt = WORDDATA_Open(fp);
 
702
 
 
703
    for(i=0;i<N_TEST;i++)
 
704
    {
 
705
        if(memcmp(WORDDATA_Get(bt,nums[i],&len),"1234567890123456",16)!=0)
 
706
            printf("\n\nmal %d\n\n",i);
 
707
        if(!(i%1000))
 
708
            printf("%d            \r",i);
 
709
    }
 
710
 
 
711
    WORDDATA_Close(bt);
 
712
 
 
713
    fclose(fp);
 
714
printf("\n\nUnfreed %d\n\n",num);
 
715
 
 
716
}
 
717
 
 
718
#endif