2 * Copyright (c) 1995-1996, Index Data.
3 * See the file LICENSE for details.
4 * Sebastian Hammer, Adam Dickmeiss
7 * Revision 1.2 1996-10-29 16:44:56 adam
10 * Revision 1.1 1996/10/29 13:40:48 adam
23 ISAMC_M isc_getmethod (void)
25 static struct ISAMC_filecat_s def_cat[] = {
27 { 512, 490, 100, 20 },
28 { 4096, 3950, 1000, 20 },
29 {32768, 32000, 10000, 0 },
32 ISAMC_M m = xmalloc (sizeof(*m));
39 m->compare_item = NULL;
47 ISAMC isc_open (const char *name, int writeflag, ISAMC_M method)
50 ISAMC_filecat filecat;
54 is = xmalloc (sizeof(*is));
56 is->method = xmalloc (sizeof(*is->method));
57 memcpy (is->method, method, sizeof(*method));
58 filecat = is->method->filecat;
61 /* determine number of block categories */
62 if (is->method->debug)
63 logf (LOG_LOG, "isc: bsize ifill mfill mblocks");
64 for (i = 0; filecat[i].bsize; i++)
66 if (is->method->debug)
67 logf (LOG_LOG, "isc:%6d %6d %6d %6d",
68 filecat[i].bsize, filecat[i].ifill,
69 filecat[i].mfill, filecat[i].mblocks);
70 if (max_buf_size < filecat[i].mblocks * filecat[i].bsize)
71 max_buf_size = filecat[i].mblocks * filecat[i].bsize;
75 /* max_buf_size is the larget buffer to be used during merge */
76 max_buf_size = (1 + max_buf_size / filecat[i].bsize) * filecat[i].bsize;
77 if (is->method->debug)
78 logf (LOG_LOG, "isc: max_buf_size %d", max_buf_size);
80 assert (is->no_files > 0);
81 is->files = xmalloc (sizeof(*is->files)*i);
82 is->r_buf = xmalloc (max_buf_size+128);
83 for (i = 0; i<is->no_files; i++)
87 sprintf (fname, "%s%c", name, i+'A');
88 is->files[i].bf = bf_open (fname, is->method->filecat[i].bsize,
90 is->files[i].head_is_dirty = 0;
91 if (!bf_read (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
94 is->files[i].head.lastblock = 1;
95 is->files[i].head.freelist = 0;
101 int isc_close (ISAMC is)
105 for (i = 0; i<is->no_files; i++)
108 if (is->files[i].head_is_dirty)
109 bf_write (is->files[i].bf, 0, 0, sizeof(ISAMC_head),
111 bf_close (is->files[i].bf);
119 int isc_read_block (ISAMC is, int cat, int pos, char *dst)
121 if (is->method->debug > 1)
122 logf (LOG_LOG, "isc: read_block %d %d", cat, pos);
123 return bf_read (is->files[cat].bf, pos, 0, 0, dst);
126 int isc_write_block (ISAMC is, int cat, int pos, char *src)
128 if (is->method->debug > 1)
129 logf (LOG_LOG, "isc: write_block %d %d", cat, pos);
130 return bf_write (is->files[cat].bf, pos, 0, 0, src);
133 int isc_write_dblock (ISAMC is, int cat, int pos, char *src,
134 int nextpos, int offset)
136 int xoffset = offset + 2*sizeof(int);
137 if (is->method->debug > 2)
138 logf (LOG_LOG, "isc: write_dblock. offset=%d nextpos=%d",
140 memcpy (src - sizeof(int)*2, &nextpos, sizeof(int));
141 memcpy (src - sizeof(int), &xoffset, sizeof(int));
142 return isc_write_block (is, cat, pos, src - sizeof(int)*2);
145 int isc_alloc_block (ISAMC is, int cat)
148 char buf[sizeof(int)];
150 is->files[cat].head_is_dirty = 1;
151 if ((block = is->files[cat].head.freelist))
153 bf_read (is->files[cat].bf, block, 0, sizeof(int), buf);
154 memcpy (&is->files[cat].head.freelist, buf, sizeof(int));
157 block = (is->files[cat].head.lastblock)++;
158 if (is->method->debug > 2)
159 logf (LOG_LOG, "isc: alloc_block in cat %d -> %d", cat, block);
163 void isc_release_block (ISAMC is, int cat, int pos)
165 char buf[sizeof(int)];
167 is->files[cat].head_is_dirty = 1;
168 memcpy (buf, &is->files[cat].head.freelist, sizeof(int));
169 is->files[cat].head.freelist = pos;
170 bf_write (is->files[cat].bf, pos, 0, sizeof(int), buf);
173 static void isc_flush_blocks (ISAMC is, int *r_ptr, int r_ptri, char *r_buf,
174 int *nextpos, int *firstpos, int cat, int last)
178 for (i = 1; i<r_ptri; i++)
184 pos = isc_alloc_block (is, cat);
187 if (last && i == r_ptri-1)
190 *nextpos = isc_alloc_block (is, cat);
191 isc_write_dblock (is, cat, pos, r_buf + r_ptr[i-1], *nextpos,
192 r_ptr[i] - r_ptr[i-1]);
197 ISAMC_P isc_merge_first (ISAMC is, ISAMC_I data)
199 char i_item[128], *i_item_ptr;
200 int i_more, i_mode, i;
205 char r_item_buf[128];
209 void *r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
210 char *r_buf = is->r_buf + ISAMC_BLOCK_OFFSET;
212 /* read first item from i */
214 i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
219 char *r_item = r_item_buf;
221 memcpy (r_item, i_item, i_item_ptr - i_item);
223 if (r_item) /* insert resulting item? */
225 char *r_out_ptr = r_buf + r_offset;
227 int border = r_ptr[r_ptri-1] + is->method->filecat[cat].ifill
230 (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
231 &r_out_ptr, &r_item);
232 new_offset = r_out_ptr - r_buf;
234 if (border >= r_offset && border < new_offset)
236 /* Initial fill of current block category reached...
239 r_ptr[r_ptri++] = r_offset;
240 if (cat == is->max_cat)
242 /* We are dealing with block of max size. Block(s)
243 will be flushed. Note: the block(s) are surely not
246 if (is->method->debug > 1)
247 logf (LOG_LOG, "isc: flush %d sections", r_ptri-1);
248 isc_flush_blocks (is, r_ptr, r_ptri, r_buf,
249 &nextpos, &firstpos, cat, 0);
252 memcpy (r_buf, r_buf + r_offset, new_offset - r_offset);
253 new_offset = (new_offset - r_offset);
256 r_offset = new_offset;
257 if (cat < is->max_cat &&
258 r_ptri>is->method->filecat[cat].mblocks)
260 /* Max number blocks in current category reached ->
261 must switch to next category (with larger block size)
265 /* r_ptr[0] = r_ptr[0] = 0 true anyway.. */
266 for (i = 2; i < r_ptri; i++)
268 border = is->method->filecat[cat].ifill -
269 ISAMC_BLOCK_OFFSET + r_ptr[j-1];
270 if (r_ptr[i] > border && r_ptr[i-1] <= border)
271 r_ptr[j++] = r_ptr[i-1];
277 i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
279 r_ptr[r_ptri++] = r_offset;
280 /* flush rest of block(s) in r_buf */
281 if (is->method->debug > 1)
282 logf (LOG_LOG, "isc: flush rest, %d sections", r_ptri-1);
283 isc_flush_blocks (is, r_ptr, r_ptri, r_buf, &nextpos, &firstpos, cat, 1);
284 (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
285 return cat + firstpos * 8;
288 ISAMC_P isc_merge (ISAMC is, ISAMC_P ipos, ISAMC_I data)
290 char i_item[128], *i_item_ptr;
291 int i_more, i_mode, i;
294 char f_item[128], *f_item_ptr;
296 int block_ptr[100]; /* block pointer (0 if none) */
297 int dirty_ptr[100]; /* dirty flag pointer (1 if dirty) */
302 char r_item_buf[128]; /* temporary result output */
303 char *r_buf; /* block with resulting data */
304 int r_offset = 0; /* current offset in r_buf */
305 int r_ptr[100]; /* offset pointer */
306 int r_ptri = 0; /* pointer */
307 void *r_clientData; /* encode client data */
310 return isc_merge_first (is, data);
312 r_clientData = (*is->method->code_start)(ISAMC_ENCODE);
313 r_buf = is->r_buf + ISAMC_BLOCK_OFFSET;
315 pp = isc_pp_open (is, ipos);
317 f_more = isc_read_item (pp, &f_item_ptr);
320 /* read first item from i */
322 i_more = (*data->read_item)(data->clientData, &i_item_ptr, &i_mode);
323 block_ptr[r_ptri] = pp->pos;
324 dirty_ptr[r_ptri] = 0;
327 while (i_more || f_more)
329 char *r_item = r_item_buf;
337 cmp = (*is->method->compare_item)(i_item, f_item);
338 if (cmp == 0) /* insert i=f */
343 dirty_ptr[r_ptri-1] = 1;
346 memcpy (r_item, f_item, f_item_ptr - f_item);
350 i_more = (*data->read_item)(data->clientData, &i_item_ptr,
354 f_more = isc_read_item (pp, &f_item_ptr);
356 else if (cmp > 0) /* insert f */
358 memcpy (r_item, f_item, f_item_ptr - f_item);
361 f_more = isc_read_item (pp, &f_item_ptr);
365 if (!i_mode) /* delete item which isn't there? */
367 logf (LOG_FATAL, "Inconsistent register");
370 memcpy (r_item, i_item, i_item_ptr - i_item);
371 dirty_ptr[r_ptri-1] = 1;
374 i_more = (*data->read_item)(data->clientData, &i_item_ptr,
377 if (r_item) /* insert resulting item? */
379 char *r_out_ptr = r_buf + r_offset;
383 /* border set to initial fill or block size depending on
384 whether we are creating a new one or updating and old
386 if (block_ptr[r_ptri-1])
387 border = r_ptr[r_ptri-1] + is->method->filecat[cat].bsize
390 border = r_ptr[r_ptri-1] + is->method->filecat[cat].ifill
393 (*is->method->code_item)(ISAMC_ENCODE, r_clientData,
394 &r_out_ptr, &r_item);
395 new_offset = r_out_ptr - r_buf;
397 if (border >= r_offset && border < new_offset)
399 /* Initial fill of current block category reached...
402 r_ptr[r_ptri++] = r_offset;
403 if (cat == is->max_cat)
405 /* We are dealing with block of max size. Block(s)
406 will be flushed. Note: the block(s) are surely not
409 if (is->method->debug > 1)
410 logf (LOG_LOG, "isc: flush %d sections", r_ptri-1);
411 isc_flush_blocks (is, r_ptr, r_ptri, r_buf,
412 &nextpos, &firstpos, cat, 0);
415 memcpy (r_buf, r_buf + r_offset, new_offset - r_offset);
416 new_offset = (new_offset - r_offset);
419 r_offset = new_offset;
420 if (cat < is->max_cat &&
421 r_ptri>is->method->filecat[cat].mblocks)
423 /* Max number blocks in current category reached ->
424 must switch to next category (with larger block size)
428 /* r_ptr[0] = r_ptr[0] = 0 true anyway.. */
429 /* AD: Any old blocks should be deleted */
430 for (i = 2; i < r_ptri; i++)
432 border = is->method->filecat[cat].ifill -
433 ISAMC_BLOCK_OFFSET + r_ptr[j-1];
434 if (r_ptr[i] > border && r_ptr[i-1] <= border)
435 r_ptr[j++] = r_ptr[i-1];
441 r_ptr[r_ptri++] = r_offset;
442 /* flush rest of block(s) in r_buf */
443 if (is->method->debug > 1)
444 logf (LOG_LOG, "isc: flush rest, %d sections", r_ptri-1);
445 isc_flush_blocks (is, r_ptr, r_ptri, r_buf, &nextpos, &firstpos, cat, 1);
446 (*is->method->code_stop)(ISAMC_ENCODE, r_clientData);
447 return cat + firstpos * 8;
452 ISAMC_P isc_merge (ISAMC is, ISAMC_P ipos, ISAMC_I data)
455 char f_item[128], *f_item_ptr;
460 char i_item[128], *i_item_ptr;
461 int i_more, insertMode;
463 char r_item_buf[128];
464 int r_offset = ISAMC_BLOCK_OFFSET;
469 void *r_clientData = (*is->method->code_start)();
471 /* rewind and read first item from file */
472 pp = isc_position (is, ipos);
474 f_more = isc_read_item (pp, &f_item_ptr);
477 /* read first item from i */
479 i_more = (*data->read_item)(data->clientData, &i_item_ptr, &insertMode);
481 while (f_more || i_more)
484 char *r_item = r_item_buf;
491 cmp = (*is->method->compare_item)(i_item, f_item);
492 if (cmp == 0) /* insert i=f */
500 memcpy (r_item, f_item, f_item_ptr - f_item);
504 i_more = (*data->read_item)(data->clientData, &i_item_ptr,
508 f_more = isc_read_item (pp, &f_item_ptr);
510 else if (cmp > 0) /* insert f */
512 memcpy (r_item, f_item, f_item_ptr - f_item);
515 f_more = isc_read_item (pp, &f_item_ptr);
519 if (!insertMode) /* delete item which isn't there? */
521 logf (LOG_FATAL, "Inconsistent register");
524 memcpy (r_item, i_item, i_item_ptr - i_item);
528 i_more = (*data->read_item)(data->clientData, &i_item_ptr,
531 /* check for end of input block condition */
533 if (r_item) /* insert resulting item? */
535 char *r_out_ptr = is->r_buf + r_offset;
537 int border = is->method->filecat[cat].initsize - r_start;
539 (*is->method->code_item)(r_clientData, &r_out_ptr, &r_item);
540 new_offset = r_out_ptr - is->r_buf;
542 if (border >= r_offset && border < r_newoffset)
544 r_ptr[r_ptri++] = r_offset;
545 if (!is->method->filecat[cat].mblocks)
547 assert (r_ptri == 1);
548 /* dump block from 0 -> r_offset in max cat */
550 r_offset = ISAMC_BLOCK_OFFSET;
553 r_offset = new_offset;
555 if (r_ptri && r_ptri == is->method->filecat[cat].mblocks)
559 /* dump previous blocks in chain */
563 for (i = 1; i<r_ptr; i++)
565 if (r_ptr[i] > is->method->filecat[cat].ifill &&
566 r_ptr[i-1] <= is->method->filecat[cat].ifill)
567 r_ptr[j++] = r_ptr[i-1];
572 (*is->method->code_stop)(r_clientData);
577 void isc_pp_close (ISAMC_PP pp)
581 (*is->method->code_stop)(ISAMC_DECODE, pp->decodeClientData);
586 ISAMC_PP isc_pp_open (ISAMC is, ISAMC_P ipos)
588 ISAMC_PP pp = xmalloc (sizeof(*pp));
591 pp->cat = isc_type(ipos);
592 pp->next = isc_block(ipos);
594 src = pp->buf = xmalloc (is->method->filecat[pp->cat].bsize);
600 pp->decodeClientData = (*is->method->code_start)(ISAMC_DECODE);
604 /* returns 1 if item could be read; 0 otherwise */
605 int isc_read_key (ISAMC_PP pp, void *buf)
607 return isc_read_item (pp, (char **) &buf);
610 /* returns 1 if item could be read; 0 otherwise */
611 int isc_read_item (ISAMC_PP pp, char **dst)
614 char *src = pp->buf + pp->offset;
616 if (pp->offset >= pp->size)
622 isc_read_block (is, pp->cat, pp->pos, src);
624 memcpy (&pp->next, src, sizeof(pp->next));
625 src += sizeof(pp->next);
626 memcpy (&pp->size, src, sizeof(pp->size));
627 src += sizeof(pp->size);
628 /* assume block is non-empty */
629 assert (pp->next != pp->pos);
631 (*is->method->code_item)(ISAMC_DECODE, pp->decodeClientData, dst, &src);
632 pp->offset = src - pp->buf;
636 int isc_read_islast (ISAMC_PP pp)
638 return pp->offset >= pp->size;
641 int isc_numkeys (ISAMC_PP pp)