1 /* $Id: isamb.c,v 1.83 2006-08-14 10:40:17 adam Exp $
2 Copyright (C) 1995-2006
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 this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
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, ISAM_P pos, unsigned 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, ISAM_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 = (char *)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);
468 src = (char*) p->buf + 3;
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 = (char*)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 = (char*)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);
735 if (p->size <= b->file[p->cat].head.block_max)
737 /* it fits OK in this block */
738 memcpy (startp, dst_buf, dst - dst_buf);
740 close_block(b, sub_p2);
744 /* must split _this_ block as well .. */
745 struct ISAMB_block *sub_p3;
747 char file_item_buf[DST_ITEM_MAX];
748 char *file_item = file_item_buf;
752 zint no_items_first_half = 0;
759 close_block(b, sub_p2);
761 half = src + b->file[p->cat].head.block_size/2;
762 decode_ptr(&src, &pos);
764 /* read sub block so we can get no_items for it */
765 sub_p3 = open_block(b, pos);
766 no_items_first_half += sub_p3->no_items;
767 close_block(b, sub_p3);
772 file_item = file_item_buf;
773 (*b->method->codec.reset)(c1);
774 (*b->method->codec.decode)(c1, &file_item, &src);
776 decode_item_len(&src, &split_size_tmp);
777 *split_size = (int) split_size_tmp;
780 decode_ptr(&src, &pos);
782 /* read sub block so we can get no_items for it */
783 sub_p3 = open_block(b, pos);
784 no_items_first_half += sub_p3->no_items;
785 close_block(b, sub_p3);
787 /* p is first half */
788 p_new_size = src - dst_buf;
789 memcpy (p->bytes, dst_buf, p_new_size);
792 file_item = file_item_buf;
793 (*b->method->codec.reset)(c1);
794 (*b->method->codec.decode)(c1, &file_item, &src);
795 *split_size = file_item - file_item_buf;
796 memcpy(split_item, file_item_buf, *split_size);
798 decode_item_len(&src, &split_size_tmp);
799 *split_size = (int) split_size_tmp;
800 memcpy (split_item, src, *split_size);
803 /* *sp is second half */
804 *sp = new_int (b, p->cat);
805 (*sp)->size = endp - src;
806 memcpy ((*sp)->bytes, src, (*sp)->size);
808 p->size = p_new_size;
810 /* adjust no_items in first&second half */
811 (*sp)->no_items = p->no_items - no_items_first_half;
812 p->no_items = no_items_first_half;
816 close_block(b, sub_p1);
817 (*b->method->codec.stop)(c1);
821 int insert_leaf (ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
822 int *lookahead_mode, ISAMC_I *stream,
823 struct ISAMB_block **sp2,
824 void *sub_item, int *sub_size,
825 const void *max_item)
827 struct ISAMB_block *p = *sp1;
830 char dst_buf[DST_BUF_SIZE], *dst = dst_buf;
832 void *c1 = (*b->method->codec.start)();
833 void *c2 = (*b->method->codec.start)();
835 int quater = b->file[b->no_cat-1].head.block_max / 4;
836 char *mid_cut = dst_buf + quater * 2;
837 char *tail_cut = dst_buf + quater * 3;
838 char *maxp = dst_buf + b->file[b->no_cat-1].head.block_max;
841 char cut_item_buf[DST_ITEM_MAX];
842 int cut_item_size = 0;
843 int no_items = 0; /* number of items (total) */
844 int no_items_1 = 0; /* number of items (first half) */
845 int inserted_dst_bytes = 0;
849 char file_item_buf[DST_ITEM_MAX];
850 char *file_item = file_item_buf;
853 endp = p->bytes + p->size;
854 (*b->method->codec.decode)(c1, &file_item, &src);
857 const char *dst_item = 0; /* resulting item to be inserted */
858 char *lookahead_next;
863 d = (*b->method->compare_item)(file_item_buf, lookahead_item);
865 /* d now holds comparison between existing file item and
868 d > 0: lookahead before file
869 d < 0: lookahead after file
873 /* lookahead must be inserted */
874 dst_item = lookahead_item;
875 /* if this is not an insertion, it's really bad .. */
876 if (!*lookahead_mode)
878 yaz_log(YLOG_WARN, "isamb: Inconsistent register (1)");
879 assert (*lookahead_mode);
883 dst_item = file_item_buf;
885 if (!*lookahead_mode && d == 0)
887 /* it's a deletion and they match so there is nothing to be
888 inserted anyway .. But mark the thing bad (file item
889 was part of input.. The item will not be part of output */
892 else if (!half1 && dst > mid_cut)
894 /* we have reached the splitting point for the first time */
895 const char *dst_item_0 = dst_item;
896 half1 = dst; /* candidate for splitting */
898 /* encode the resulting item */
899 (*b->method->codec.encode)(c2, &dst, &dst_item);
901 cut_item_size = dst_item - dst_item_0;
902 assert(cut_item_size > 0);
903 memcpy (cut_item_buf, dst_item_0, cut_item_size);
906 no_items_1 = no_items;
911 /* encode the resulting item */
912 (*b->method->codec.encode)(c2, &dst, &dst_item);
916 /* now move "pointers" .. result has been encoded .. */
919 /* we must move the lookahead pointer */
921 inserted_dst_bytes += (dst - dst_0);
922 if (inserted_dst_bytes >= quater)
923 /* no more room. Mark lookahead as "gone".. */
927 /* move it really.. */
928 lookahead_next = lookahead_item;
929 if (!(*stream->read_item)(stream->clientData,
933 /* end of stream reached: no "more" and no lookahead */
937 if (lookahead_item && max_item &&
938 (*b->method->compare_item)(max_item, lookahead_item) <= 0)
940 /* the lookahead goes beyond what we allow in this
941 leaf. Mark it as "gone" */
950 /* exact match .. move both pointers */
952 lookahead_next = lookahead_item;
953 if (!(*stream->read_item)(stream->clientData,
954 &lookahead_next, lookahead_mode))
960 break; /* end of file stream reached .. */
961 file_item = file_item_buf; /* move file pointer */
962 (*b->method->codec.decode)(c1, &file_item, &src);
966 /* file pointer must be moved */
969 file_item = file_item_buf;
970 (*b->method->codec.decode)(c1, &file_item, &src);
975 /* this loop runs when we are "appending" to a leaf page. That is
976 either it's empty (new) or all file items have been read in
979 maxp = dst_buf + b->file[b->no_cat-1].head.block_max + quater;
980 while (lookahead_item)
983 const char *src = lookahead_item;
986 /* if we have a lookahead item, we stop if we exceed the value of it */
988 (*b->method->compare_item)(max_item, lookahead_item) <= 0)
990 /* stop if we have reached the value of max item */
993 if (!*lookahead_mode)
995 /* this is append. So a delete is bad */
996 yaz_log(YLOG_WARN, "isamb: Inconsistent register (2)");
999 else if (!half1 && dst > tail_cut)
1001 const char *src_0 = src;
1002 half1 = dst; /* candidate for splitting */
1004 (*b->method->codec.encode)(c2, &dst, &src);
1006 cut_item_size = src - src_0;
1007 assert(cut_item_size > 0);
1008 memcpy (cut_item_buf, src_0, cut_item_size);
1010 no_items_1 = no_items;
1014 (*b->method->codec.encode)(c2, &dst, &src);
1024 dst_item = lookahead_item;
1025 if (!(*stream->read_item)(stream->clientData, &dst_item,
1032 new_size = dst - dst_buf;
1033 if (p && p->cat != b->no_cat-1 &&
1034 new_size > b->file[p->cat].head.block_max)
1036 /* non-btree block will be removed */
1039 /* delete it too!! */
1040 p = 0; /* make a new one anyway */
1043 { /* must create a new one */
1045 for (i = 0; i < b->no_cat; i++)
1046 if (new_size <= b->file[i].head.block_max)
1050 p = new_leaf (b, i);
1052 if (new_size > b->file[p->cat].head.block_max)
1055 const char *cut_item = cut_item_buf;
1060 assert(cut_item_size > 0);
1063 p->size = half1 - dst_buf;
1064 assert(p->size <= b->file[p->cat].head.block_max);
1065 memcpy (p->bytes, dst_buf, half1 - dst_buf);
1066 p->no_items = no_items_1;
1069 *sp2 = new_leaf (b, p->cat);
1071 (*b->method->codec.reset)(c2);
1073 first_dst = (*sp2)->bytes;
1075 (*b->method->codec.encode)(c2, &first_dst, &cut_item);
1077 memcpy (first_dst, half2, dst - half2);
1079 (*sp2)->size = (first_dst - (*sp2)->bytes) + (dst - half2);
1080 assert((*sp2)->size <= b->file[p->cat].head.block_max);
1081 (*sp2)->no_items = no_items - no_items_1;
1084 memcpy (sub_item, cut_item_buf, cut_item_size);
1085 *sub_size = cut_item_size;
1089 memcpy (p->bytes, dst_buf, dst - dst_buf);
1091 p->no_items = no_items;
1093 (*b->method->codec.stop)(c1);
1094 (*b->method->codec.stop)(c2);
1099 int insert_sub (ISAMB b, struct ISAMB_block **p, void *new_item,
1102 struct ISAMB_block **sp,
1103 void *sub_item, int *sub_size,
1104 const void *max_item)
1106 if (!*p || (*p)->leaf)
1107 return insert_leaf (b, p, new_item, mode, stream, sp, sub_item,
1108 sub_size, max_item);
1110 return insert_int (b, *p, new_item, mode, stream, sp, sub_item,
1111 sub_size, max_item);
1114 int isamb_unlink (ISAMB b, ISAM_P pos)
1116 struct ISAMB_block *p1;
1120 p1 = open_block(b, pos);
1125 const char *src = p1->bytes + p1->offset;
1127 void *c1 = (*b->method->codec.start)();
1129 decode_ptr(&src, &sub_p);
1130 isamb_unlink(b, sub_p);
1132 while (src != p1->bytes + p1->size)
1135 char file_item_buf[DST_ITEM_MAX];
1136 char *file_item = file_item_buf;
1137 (*b->method->codec.reset)(c1);
1138 (*b->method->codec.decode)(c1, &file_item, &src);
1141 decode_item_len(&src, &item_len);
1144 decode_ptr(&src, &sub_p);
1145 isamb_unlink(b, sub_p);
1148 (*b->method->codec.stop)(c1);
1155 void isamb_merge(ISAMB b, ISAM_P *pos, ISAMC_I *stream)
1157 char item_buf[DST_ITEM_MAX];
1161 int must_delete = 0;
1168 item_ptr = item_buf;
1170 (*stream->read_item)(stream->clientData, &item_ptr, &i_mode);
1175 item_ptr = item_buf;
1176 more = (*stream->read_item)(stream->clientData, &item_ptr, &i_mode);
1179 struct ISAMB_block *p = 0, *sp = 0;
1180 char sub_item[DST_ITEM_MAX];
1184 p = open_block(b, *pos);
1185 more = insert_sub (b, &p, item_buf, &i_mode, stream, &sp,
1186 sub_item, &sub_size, 0);
1188 { /* increase level of tree by one */
1189 struct ISAMB_block *p2 = new_int (b, p->cat);
1190 char *dst = p2->bytes + p2->size;
1192 void *c1 = (*b->method->codec.start)();
1193 const char *sub_item_ptr = sub_item;
1196 encode_ptr(&dst, p->pos);
1197 assert (sub_size < 80 && sub_size > 1);
1199 (*b->method->codec.reset)(c1);
1200 (*b->method->codec.encode)(c1, &dst, &sub_item_ptr);
1202 encode_item_len (&dst, sub_size);
1203 memcpy (dst, sub_item, sub_size);
1206 encode_ptr(&dst, sp->pos);
1208 p2->size = dst - p2->bytes;
1209 p2->no_items = p->no_items + sp->no_items;
1210 *pos = p2->pos; /* return new super page */
1214 (*b->method->codec.stop)(c1);
1219 *pos = p->pos; /* return current one (again) */
1221 if (p->no_items == 0)
1229 isamb_unlink(b, *pos);
1234 ISAMB_PP isamb_pp_open_x(ISAMB isamb, ISAM_P pos, int *level, int scope)
1236 ISAMB_PP pp = xmalloc(sizeof(*pp));
1242 pp->block = xmalloc(ISAMB_MAX_LEVEL * sizeof(*pp->block));
1249 pp->skipped_numbers = 0;
1250 pp->returned_numbers = 0;
1252 for (i = 0; i<ISAMB_MAX_LEVEL; i++)
1253 pp->skipped_nodes[i] = pp->accessed_nodes[i] = 0;
1256 struct ISAMB_block *p = open_block(isamb, pos);
1257 const char *src = p->bytes + p->offset;
1258 pp->block[pp->level] = p;
1260 pp->total_size += p->size;
1264 decode_ptr(&src, &pos);
1265 p->offset = src - p->bytes;
1267 pp->accessed_nodes[pp->level]++;
1269 pp->block[pp->level+1] = 0;
1270 pp->maxlevel = pp->level;
1276 ISAMB_PP isamb_pp_open (ISAMB isamb, ISAM_P pos, int scope)
1278 return isamb_pp_open_x(isamb, pos, 0, scope);
1281 void isamb_pp_close_x(ISAMB_PP pp, zint *size, zint *blocks)
1286 yaz_log(YLOG_DEBUG, "isamb_pp_close lev=%d returned "ZINT_FORMAT" values, "
1287 "skipped "ZINT_FORMAT,
1288 pp->maxlevel, pp->skipped_numbers, pp->returned_numbers);
1289 for (i = pp->maxlevel; i>=0; i--)
1290 if (pp->skipped_nodes[i] || pp->accessed_nodes[i])
1291 yaz_log(YLOG_DEBUG, "isamb_pp_close level leaf-%d: "
1292 ZINT_FORMAT" read, "ZINT_FORMAT" skipped", i,
1293 pp->accessed_nodes[i], pp->skipped_nodes[i]);
1294 pp->isamb->skipped_numbers += pp->skipped_numbers;
1295 pp->isamb->returned_numbers += pp->returned_numbers;
1296 for (i = pp->maxlevel; i>=0; i--)
1298 pp->isamb->accessed_nodes[i] += pp->accessed_nodes[i];
1299 pp->isamb->skipped_nodes[i] += pp->skipped_nodes[i];
1302 *size = pp->total_size;
1304 *blocks = pp->no_blocks;
1305 for (i = 0; i <= pp->level; i++)
1306 close_block(pp->isamb, pp->block[i]);
1311 int isamb_block_info (ISAMB isamb, int cat)
1313 if (cat >= 0 && cat < isamb->no_cat)
1314 return isamb->file[cat].head.block_size;
1318 void isamb_pp_close (ISAMB_PP pp)
1320 isamb_pp_close_x(pp, 0, 0);
1323 /* simple recursive dumper .. */
1324 static void isamb_dump_r (ISAMB b, ISAM_P pos, void (*pr)(const char *str),
1328 char prefix_str[1024];
1331 struct ISAMB_block *p = open_block(b, pos);
1332 sprintf(prefix_str, "%*s " ZINT_FORMAT " cat=%d size=%d max=%d items="
1333 ZINT_FORMAT, level*2, "",
1334 pos, p->cat, p->size, b->file[p->cat].head.block_max,
1337 sprintf(prefix_str, "%*s " ZINT_FORMAT, level*2, "", pos);
1340 while (p->offset < p->size)
1342 const char *src = p->bytes + p->offset;
1344 (*b->method->codec.decode)(p->decodeClientData, &dst, &src);
1345 (*b->method->log_item)(YLOG_DEBUG, buf, prefix_str);
1346 p->offset = src - (char*) p->bytes;
1348 assert(p->offset == p->size);
1352 const char *src = p->bytes + p->offset;
1355 decode_ptr(&src, &sub);
1356 p->offset = src - (char*) p->bytes;
1358 isamb_dump_r(b, sub, pr, level+1);
1360 while (p->offset < p->size)
1363 char file_item_buf[DST_ITEM_MAX];
1364 char *file_item = file_item_buf;
1365 void *c1 = (*b->method->codec.start)();
1366 (*b->method->codec.decode)(c1, &file_item, &src);
1367 (*b->method->codec.stop)(c1);
1368 (*b->method->log_item)(YLOG_DEBUG, file_item_buf, prefix_str);
1371 decode_item_len(&src, &item_len);
1372 (*b->method->log_item)(YLOG_DEBUG, src, prefix_str);
1375 decode_ptr(&src, &sub);
1377 p->offset = src - (char*) p->bytes;
1379 isamb_dump_r(b, sub, pr, level+1);
1386 void isamb_dump(ISAMB b, ISAM_P pos, void (*pr)(const char *str))
1388 isamb_dump_r(b, pos, pr, 0);
1391 int isamb_pp_read(ISAMB_PP pp, void *buf)
1393 return isamb_pp_forward(pp, buf, 0);
1397 static int isamb_pp_on_right_node(ISAMB_PP pp, int level, const void *untilbuf)
1398 { /* looks one node higher to see if we should be on this node at all */
1399 /* useful in backing off quickly, and in avoiding tail descends */
1400 /* call with pp->level to begin with */
1401 struct ISAMB_block *p;
1404 ISAMB b = pp->isamb;
1410 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true for root");
1412 return 1; /* we can never skip the root node */
1415 p = pp->block[level];
1416 assert(p->offset <= p->size);
1417 if (p->offset < p->size)
1420 char file_item_buf[DST_ITEM_MAX];
1421 char *file_item = file_item_buf;
1422 void *c1 = (*b->method->codec.start)();
1423 assert(p->offset > 0);
1424 src = p->bytes + p->offset;
1425 (*b->method->codec.decode)(c1, &file_item, &src);
1426 (*b->method->codec.stop)(c1);
1427 cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
1430 assert(p->offset > 0);
1431 src = p->bytes + p->offset;
1432 decode_item_len(&src, &item_len);
1434 (*b->method->codec.log_item)(YLOG_DEBUG, untilbuf, "on_leaf: until");
1435 (*b->method->codec.log_item)(YLOG_DEBUG, src, "on_leaf: value");
1437 cmp = (*b->method->compare_item)(untilbuf, src);
1439 if (cmp < pp->scope)
1442 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true "
1443 "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
1450 yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning false "
1451 "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
1458 yaz_log(YLOG_DEBUG, "isamb_pp_on_right at tail, looking higher "
1461 return isamb_pp_on_right_node(pp, level, untilbuf);
1463 } /* isamb_pp_on_right_node */
1465 static int isamb_pp_read_on_leaf(ISAMB_PP pp, void *buf)
1467 /* reads the next item on the current leaf, returns 0 if end of leaf*/
1468 struct ISAMB_block *p = pp->block[pp->level];
1473 if (p->offset == p->size)
1476 yaz_log(YLOG_DEBUG, "isamb_pp_read_on_leaf returning 0 on "
1479 return 0; /* at end of leaf */
1481 src = p->bytes + p->offset;
1483 (*pp->isamb->method->codec.decode)(p->decodeClientData, &dst, &src);
1484 p->offset = src - (char*) p->bytes;
1486 (*pp->isamb->method->codec.log_item)(YLOG_DEBUG, buf,
1487 "read_on_leaf returning 1");
1489 pp->returned_numbers++;
1491 } /* read_on_leaf */
1493 static int isamb_pp_forward_on_leaf(ISAMB_PP pp, void *buf, const void *untilbuf)
1494 { /* forwards on the current leaf, returns 0 if not found */
1499 if (!isamb_pp_read_on_leaf(pp, buf))
1501 /* FIXME - this is an extra function call, inline the read? */
1502 cmp=(*pp->isamb->method->compare_item)(untilbuf, buf);
1504 { /* cmp<2 found a good one */
1507 yaz_log(YLOG_DEBUG, "isam_pp_fwd_on_leaf skipped %d items", skips);
1509 pp->returned_numbers++;
1513 if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
1514 return 0; /* never mind the rest of this leaf */
1515 pp->skipped_numbers++;
1518 } /* forward_on_leaf */
1520 static int isamb_pp_climb_level(ISAMB_PP pp, ISAM_P *pos)
1521 { /* climbs higher in the tree, until finds a level with data left */
1522 /* returns the node to (consider to) descend to in *pos) */
1523 struct ISAMB_block *p = pp->block[pp->level];
1526 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level starting "
1527 "at level %d node %d ofs=%d sz=%d",
1528 pp->level, p->pos, p->offset, p->size);
1530 assert(pp->level >= 0);
1531 assert(p->offset <= p->size);
1535 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level returning 0 at root");
1539 assert(pp->level>0);
1540 close_block(pp->isamb, pp->block[pp->level]);
1541 pp->block[pp->level] = 0;
1543 p = pp->block[pp->level];
1545 yaz_log(YLOG_DEBUG, "isamb_pp_climb_level climbed to level %d node %d ofs=%d",
1546 pp->level, p->pos, p->offset);
1549 assert(p->offset <= p->size);
1550 if (p->offset == p->size)
1552 /* we came from the last pointer, climb on */
1553 if (!isamb_pp_climb_level(pp, pos))
1555 p = pp->block[pp->level];
1560 char file_item_buf[DST_ITEM_MAX];
1561 char *file_item = file_item_buf;
1562 ISAMB b = pp->isamb;
1563 void *c1 = (*b->method->codec.start)();
1567 /* skip the child we just came from */
1569 yaz_log(YLOG_DEBUG, "isam_pp_climb_level: skipping lev=%d ofs=%d sz=%d",
1570 pp->level, p->offset, p->size);
1572 assert (p->offset < p->size);
1573 src = p->bytes + p->offset;
1575 (*b->method->codec.decode)(c1, &file_item, &src);
1576 (*b->method->codec.stop)(c1);
1578 decode_item_len(&src, &item_len);
1581 decode_ptr(&src, pos);
1582 p->offset = src - (char *)p->bytes;
1589 static zint isamb_pp_forward_unode(ISAMB_PP pp, zint pos, const void *untilbuf)
1590 { /* scans a upper node until it finds a child <= untilbuf */
1591 /* pp points to the key value, as always. pos is the child read from */
1593 /* if all values are too small, returns the last child in the node */
1594 /* FIXME - this can be detected, and avoided by looking at the */
1595 /* parent node, but that gets messy. Presumably the cost is */
1596 /* pretty low anyway */
1597 ISAMB b = pp->isamb;
1598 struct ISAMB_block *p = pp->block[pp->level];
1599 const char *src = p->bytes + p->offset;
1604 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode starting "
1605 "at level %d node %d ofs=%di sz=%d",
1606 pp->level, p->pos, p->offset, p->size);
1609 assert(p->offset <= p->size);
1610 if (p->offset == p->size)
1613 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at end "
1614 "at level %d node %d ofs=%di sz=%d",
1615 pp->level, p->pos, p->offset, p->size);
1617 return pos; /* already at the end of it */
1619 while(p->offset < p->size)
1622 char file_item_buf[DST_ITEM_MAX];
1623 char *file_item = file_item_buf;
1624 void *c1 = (*b->method->codec.start)();
1625 (*b->method->codec.decode)(c1, &file_item, &src);
1626 (*b->method->codec.stop)(c1);
1627 cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
1630 decode_item_len(&src, &item_len);
1631 cmp = (*b->method->compare_item)(untilbuf, src);
1634 decode_ptr(&src, &nxtpos);
1635 if (cmp<pp->scope) /* cmp<2 */
1638 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning a hit "
1639 "at level %d node %d ofs=%d sz=%d",
1640 pp->level, p->pos, p->offset, p->size);
1645 p->offset = src-(char*)p->bytes;
1646 (pp->skipped_nodes[pp->maxlevel - pp->level -1])++;
1652 yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at tail "
1653 "at level %d node %d ofs=%d sz=%d skips=%d",
1654 pp->level, p->pos, p->offset, p->size, skips);
1656 return pos; /* that's the last one in the line */
1658 } /* forward_unode */
1660 static void isamb_pp_descend_to_leaf(ISAMB_PP pp, ISAM_P pos,
1661 const void *untilbuf)
1662 { /* climbs down the tree, from pos, to the leftmost leaf */
1663 struct ISAMB_block *p = pp->block[pp->level];
1667 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1668 "starting at lev %d node %d ofs=%d lf=%d u=%p",
1669 pp->level, p->pos, p->offset, p->leaf, untilbuf);
1672 pos = isamb_pp_forward_unode(pp, pos, untilbuf);
1675 p = open_block(pp->isamb, pos);
1676 pp->block[pp->level] = p;
1677 ++(pp->accessed_nodes[pp->maxlevel-pp->level]);
1680 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1681 "got lev %d node %d lf=%d",
1682 pp->level, p->pos, p->leaf);
1686 assert (p->offset==0);
1687 src = p->bytes + p->offset;
1688 decode_ptr(&src, &pos);
1689 p->offset = src-(char*)p->bytes;
1690 isamb_pp_descend_to_leaf(pp, pos, untilbuf);
1692 yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
1693 "returning at lev %d node %d ofs=%d lf=%d",
1694 pp->level, p->pos, p->offset, p->leaf);
1696 } /* descend_to_leaf */
1698 static int isamb_pp_find_next_leaf(ISAMB_PP pp)
1699 { /* finds the next leaf by climbing up and down */
1701 if (!isamb_pp_climb_level(pp, &pos))
1703 isamb_pp_descend_to_leaf(pp, pos, 0);
1707 static int isamb_pp_climb_desc(ISAMB_PP pp, const void *untilbuf)
1708 { /* climbs up and descends to a leaf where values >= *untilbuf are found */
1711 struct ISAMB_block *p = pp->block[pp->level];
1712 yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc starting "
1713 "at level %d node %d ofs=%d sz=%d",
1714 pp->level, p->pos, p->offset, p->size);
1716 if (!isamb_pp_climb_level(pp, &pos))
1718 /* see if it would pay to climb one higher */
1719 if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
1720 if (!isamb_pp_climb_level(pp, &pos))
1722 isamb_pp_descend_to_leaf(pp, pos, untilbuf);
1724 p = pp->block[pp->level];
1725 yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc done "
1726 "at level %d node %d ofs=%d sz=%d",
1727 pp->level, p->pos, p->offset, p->size);
1732 int isamb_pp_forward (ISAMB_PP pp, void *buf, const void *untilbuf)
1735 struct ISAMB_block *p = pp->block[pp->level];
1737 yaz_log(YLOG_DEBUG, "isamb_pp_forward starting "
1738 "at level %d node %d ofs=%d sz=%d u=%p sc=%d",
1739 pp->level, p->pos, p->offset, p->size, untilbuf, scope);
1743 if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
1746 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (A) "
1747 "at level %d node %d ofs=%d sz=%d",
1748 pp->level, p->pos, p->offset, p->size);
1752 if (! isamb_pp_climb_desc(pp, untilbuf))
1755 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning notfound (B) "
1756 "at level %d node %d ofs=%d sz=%d",
1757 pp->level, p->pos, p->offset, p->size);
1759 return 0; /* could not find a leaf */
1762 if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
1765 yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (c) "
1766 "at level %d node %d ofs=%d sz=%d",
1767 pp->level, p->pos, p->offset, p->size);
1771 } while (isamb_pp_find_next_leaf(pp));
1772 return 0; /* could not find at all */
1774 else { /* no untilbuf, a straight read */
1775 /* FIXME - this should be moved
1776 * directly into the pp_read */
1777 /* keeping here now, to keep same
1778 * interface as the old fwd */
1779 if (isamb_pp_read_on_leaf(pp, buf))
1782 yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (D) "
1783 "at level %d node %d ofs=%d sz=%d",
1784 pp->level, p->pos, p->offset, p->size);
1788 if (isamb_pp_find_next_leaf(pp))
1791 yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (E) "
1792 "at level %d node %d ofs=%d sz=%d",
1793 pp->level, p->pos, p->offset, p->size);
1795 return isamb_pp_read_on_leaf(pp, buf);
1800 } /* isam_pp_forward (new version) */
1802 void isamb_pp_pos(ISAMB_PP pp, double *current, double *total)
1803 { /* return an estimate of the current position and of the total number of */
1804 /* occureences in the isam tree, based on the current leaf */
1808 /* if end-of-stream PP may not be leaf */
1810 *total = (double) (pp->block[0]->no_items);
1811 *current = (double) pp->returned_numbers;
1813 yaz_log(YLOG_LOG, "isamb_pp_pos returning: cur= %0.1f tot=%0.1f rn="
1814 ZINT_FORMAT, *current, *total, pp->returned_numbers);
1818 int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
1822 struct ISAMB_block *p = pp->block[pp->level];
1823 ISAMB b = pp->isamb;
1827 while (p->offset == p->size)
1833 char file_item_buf[DST_ITEM_MAX];
1834 char *file_item = file_item_buf;
1838 while (p->offset == p->size)
1842 close_block (pp->isamb, pp->block[pp->level]);
1843 pp->block[pp->level] = 0;
1845 p = pp->block[pp->level];
1850 src = p->bytes + p->offset;
1853 c1 = (*b->method->codec.start)();
1854 (*b->method->codec.decode)(c1, &file_item, &src);
1856 decode_ptr (&src, &item_len);
1859 decode_ptr (&src, &pos);
1860 p->offset = src - (char*) p->bytes;
1862 src = p->bytes + p->offset;
1866 if (!untilb || p->offset == p->size)
1868 assert(p->offset < p->size);
1871 file_item = file_item_buf;
1872 (*b->method->codec.reset)(c1);
1873 (*b->method->codec.decode)(c1, &file_item, &src);
1874 if ((*b->method->compare_item)(untilb, file_item_buf) <= 1)
1880 decode_item_len(&src, &item_len);
1881 if ((*b->method->compare_item)(untilb, src) <= 1)
1885 decode_ptr (&src, &pos);
1886 p->offset = src - (char*) p->bytes;
1893 pp->block[pp->level] = p = open_block (pp->isamb, pos);
1895 pp->total_size += p->size;
1903 src = p->bytes + p->offset;
1906 decode_ptr (&src, &pos);
1907 p->offset = src - (char*) p->bytes;
1909 if (!untilb || p->offset == p->size)
1911 assert(p->offset < p->size);
1914 file_item = file_item_buf;
1915 (*b->method->codec.reset)(c1);
1916 (*b->method->codec.decode)(c1, &file_item, &src);
1917 if ((*b->method->compare_item)(untilb, file_item_buf) <= 1)
1923 decode_ptr (&src, &item_len);
1924 if ((*b->method->compare_item)(untilb, src) <= 1)
1932 (*b->method->codec.stop)(c1);
1935 assert (p->offset < p->size);
1940 src = p->bytes + p->offset;
1941 (*pp->isamb->method->codec.decode)(p->decodeClientData, &dst, &src);
1942 p->offset = src - (char*) p->bytes;
1943 if (!untilb || (*pp->isamb->method->compare_item)(untilb, dst0) <= 1)
1946 if (p->offset == p->size) goto again;
1953 * indent-tabs-mode: nil
1955 * vim: shiftwidth=4 tabstop=8 expandtab