1 /* $Id: isamb.c,v 1.75 2005-03-21 17:20:54 adam Exp $
2 Copyright (C) 1995-2005
5 This file is part of the Zebra server.
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
26 #include <yaz/xmalloc.h>
27 #include <idzebra/isamb.h>
35 #define ISAMB_MAJOR_VERSION 3
36 #define ISAMB_MINOR_VERSION 0
48 /* if 1, upper nodes items are encoded; 0 if not encoded */
51 /* maximum size of encoded buffer */
52 #define DST_ITEM_MAX 256
54 #define ISAMB_MAX_LEVEL 10
55 /* approx 2*max page + max size of item */
56 #define DST_BUF_SIZE 16840
58 #define ISAMB_CACHE_ENTRY_SIZE 4096
60 /* CAT_MAX: _must_ be power of 2 */
62 #define CAT_MASK (CAT_MAX-1)
63 /* CAT_NO: <= CAT_MAX */
66 /* Smallest block size */
67 #define ISAMB_MIN_SIZE 32
69 #define ISAMB_FAC_SIZE 4
71 /* ISAMB_PTR_CODEC = 1 var, =0 fixed */
72 #define ISAMB_PTR_CODEC 1
74 struct ISAMB_cache_entry {
79 struct ISAMB_cache_entry *next;
85 struct ISAMB_head head;
86 struct ISAMB_cache_entry *cache_entries;
93 struct ISAMB_file *file;
95 int cache; /* 0 = no cache, 1 = use cache, -1 = dummy isam (for testing only) */
96 int log_io; /* log level for bf_read/bf_write calls */
97 int log_freelist; /* log level for freelist handling */
98 zint skipped_numbers; /* on a leaf node */
99 zint returned_numbers;
100 zint skipped_nodes[ISAMB_MAX_LEVEL]; /* [0]=skipped leaves, 1 = higher etc */
101 zint accessed_nodes[ISAMB_MAX_LEVEL]; /* nodes we did not skip */
112 zint no_items; /* number of nodes in this + children */
116 void *decodeClientData;
124 int maxlevel; /* total depth */
127 zint skipped_numbers; /* on a leaf node */
128 zint returned_numbers;
129 zint skipped_nodes[ISAMB_MAX_LEVEL]; /* [0]=skipped leaves, 1 = higher etc */
130 zint accessed_nodes[ISAMB_MAX_LEVEL]; /* nodes we did not skip */
131 struct ISAMB_block **block;
132 int scope; /* on what level we forward */
136 #define encode_item_len encode_ptr
138 static void encode_ptr(char **dst, zint pos)
140 unsigned char *bp = (unsigned char*) *dst;
144 *bp++ = (unsigned char) (128 | (pos & 127));
147 *bp++ = (unsigned char) pos;
151 static void encode_ptr(char **dst, zint pos)
153 memcpy(*dst, &pos, sizeof(pos));
154 (*dst) += sizeof(pos);
158 #define decode_item_len decode_ptr
160 static void decode_ptr(const char **src1, zint *pos)
162 const unsigned char **src = (const unsigned char **) src1;
167 while (((c = *(*src)++) & 128))
169 d += ((zint) (c & 127) << r);
172 d += ((zint) c << r);
176 static void decode_ptr(const char **src, zint *pos)
178 memcpy(pos, *src, sizeof(*pos));
179 (*src) += sizeof(*pos);
183 ISAMB isamb_open(BFiles bfs, const char *name, int writeflag, ISAMC_M *method,
186 ISAMB isamb = xmalloc(sizeof(*isamb));
187 int i, b_size = ISAMB_MIN_SIZE;
190 isamb->method = (ISAMC_M *) xmalloc(sizeof(*method));
191 memcpy(isamb->method, method, sizeof(*method));
192 isamb->no_cat = CAT_NO;
194 isamb->log_freelist = 0;
195 isamb->cache = cache;
196 isamb->skipped_numbers = 0;
197 isamb->returned_numbers = 0;
198 for (i = 0; i<ISAMB_MAX_LEVEL; i++)
199 isamb->skipped_nodes[i] = isamb->accessed_nodes[i] = 0;
202 isamb->file = xmalloc(sizeof(*isamb->file) * isamb->no_cat);
203 for (i = 0; i < isamb->no_cat; i++)
205 char fname[DST_BUF_SIZE];
206 char hbuf[DST_BUF_SIZE];
207 isamb->file[i].cache_entries = 0;
208 isamb->file[i].head_dirty = 0;
209 sprintf(fname, "%s%c", name, i+'A');
211 isamb->file[i].bf = bf_open(bfs, fname, ISAMB_CACHE_ENTRY_SIZE,
214 isamb->file[i].bf = bf_open(bfs, fname, b_size, writeflag);
216 /* fill-in default values (for empty isamb) */
217 isamb->file[i].head.first_block = ISAMB_CACHE_ENTRY_SIZE/b_size+1;
218 isamb->file[i].head.last_block = isamb->file[i].head.first_block;
219 isamb->file[i].head.block_size = b_size;
221 if (i == isamb->no_cat-1 || b_size > 128)
222 isamb->file[i].head.block_offset = 8;
224 isamb->file[i].head.block_offset = 4;
226 isamb->file[i].head.block_offset = 11;
228 isamb->file[i].head.block_max =
229 b_size - isamb->file[i].head.block_offset;
230 isamb->file[i].head.free_list = 0;
231 if (bf_read(isamb->file[i].bf, 0, 0, 0, hbuf))
233 /* got header assume "isamb"major minor len can fit in 16 bytes */
235 int major, minor, len, pos = 0;
238 if (memcmp(hbuf, "isamb", 5))
240 yaz_log(YLOG_WARN, "bad isamb header for file %s", fname);
243 if (sscanf(hbuf+5, "%d %d %d", &major, &minor, &len) != 3)
245 yaz_log(YLOG_WARN, "bad isamb header for file %s", fname);
248 if (major != ISAMB_MAJOR_VERSION)
250 yaz_log(YLOG_WARN, "bad major version for file %s %d, must be %d",
251 fname, major, ISAMB_MAJOR_VERSION);
254 for (left = len - b_size; left > 0; left = left - b_size)
257 if (!bf_read(isamb->file[i].bf, pos, 0, 0, hbuf + pos*b_size))
259 yaz_log(YLOG_WARN, "truncated isamb header for "
260 "file=%s len=%d pos=%d",
266 decode_ptr(&src, &isamb->file[i].head.first_block);
267 decode_ptr(&src, &isamb->file[i].head.last_block);
268 decode_ptr(&src, &zint_tmp);
269 isamb->file[i].head.block_size = (int) zint_tmp;
270 decode_ptr(&src, &zint_tmp);
271 isamb->file[i].head.block_max = (int) zint_tmp;
272 decode_ptr(&src, &isamb->file[i].head.free_list);
274 assert (isamb->file[i].head.block_size >= isamb->file[i].head.block_offset);
275 isamb->file[i].head_dirty = 0;
276 assert(isamb->file[i].head.block_size == b_size);
277 b_size = b_size * ISAMB_FAC_SIZE;
280 yaz_log(YLOG_WARN, "isamb debug enabled. Things will be slower than usual");
285 static void flush_blocks (ISAMB b, int cat)
287 while (b->file[cat].cache_entries)
289 struct ISAMB_cache_entry *ce_this = b->file[cat].cache_entries;
290 b->file[cat].cache_entries = ce_this->next;
294 yaz_log(b->log_io, "bf_write: flush_blocks");
295 bf_write(b->file[cat].bf, ce_this->pos, 0, 0, ce_this->buf);
302 static int cache_block (ISAMB b, ISAMC_P pos, char *userbuf, int wr)
304 int cat = (int) (pos&CAT_MASK);
305 int off = (int) (((pos/CAT_MAX) &
306 (ISAMB_CACHE_ENTRY_SIZE / b->file[cat].head.block_size - 1))
307 * b->file[cat].head.block_size);
308 zint norm = pos / (CAT_MASK*ISAMB_CACHE_ENTRY_SIZE / b->file[cat].head.block_size);
310 struct ISAMB_cache_entry **ce, *ce_this = 0, **ce_last = 0;
315 assert (ISAMB_CACHE_ENTRY_SIZE >= b->file[cat].head.block_size);
316 for (ce = &b->file[cat].cache_entries; *ce; ce = &(*ce)->next, no++)
319 if ((*ce)->pos == norm)
322 *ce = (*ce)->next; /* remove from list */
324 ce_this->next = b->file[cat].cache_entries; /* move to front */
325 b->file[cat].cache_entries = ce_this;
329 memcpy (ce_this->buf + off, userbuf,
330 b->file[cat].head.block_size);
334 memcpy (userbuf, ce_this->buf + off,
335 b->file[cat].head.block_size);
342 assert (ce_last && *ce_last);
344 *ce_last = 0; /* remove the last entry from list */
347 yaz_log(b->log_io, "bf_write: cache_block");
348 bf_write(b->file[cat].bf, ce_this->pos, 0, 0, ce_this->buf);
353 ce_this = xmalloc(sizeof(*ce_this));
354 ce_this->next = b->file[cat].cache_entries;
355 b->file[cat].cache_entries = ce_this;
356 ce_this->buf = xmalloc(ISAMB_CACHE_ENTRY_SIZE);
358 yaz_log(b->log_io, "bf_read: cache_block");
359 if (!bf_read(b->file[cat].bf, norm, 0, 0, ce_this->buf))
360 memset (ce_this->buf, 0, ISAMB_CACHE_ENTRY_SIZE);
363 memcpy (ce_this->buf + off, userbuf, b->file[cat].head.block_size);
369 memcpy (userbuf, ce_this->buf + off, b->file[cat].head.block_size);
375 void isamb_close (ISAMB isamb)
378 for (i = 0; isamb->accessed_nodes[i]; i++)
379 yaz_log(YLOG_DEBUG, "isamb_close level leaf-%d: "ZINT_FORMAT" read, "
380 ZINT_FORMAT" skipped",
381 i, isamb->accessed_nodes[i], isamb->skipped_nodes[i]);
382 yaz_log(YLOG_DEBUG, "isamb_close returned "ZINT_FORMAT" values, "
383 "skipped "ZINT_FORMAT,
384 isamb->skipped_numbers, isamb->returned_numbers);
385 for (i = 0; i<isamb->no_cat; i++)
387 flush_blocks (isamb, i);
388 if (isamb->file[i].head_dirty)
390 char hbuf[DST_BUF_SIZE];
391 int major = ISAMB_MAJOR_VERSION;
392 int minor = ISAMB_MINOR_VERSION;
394 char *dst = hbuf + 16;
396 int b_size = isamb->file[i].head.block_size;
398 encode_ptr(&dst, isamb->file[i].head.first_block);
399 encode_ptr(&dst, isamb->file[i].head.last_block);
400 encode_ptr(&dst, isamb->file[i].head.block_size);
401 encode_ptr(&dst, isamb->file[i].head.block_max);
402 encode_ptr(&dst, isamb->file[i].head.free_list);
403 memset(dst, '\0', b_size); /* ensure no random bytes are written */
407 /* print exactly 16 bytes (including trailing 0) */
408 sprintf(hbuf, "isamb%02d %02d %02d\r\n", major, minor, len);
410 bf_write(isamb->file[i].bf, pos, 0, 0, hbuf);
412 for (left = len - b_size; left > 0; left = left - b_size)
415 bf_write(isamb->file[i].bf, pos, 0, 0, hbuf + pos*b_size);
418 bf_close (isamb->file[i].bf);
421 xfree(isamb->method);
425 /* open_block: read one block at pos.
426 Decode leading sys bytes .. consisting of
428 0: leader byte, != 0 leaf, == 0, non-leaf
429 1-2: used size of block
430 3-7*: number of items and all children
432 * Reserve 5 bytes for large block sizes. 1 for small ones .. Number
433 of items. We can thus have at most 2^40 nodes.
435 static struct ISAMB_block *open_block(ISAMB b, ISAMC_P pos)
437 int cat = (int) (pos&CAT_MASK);
439 int offset = b->file[cat].head.block_offset;
440 struct ISAMB_block *p;
443 p = xmalloc(sizeof(*p));
445 p->cat = (int) (pos & CAT_MASK);
446 p->buf = xmalloc(b->file[cat].head.block_size);
449 if (!cache_block (b, pos, p->buf, 0))
451 yaz_log(b->log_io, "bf_read: open_block");
452 if (!bf_read(b->file[cat].bf, pos/CAT_MAX, 0, 0, p->buf))
454 yaz_log(YLOG_FATAL, "isamb: read fail for pos=%ld block=%ld",
455 (long) pos, (long) pos/CAT_MAX);
459 p->bytes = p->buf + offset;
461 p->size = (p->buf[1] + 256 * p->buf[2]) - offset;
464 yaz_log(YLOG_FATAL, "Bad block size %d in pos=" ZINT_FORMAT "\n",
467 assert (p->size >= 0);
469 decode_ptr(&src, &p->no_items);
474 p->decodeClientData = (*b->method->codec.start)();
478 struct ISAMB_block *new_block (ISAMB b, int leaf, int cat)
480 struct ISAMB_block *p;
482 p = xmalloc(sizeof(*p));
483 p->buf = xmalloc(b->file[cat].head.block_size);
485 if (!b->file[cat].head.free_list)
488 block_no = b->file[cat].head.last_block++;
489 p->pos = block_no * CAT_MAX + cat;
493 p->pos = b->file[cat].head.free_list;
494 assert((p->pos & CAT_MASK) == cat);
495 if (!cache_block (b, p->pos, p->buf, 0))
497 yaz_log(b->log_io, "bf_read: new_block");
498 if (!bf_read(b->file[cat].bf, p->pos/CAT_MAX, 0, 0, p->buf))
500 yaz_log(YLOG_FATAL, "isamb: read fail for pos=%ld block=%ld",
501 (long) p->pos/CAT_MAX, (long) p->pos/CAT_MAX);
505 yaz_log(b->log_freelist, "got block " ZINT_FORMAT " from freelist %d:" ZINT_FORMAT, p->pos,
506 cat, p->pos/CAT_MAX);
507 memcpy (&b->file[cat].head.free_list, p->buf, sizeof(zint));
510 b->file[cat].head_dirty = 1;
511 memset (p->buf, 0, b->file[cat].head.block_size);
512 p->bytes = p->buf + b->file[cat].head.block_offset;
519 p->decodeClientData = (*b->method->codec.start)();
523 struct ISAMB_block *new_leaf (ISAMB b, int cat)
525 return new_block (b, 1, cat);
529 struct ISAMB_block *new_int (ISAMB b, int cat)
531 return new_block (b, 0, cat);
534 static void check_block (ISAMB b, struct ISAMB_block *p)
536 assert(b); /* mostly to make the compiler shut up about unused b */
544 char *startp = p->bytes;
545 const char *src = startp;
546 char *endp = p->bytes + p->size;
548 void *c1 = (*b->method->codec.start)();
550 decode_ptr(&src, &pos);
551 assert ((pos&CAT_MASK) == p->cat);
555 char file_item_buf[DST_ITEM_MAX];
556 char *file_item = file_item_buf;
557 (*b->method->codec.reset)(c1);
558 (*b->method->codec.decode)(c1, &file_item, &src);
561 decode_item_len(&src, &item_len);
562 assert (item_len > 0 && item_len < 80);
565 decode_ptr(&src, &pos);
566 if ((pos&CAT_MASK) != p->cat)
568 assert ((pos&CAT_MASK) == p->cat);
571 (*b->method->codec.stop)(c1);
575 void close_block(ISAMB b, struct ISAMB_block *p)
581 yaz_log(b->log_freelist, "release block " ZINT_FORMAT " from freelist %d:" ZINT_FORMAT,
582 p->pos, p->cat, p->pos/CAT_MAX);
583 memcpy (p->buf, &b->file[p->cat].head.free_list, sizeof(zint));
584 b->file[p->cat].head.free_list = p->pos;
585 if (!cache_block (b, p->pos, p->buf, 1))
587 yaz_log(b->log_io, "bf_write: close_block (deleted)");
588 bf_write(b->file[p->cat].bf, p->pos/CAT_MAX, 0, 0, p->buf);
593 int offset = b->file[p->cat].head.block_offset;
594 int size = p->size + offset;
595 char *dst = p->buf + 3;
596 assert (p->size >= 0);
598 /* memset becuase encode_ptr usually does not write all bytes */
599 memset(p->buf, 0, b->file[p->cat].head.block_offset);
601 p->buf[1] = size & 255;
602 p->buf[2] = size >> 8;
603 encode_ptr(&dst, p->no_items);
605 if (!cache_block (b, p->pos, p->buf, 1))
607 yaz_log(b->log_io, "bf_write: close_block");
608 bf_write(b->file[p->cat].bf, p->pos/CAT_MAX, 0, 0, p->buf);
611 (*b->method->codec.stop)(p->decodeClientData);
616 int insert_sub (ISAMB b, struct ISAMB_block **p,
617 void *new_item, int *mode,
619 struct ISAMB_block **sp,
620 void *sub_item, int *sub_size,
621 const void *max_item);
623 int insert_int (ISAMB b, struct ISAMB_block *p, void *lookahead_item,
625 ISAMC_I *stream, struct ISAMB_block **sp,
626 void *split_item, int *split_size, const void *last_max_item)
628 char *startp = p->bytes;
629 const char *src = startp;
630 char *endp = p->bytes + p->size;
632 struct ISAMB_block *sub_p1 = 0, *sub_p2 = 0;
633 char sub_item[DST_ITEM_MAX];
637 void *c1 = (*b->method->codec.start)();
641 assert(p->size >= 0);
642 decode_ptr(&src, &pos);
646 const char *src0 = src;
648 char file_item_buf[DST_ITEM_MAX];
649 char *file_item = file_item_buf;
650 (*b->method->codec.reset)(c1);
651 (*b->method->codec.decode)(c1, &file_item, &src);
652 d = (*b->method->compare_item)(file_item_buf, lookahead_item);
655 sub_p1 = open_block(b, pos);
657 diff_terms -= sub_p1->no_items;
658 more = insert_sub (b, &sub_p1, lookahead_item, mode,
660 sub_item, &sub_size, file_item_buf);
661 diff_terms += sub_p1->no_items;
667 decode_item_len(&src, &item_len);
668 d = (*b->method->compare_item)(src, lookahead_item);
671 sub_p1 = open_block(b, pos);
673 diff_terms -= sub_p1->no_items;
674 more = insert_sub (b, &sub_p1, lookahead_item, mode,
676 sub_item, &sub_size, src);
677 diff_terms += sub_p1->no_items;
683 decode_ptr(&src, &pos);
687 /* we reached the end. So lookahead > last item */
688 sub_p1 = open_block(b, pos);
690 diff_terms -= sub_p1->no_items;
691 more = insert_sub (b, &sub_p1, lookahead_item, mode, stream, &sub_p2,
692 sub_item, &sub_size, last_max_item);
693 diff_terms += sub_p1->no_items;
696 diff_terms += sub_p2->no_items;
700 p->no_items += diff_terms;
704 /* there was a split - must insert pointer in this one */
705 char dst_buf[DST_BUF_SIZE];
708 const char *sub_item_ptr = sub_item;
710 assert (sub_size < 80 && sub_size > 1);
712 memcpy (dst, startp, src - startp);
717 (*b->method->codec.reset)(c1);
718 (*b->method->codec.encode)(c1, &dst, &sub_item_ptr);
720 encode_item_len (&dst, sub_size); /* sub length and item */
721 memcpy (dst, sub_item, sub_size);
725 encode_ptr(&dst, sub_p2->pos); /* pos */
727 if (endp - src) /* remaining data */
729 memcpy (dst, src, endp - src);
732 p->size = dst - dst_buf;
733 assert (p->size >= 0);
736 if (p->size <= b->file[p->cat].head.block_max)
738 /* it fits OK in this block */
739 memcpy (startp, dst_buf, dst - dst_buf);
743 /* must split _this_ block as well .. */
744 struct ISAMB_block *sub_p3;
746 char file_item_buf[DST_ITEM_MAX];
747 char *file_item = file_item_buf;
751 zint no_items_first_half = 0;
757 half = src + b->file[p->cat].head.block_size/2;
758 decode_ptr(&src, &pos);
760 /* read sub block so we can get no_items for it */
761 sub_p3 = open_block(b, pos);
762 no_items_first_half += sub_p3->no_items;
763 close_block(b, sub_p3);
768 file_item = file_item_buf;
769 (*b->method->codec.reset)(c1);
770 (*b->method->codec.decode)(c1, &file_item, &src);
772 decode_item_len(&src, &split_size_tmp);
773 *split_size = (int) split_size_tmp;
776 decode_ptr(&src, &pos);
778 /* read sub block so we can get no_items for it */
779 sub_p3 = open_block(b, pos);
780 no_items_first_half += sub_p3->no_items;
781 close_block(b, sub_p3);
783 /* p is first half */
784 p_new_size = src - dst_buf;
785 memcpy (p->bytes, dst_buf, p_new_size);
788 file_item = file_item_buf;
789 (*b->method->codec.reset)(c1);
790 (*b->method->codec.decode)(c1, &file_item, &src);
791 *split_size = file_item - file_item_buf;
792 memcpy(split_item, file_item_buf, *split_size);
794 decode_item_len(&src, &split_size_tmp);
795 *split_size = (int) split_size_tmp;
796 memcpy (split_item, src, *split_size);
799 /* *sp is second half */
800 *sp = new_int (b, p->cat);
801 (*sp)->size = endp - src;
802 memcpy ((*sp)->bytes, src, (*sp)->size);
804 p->size = p_new_size;
806 /* adjust no_items in first&second half */
807 (*sp)->no_items = p->no_items - no_items_first_half;
808 p->no_items = no_items_first_half;
811 close_block(b, sub_p2);
813 close_block(b, sub_p1);
814 (*b->method->codec.stop)(c1);
818 int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
819 int *lookahead_mode, ISAMC_I *stream,
820 struct ISAMB_block **sp2,
821 void *sub_item, int *sub_size,
822 const void *max_item)
824 struct ISAMB_block *p = *sp1;
827 char dst_buf[DST_BUF_SIZE], *dst = dst_buf;
829 void *c1 = (*b->method->codec.start)();
830 void *c2 = (*b->method->codec.start)();
832 int quater = b->file[b->no_cat-1].head.block_max / 4;
833 char *mid_cut = dst_buf + quater * 2;
834 char *tail_cut = dst_buf + quater * 3;
835 char *maxp = dst_buf + b->file[b->no_cat-1].head.block_max;
838 char cut_item_buf[DST_ITEM_MAX];
839 int cut_item_size = 0;
840 int no_items = 0; /* number of items (total) */
841 int no_items_1 = 0; /* number of items (first half) */
842 int inserted_dst_bytes = 0;
846 char file_item_buf[DST_ITEM_MAX];
847 char *file_item = file_item_buf;
850 endp = p->bytes + p->size;
851 (*b->method->codec.decode)(c1, &file_item, &src);
854 const char *dst_item = 0; /* resulting item to be inserted */
855 char *lookahead_next;
860 d = (*b->method->compare_item)(file_item_buf, lookahead_item);
862 /* d now holds comparison between existing file item and
865 d > 0: lookahead before file
866 d < 0: lookahead after file
870 /* lookahead must be inserted */
871 dst_item = lookahead_item;
872 /* if this is not an insertion, it's really bad .. */
873 if (!*lookahead_mode)
875 yaz_log(YLOG_WARN, "isamb: Inconsistent register (1)");
876 assert (*lookahead_mode);
880 dst_item = file_item_buf;
882 if (!*lookahead_mode && d == 0)
884 /* it's a deletion and they match so there is nothing to be
885 inserted anyway .. But mark the thing bad (file item
886 was part of input.. The item will not be part of output */
889 else if (!half1 && dst > mid_cut)
891 /* we have reached the splitting point for the first time */
892 const char *dst_item_0 = dst_item;
893 half1 = dst; /* candidate for splitting */
895 /* encode the resulting item */
896 (*b->method->codec.encode)(c2, &dst, &dst_item);
898 cut_item_size = dst_item - dst_item_0;
899 assert(cut_item_size > 0);
900 memcpy (cut_item_buf, dst_item_0, cut_item_size);
903 no_items_1 = no_items;
908 /* encode the resulting item */
909 (*b->method->codec.encode)(c2, &dst, &dst_item);
913 /* now move "pointers" .. result has been encoded .. */
916 /* we must move the lookahead pointer */
918 inserted_dst_bytes += (dst - dst_0);
919 if (inserted_dst_bytes >= quater)
920 /* no more room. Mark lookahead as "gone".. */
924 /* move it really.. */
925 lookahead_next = lookahead_item;
926 if (!(*stream->read_item)(stream->clientData,
930 /* end of stream reached: no "more" and no lookahead */
934 if (lookahead_item && max_item &&
935 (*b->method->compare_item)(max_item, lookahead_item) <= 0)
937 /* the lookahead goes beyond what we allow in this
938 leaf. Mark it as "gone" */
947 /* exact match .. move both pointers */
949 lookahead_next = lookahead_item;
950 if (!(*stream->read_item)(stream->clientData,
951 &lookahead_next, lookahead_mode))
957 break; /* end of file stream reached .. */
958 file_item = file_item_buf; /* move file pointer */
959 (*b->method->codec.decode)(c1, &file_item, &src);
963 /* file pointer must be moved */
966 file_item = file_item_buf;
967 (*b->method->codec.decode)(c1, &file_item, &src);
972 /* this loop runs when we are "appending" to a leaf page. That is
973 either it's empty (new) or all file items have been read in
976 maxp = dst_buf + b->file[b->no_cat-1].head.block_max + quater;
977 while (lookahead_item)
980 const char *src = lookahead_item;
983 /* if we have a lookahead item, we stop if we exceed the value of it */
985 (*b->method->compare_item)(max_item, lookahead_item) <= 0)
987 /* stop if we have reached the value of max item */
990 if (!*lookahead_mode)
992 /* this is append. So a delete is bad */
993 yaz_log(YLOG_WARN, "isamb: Inconsistent register (2)");
996 else if (!half1 && dst > tail_cut)
998 const char *src_0 = src;
999 half1 = dst; /* candidate for splitting */
1001 (*b->method->codec.encode)(c2, &dst, &src);
1003 cut_item_size = src - src_0;
1004 assert(cut_item_size > 0);
1005 memcpy (cut_item_buf, src_0, cut_item_size);
1007 no_items_1 = no_items;
1011 (*b->method->codec.encode)(c2, &dst, &src);
1021 dst_item = lookahead_item;
1022 if (!(*stream->read_item)(stream->clientData, &dst_item,
1029 new_size = dst - dst_buf;
1030 if (p && p->cat != b->no_cat-1 &&
1031 new_size > b->file[p->cat].head.block_max)
1033 /* non-btree block will be removed */
1036 /* delete it too!! */
1037 p = 0; /* make a new one anyway */
1040 { /* must create a new one */
1042 for (i = 0; i < b->no_cat; i++)
1043 if (new_size <= b->file[i].head.block_max)
1047 p = new_leaf (b, i);
1049 if (new_size > b->file[p->cat].head.block_max)
1052 const char *cut_item = cut_item_buf;
1057 assert(cut_item_size > 0);
1060 p->size = half1 - dst_buf;
1061 assert(p->size <= b->file[p->cat].head.block_max);
1062 memcpy (p->bytes, dst_buf, half1 - dst_buf);
1063 p->no_items = no_items_1;
1066 *sp2 = new_leaf (b, p->cat);
1068 (*b->method->codec.reset)(c2);
1070 first_dst = (*sp2)->bytes;
1072 (*b->method->codec.encode)(c2, &first_dst, &cut_item);
1074 memcpy (first_dst, half2, dst - half2);
1076 (*sp2)->size = (first_dst - (*sp2)->bytes) + (dst - half2);
1077 assert((*sp2)->size <= b->file[p->cat].head.block_max);
1078 (*sp2)->no_items = no_items - no_items_1;
1081 memcpy (sub_item, cut_item_buf, cut_item_size);
1082 *sub_size = cut_item_size;
1086 memcpy (p->bytes, dst_buf, dst - dst_buf);
1088 p->no_items = no_items;
1090 (*b->method->codec.stop)(c1);
1091 (*b->method->codec.stop)(c2);
1096 int insert_sub (ISAMB b, struct ISAMB_block **p, void *new_item,
1099 struct ISAMB_block **sp,
1100 void *sub_item, int *sub_size,
1101 const void *max_item)
1103 if (!*p || (*p)->leaf)
1104 return insert_leaf (b, p, new_item, mode, stream, sp, sub_item,
1105 sub_size, max_item);
1107 return insert_int (b, *p, new_item, mode, stream, sp, sub_item,
1108 sub_size, max_item);
1111 int isamb_unlink (ISAMB b, ISAMC_P pos)
1113 struct ISAMB_block *p1;
1117 p1 = open_block(b, pos);
1122 const char *src = p1->bytes + p1->offset;
1124 void *c1 = (*b->method->codec.start)();
1126 decode_ptr(&src, &sub_p);
1127 isamb_unlink(b, sub_p);
1129 while (src != p1->bytes + p1->size)
1132 char file_item_buf[DST_ITEM_MAX];
1133 char *file_item = file_item_buf;
1134 (*b->method->codec.reset)(c1);
1135 (*b->method->codec.decode)(c1, &file_item, &src);
1138 decode_item_len(&src, &item_len);
1141 decode_ptr(&src, &sub_p);
1142 isamb_unlink(b, sub_p);
1145 (*b->method->codec.stop)(c1);
1152 ISAMB_P isamb_merge (ISAMB b, ISAMC_P pos, ISAMC_I *stream)
1154 char item_buf[DST_ITEM_MAX];
1158 int must_delete = 0;
1165 item_ptr = item_buf;
1167 (*stream->read_item)(stream->clientData, &item_ptr, &i_mode);
1171 item_ptr = item_buf;
1172 more = (*stream->read_item)(stream->clientData, &item_ptr, &i_mode);
1175 struct ISAMB_block *p = 0, *sp = 0;
1176 char sub_item[DST_ITEM_MAX];
1180 p = open_block(b, pos);
1181 more = insert_sub (b, &p, item_buf, &i_mode, stream, &sp,
1182 sub_item, &sub_size, 0);
1184 { /* increase level of tree by one */
1185 struct ISAMB_block *p2 = new_int (b, p->cat);
1186 char *dst = p2->bytes + p2->size;
1188 void *c1 = (*b->method->codec.start)();
1189 const char *sub_item_ptr = sub_item;
1192 encode_ptr(&dst, p->pos);
1193 assert (sub_size < 80 && sub_size > 1);
1195 (*b->method->codec.reset)(c1);
1196 (*b->method->codec.encode)(c1, &dst, &sub_item_ptr);
1198 encode_item_len (&dst, sub_size);
1199 memcpy (dst, sub_item, sub_size);
1202 encode_ptr(&dst, sp->pos);
1204 p2->size = dst - p2->bytes;
1205 p2->no_items = p->no_items + sp->no_items;
1206 pos = p2->pos; /* return new super page */
1210 (*b->method->codec.stop)(c1);
1215 pos = p->pos; /* return current one (again) */
1217 if (p->no_items == 0)
1225 isamb_unlink(b, pos);
1231 ISAMB_PP isamb_pp_open_x(ISAMB isamb, ISAMB_P pos, int *level, int scope)
1233 ISAMB_PP pp = xmalloc(sizeof(*pp));
1239 pp->block = xmalloc(ISAMB_MAX_LEVEL * sizeof(*pp->block));
1246 pp->skipped_numbers = 0;
1247 pp->returned_numbers = 0;
1249 for (i = 0; i<ISAMB_MAX_LEVEL; i++)
1250 pp->skipped_nodes[i] = pp->accessed_nodes[i] = 0;
1253 struct ISAMB_block *p = open_block(isamb, pos);
1254 const char *src = p->bytes + p->offset;
1255 pp->block[pp->level] = p;
1257 pp->total_size += p->size;
1261 decode_ptr(&src, &pos);
1262 p->offset = src - p->bytes;
1264 pp->accessed_nodes[pp->level]++;
1266 pp->block[pp->level+1] = 0;
1267 pp->maxlevel = pp->level;
1273 ISAMB_PP isamb_pp_open (ISAMB isamb, ISAMB_P pos, int scope)
1275 return isamb_pp_open_x(isamb, pos, 0, scope);
1278 void isamb_pp_close_x(ISAMB_PP pp, zint *size, zint *blocks)
1283 yaz_log(YLOG_DEBUG, "isamb_pp_close lev=%d returned "ZINT_FORMAT" values, "
1284 "skipped "ZINT_FORMAT,
1285 pp->maxlevel, pp->skipped_numbers, pp->returned_numbers);
1286 for (i = pp->maxlevel; i>=0; i--)
1287 if (pp->skipped_nodes[i] || pp->accessed_nodes[i])
1288 yaz_log(YLOG_DEBUG, "isamb_pp_close level leaf-%d: "
1289 ZINT_FORMAT" read, "ZINT_FORMAT" skipped", i,
1290 pp->accessed_nodes[i], pp->skipped_nodes[i]);
1291 pp->isamb->skipped_numbers += pp->skipped_numbers;
1292 pp->isamb->returned_numbers += pp->returned_numbers;
1293 for (i = pp->maxlevel; i>=0; i--)
1295 pp->isamb->accessed_nodes[i] += pp->accessed_nodes[i];
1296 pp->isamb->skipped_nodes[i] += pp->skipped_nodes[i];
1299 *size = pp->total_size;
1301 *blocks = pp->no_blocks;
1302 for (i = 0; i <= pp->level; i++)
1303 close_block(pp->isamb, pp->block[i]);
1308 int isamb_block_info (ISAMB isamb, int cat)
1310 if (cat >= 0 && cat < isamb->no_cat)
1311 return isamb->file[cat].head.block_size;
1315 void isamb_pp_close (ISAMB_PP pp)
1317 isamb_pp_close_x(pp, 0, 0);
1320 /* simple recursive dumper .. */
1321 static void isamb_dump_r (ISAMB b, ISAMB_P pos, void (*pr)(const char *str),
1325 char prefix_str[1024];
1328 struct ISAMB_block *p = open_block(b, pos);
1329 sprintf(prefix_str, "%*s " ZINT_FORMAT " cat=%d size=%d max=%d items="
1330 ZINT_FORMAT, level*2, "",
1331 pos, p->cat, p->size, b->file[p->cat].head.block_max,
1334 sprintf(prefix_str, "%*s " ZINT_FORMAT, level*2, "", pos);
1337 while (p->offset < p->size)
1339 const char *src = p->bytes + p->offset;
1341 (*b->method->codec.decode)(p->decodeClientData, &dst, &src);
1342 (*b->method->log_item)(YLOG_DEBUG, buf, prefix_str);
1343 p->offset = src - (char*) p->bytes;
1345 assert(p->offset == p->size);
1349 const char *src = p->bytes + p->offset;
1352 decode_ptr(&src, &sub);
1353 p->offset = src - (char*) p->bytes;
1355 isamb_dump_r(b, sub, pr, level+1);
1357 while (p->offset < p->size)
1360 char file_item_buf[DST_ITEM_MAX];
1361 char *file_item = file_item_buf;
1362 void *c1 = (*b->method->codec.start)();
1363 (*b->method->codec.decode)(c1, &file_item, &src);
1364 (*b->method->codec.stop)(c1);
1365 (*b->method->log_item)(YLOG_DEBUG, file_item_buf, prefix_str);
1368 decode_item_len(&src, &item_len);
1369 (*b->method->log_item)(YLOG_DEBUG, src, prefix_str);
1372 decode_ptr(&src, &sub);
1374 p->offset = src - (char*) p->bytes;
1376 isamb_dump_r(b, sub, pr, level+1);
1383 void isamb_dump(ISAMB b, ISAMB_P pos, void (*pr)(const char *str))
1385 isamb_dump_r(b, pos, pr, 0);
1388 int isamb_pp_read(ISAMB_PP pp, void *buf)
1390 return isamb_pp_forward(pp, buf, 0);
1394 static int isamb_pp_on_right_node(ISAMB_PP pp, int level, const void *untilbuf)
1395 { /* looks one node higher to see if we should be on this node at all */
1396 /* useful in backing off quickly, and in avoiding tail descends */
1397 /* call with pp->level to begin with */
1398 struct ISAMB_block *p;
1401 ISAMB b = pp->isamb;
1407 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true for root");
1409 return 1; /* we can never skip the root node */
1412 p = pp->block[level];
1413 assert(p->offset <= p->size);
1414 if (p->offset < p->size)
1417 char file_item_buf[DST_ITEM_MAX];
1418 char *file_item = file_item_buf;
1419 void *c1 = (*b->method->codec.start)();
1420 assert(p->offset > 0);
1421 src = p->bytes + p->offset;
1422 (*b->method->codec.decode)(c1, &file_item, &src);
1423 (*b->method->codec.stop)(c1);
1424 cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
1427 assert(p->offset > 0);
1428 src = p->bytes + p->offset;
1429 decode_item_len(&src, &item_len);
1431 (*b->method->codec.log_item)(YLOG_DEBUG, untilbuf, "on_leaf: until");
1432 (*b->method->codec.log_item)(YLOG_DEBUG, src, "on_leaf: value");
1434 cmp = (*b->method->compare_item)(untilbuf, src);
1436 if (cmp < pp->scope)
1439 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true "
1440 "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
1447 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning false "
1448 "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
1455 yaz_log(YLOG_DEBUG, "isamb_pp_on_right at tail, looking higher "
1458 return isamb_pp_on_right_node(pp, level, untilbuf);
1460 } /* isamb_pp_on_right_node */
1462 static int isamb_pp_read_on_leaf(ISAMB_PP pp, void *buf)
1464 /* reads the next item on the current leaf, returns 0 if end of leaf*/
1465 struct ISAMB_block *p = pp->block[pp->level];
1470 if (p->offset == p->size)
1473 yaz_log(YLOG_DEBUG, "isamb_pp_read_on_leaf returning 0 on "
1476 return 0; /* at end of leaf */
1478 src = p->bytes + p->offset;
1480 (*pp->isamb->method->codec.decode)(p->decodeClientData, &dst, &src);
1481 p->offset = src - (char*) p->bytes;
1483 (*pp->isamb->method->codec.log_item)(YLOG_DEBUG, buf,
1484 "read_on_leaf returning 1");
1486 pp->returned_numbers++;
1488 } /* read_on_leaf */
1490 static int isamb_pp_forward_on_leaf(ISAMB_PP pp, void *buf, const void *untilbuf)
1491 { /* forwards on the current leaf, returns 0 if not found */
1496 if (!isamb_pp_read_on_leaf(pp, buf))
1498 /* FIXME - this is an extra function call, inline the read? */
1499 cmp=(*pp->isamb->method->compare_item)(untilbuf, buf);
1501 { /* cmp<2 found a good one */
1504 yaz_log(YLOG_DEBUG, "isam_pp_fwd_on_leaf skipped %d items", skips);
1506 pp->returned_numbers++;
1510 if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
1511 return 0; /* never mind the rest of this leaf */
1512 pp->skipped_numbers++;
1515 } /* forward_on_leaf */
1517 static int isamb_pp_climb_level(ISAMB_PP pp, ISAMB_P *pos)
1518 { /* climbs higher in the tree, until finds a level with data left */
1519 /* returns the node to (consider to) descend to in *pos) */
1520 struct ISAMB_block *p = pp->block[pp->level];
1523 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level starting "
1524 "at level %d node %d ofs=%d sz=%d",
1525 pp->level, p->pos, p->offset, p->size);
1527 assert(pp->level >= 0);
1528 assert(p->offset <= p->size);
1532 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level returning 0 at root");
1536 assert(pp->level>0);
1537 close_block(pp->isamb, pp->block[pp->level]);
1538 pp->block[pp->level] = 0;
1540 p = pp->block[pp->level];
1542 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level climbed to level %d node %d ofs=%d",
1543 pp->level, p->pos, p->offset);
1546 assert(p->offset <= p->size);
1547 if (p->offset == p->size)
1549 /* we came from the last pointer, climb on */
1550 if (!isamb_pp_climb_level(pp, pos))
1552 p = pp->block[pp->level];
1557 char file_item_buf[DST_ITEM_MAX];
1558 char *file_item = file_item_buf;
1559 ISAMB b = pp->isamb;
1560 void *c1 = (*b->method->codec.start)();
1564 /* skip the child we just came from */
1566 yaz_log(YLOG_DEBUG, "isam_pp_climb_level: skipping lev=%d ofs=%d sz=%d",
1567 pp->level, p->offset, p->size);
1569 assert (p->offset < p->size);
1570 src = p->bytes + p->offset;
1572 (*b->method->codec.decode)(c1, &file_item, &src);
1573 (*b->method->codec.stop)(c1);
1575 decode_item_len(&src, &item_len);
1578 decode_ptr(&src, pos);
1579 p->offset = src - (char *)p->bytes;
1586 static zint isamb_pp_forward_unode(ISAMB_PP pp, zint pos, const void *untilbuf)
1587 { /* scans a upper node until it finds a child <= untilbuf */
1588 /* pp points to the key value, as always. pos is the child read from */
1590 /* if all values are too small, returns the last child in the node */
1591 /* FIXME - this can be detected, and avoided by looking at the */
1592 /* parent node, but that gets messy. Presumably the cost is */
1593 /* pretty low anyway */
1594 ISAMB b = pp->isamb;
1595 struct ISAMB_block *p = pp->block[pp->level];
1596 const char *src = p->bytes + p->offset;
1601 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode starting "
1602 "at level %d node %d ofs=%di sz=%d",
1603 pp->level, p->pos, p->offset, p->size);
1606 assert(p->offset <= p->size);
1607 if (p->offset == p->size)
1610 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at end "
1611 "at level %d node %d ofs=%di sz=%d",
1612 pp->level, p->pos, p->offset, p->size);
1614 return pos; /* already at the end of it */
1616 while(p->offset < p->size)
1619 char file_item_buf[DST_ITEM_MAX];
1620 char *file_item = file_item_buf;
1621 void *c1 = (*b->method->codec.start)();
1622 (*b->method->codec.decode)(c1, &file_item, &src);
1623 (*b->method->codec.stop)(c1);
1624 cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
1627 decode_item_len(&src, &item_len);
1628 cmp = (*b->method->compare_item)(untilbuf, src);
1631 decode_ptr(&src, &nxtpos);
1632 if (cmp<pp->scope) /* cmp<2 */
1635 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning a hit "
1636 "at level %d node %d ofs=%d sz=%d",
1637 pp->level, p->pos, p->offset, p->size);
1642 p->offset = src-(char*)p->bytes;
1643 (pp->skipped_nodes[pp->maxlevel - pp->level -1])++;
1649 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at tail "
1650 "at level %d node %d ofs=%d sz=%d skips=%d",
1651 pp->level, p->pos, p->offset, p->size, skips);
1653 return pos; /* that's the last one in the line */
1655 } /* forward_unode */
1657 static void isamb_pp_descend_to_leaf(ISAMB_PP pp, ISAMB_P pos,
1658 const void *untilbuf)
1659 { /* climbs down the tree, from pos, to the leftmost leaf */
1660 struct ISAMB_block *p = pp->block[pp->level];
1664 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1665 "starting at lev %d node %d ofs=%d lf=%d u=%p",
1666 pp->level, p->pos, p->offset, p->leaf, untilbuf);
1669 pos = isamb_pp_forward_unode(pp, pos, untilbuf);
1672 p = open_block(pp->isamb, pos);
1673 pp->block[pp->level] = p;
1674 ++(pp->accessed_nodes[pp->maxlevel-pp->level]);
1677 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1678 "got lev %d node %d lf=%d",
1679 pp->level, p->pos, p->leaf);
1683 assert (p->offset==0);
1684 src = p->bytes + p->offset;
1685 decode_ptr(&src, &pos);
1686 p->offset = src-(char*)p->bytes;
1687 isamb_pp_descend_to_leaf(pp, pos, untilbuf);
1689 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1690 "returning at lev %d node %d ofs=%d lf=%d",
1691 pp->level, p->pos, p->offset, p->leaf);
1693 } /* descend_to_leaf */
1695 static int isamb_pp_find_next_leaf(ISAMB_PP pp)
1696 { /* finds the next leaf by climbing up and down */
1698 if (!isamb_pp_climb_level(pp, &pos))
1700 isamb_pp_descend_to_leaf(pp, pos, 0);
1704 static int isamb_pp_climb_desc(ISAMB_PP pp, const void *untilbuf)
1705 { /* climbs up and descends to a leaf where values >= *untilbuf are found */
1708 struct ISAMB_block *p = pp->block[pp->level];
1709 yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc starting "
1710 "at level %d node %d ofs=%d sz=%d",
1711 pp->level, p->pos, p->offset, p->size);
1713 if (!isamb_pp_climb_level(pp, &pos))
1715 /* see if it would pay to climb one higher */
1716 if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
1717 if (!isamb_pp_climb_level(pp, &pos))
1719 isamb_pp_descend_to_leaf(pp, pos, untilbuf);
1721 p = pp->block[pp->level];
1722 yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc done "
1723 "at level %d node %d ofs=%d sz=%d",
1724 pp->level, p->pos, p->offset, p->size);
1729 int isamb_pp_forward (ISAMB_PP pp, void *buf, const void *untilbuf)
1732 struct ISAMB_block *p = pp->block[pp->level];
1734 yaz_log(YLOG_DEBUG, "isamb_pp_forward starting "
1735 "at level %d node %d ofs=%d sz=%d u=%p sc=%d",
1736 pp->level, p->pos, p->offset, p->size, untilbuf, scope);
1740 if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
1743 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (A) "
1744 "at level %d node %d ofs=%d sz=%d",
1745 pp->level, p->pos, p->offset, p->size);
1749 if (! isamb_pp_climb_desc(pp, untilbuf))
1752 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning notfound (B) "
1753 "at level %d node %d ofs=%d sz=%d",
1754 pp->level, p->pos, p->offset, p->size);
1756 return 0; /* could not find a leaf */
1759 if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
1762 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (c) "
1763 "at level %d node %d ofs=%d sz=%d",
1764 pp->level, p->pos, p->offset, p->size);
1768 } while (isamb_pp_find_next_leaf(pp));
1769 return 0; /* could not find at all */
1771 else { /* no untilbuf, a straight read */
1772 /* FIXME - this should be moved
1773 * directly into the pp_read */
1774 /* keeping here now, to keep same
1775 * interface as the old fwd */
1776 if (isamb_pp_read_on_leaf(pp, buf))
1779 yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (D) "
1780 "at level %d node %d ofs=%d sz=%d",
1781 pp->level, p->pos, p->offset, p->size);
1785 if (isamb_pp_find_next_leaf(pp))
1788 yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (E) "
1789 "at level %d node %d ofs=%d sz=%d",
1790 pp->level, p->pos, p->offset, p->size);
1792 return isamb_pp_read_on_leaf(pp, buf);
1797 } /* isam_pp_forward (new version) */
1799 void isamb_pp_pos(ISAMB_PP pp, double *current, double *total)
1800 { /* return an estimate of the current position and of the total number of */
1801 /* occureences in the isam tree, based on the current leaf */
1802 struct ISAMB_block *p = pp->block[pp->level];
1807 *total = (double) (pp->block[0]->no_items);
1808 *current = (double) pp->returned_numbers;
1810 yaz_log(YLOG_LOG, "isamb_pp_pos returning: cur= %0.1f tot=%0.1f rn="
1811 ZINT_FORMAT, *current, *total, pp->returned_numbers);
1815 int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
1819 struct ISAMB_block *p = pp->block[pp->level];
1820 ISAMB b = pp->isamb;
1824 while (p->offset == p->size)
1830 char file_item_buf[DST_ITEM_MAX];
1831 char *file_item = file_item_buf;
1835 while (p->offset == p->size)
1839 close_block (pp->isamb, pp->block[pp->level]);
1840 pp->block[pp->level] = 0;
1842 p = pp->block[pp->level];
1847 src = p->bytes + p->offset;
1850 c1 = (*b->method->codec.start)();
1851 (*b->method->codec.decode)(c1, &file_item, &src);
1853 decode_ptr (&src, &item_len);
1856 decode_ptr (&src, &pos);
1857 p->offset = src - (char*) p->bytes;
1859 src = p->bytes + p->offset;
1863 if (!untilb || p->offset == p->size)
1865 assert(p->offset < p->size);
1868 file_item = file_item_buf;
1869 (*b->method->codec.reset)(c1);
1870 (*b->method->codec.decode)(c1, &file_item, &src);
1871 if ((*b->method->compare_item)(untilb, file_item_buf) <= 1)
1877 decode_item_len(&src, &item_len);
1878 if ((*b->method->compare_item)(untilb, src) <= 1)
1882 decode_ptr (&src, &pos);
1883 p->offset = src - (char*) p->bytes;
1890 pp->block[pp->level] = p = open_block (pp->isamb, pos);
1892 pp->total_size += p->size;
1900 src = p->bytes + p->offset;
1903 decode_ptr (&src, &pos);
1904 p->offset = src - (char*) p->bytes;
1906 if (!untilb || p->offset == p->size)
1908 assert(p->offset < p->size);
1911 file_item = file_item_buf;
1912 (*b->method->codec.reset)(c1);
1913 (*b->method->codec.decode)(c1, &file_item, &src);
1914 if ((*b->method->compare_item)(untilb, file_item_buf) <= 1)
1920 decode_ptr (&src, &item_len);
1921 if ((*b->method->compare_item)(untilb, src) <= 1)
1929 (*b->method->codec.stop)(c1);
1932 assert (p->offset < p->size);
1937 src = p->bytes + p->offset;
1938 (*pp->isamb->method->codec.decode)(p->decodeClientData, &dst, &src);
1939 p->offset = src - (char*) p->bytes;
1940 if (!untilb || (*pp->isamb->method->compare_item)(untilb, dst0) <= 1)
1943 if (p->offset == p->size) goto again;