Bump copyright year
[idzebra-moved-to-github.git] / isamb / isamb.c
index 2b69426..cf96bb5 100644 (file)
@@ -1,8 +1,5 @@
-/* $Id: isamb.c,v 1.95 2007-11-28 10:38:10 adam Exp $
-   Copyright (C) 1995-2007
-   Index Data ApS
-
-This file is part of the Zebra server.
+/* This file is part of the Zebra server.
+   Copyright (C) 2004-2013 Index Data
 
 Zebra is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
@@ -20,6 +17,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 */
 
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 #include <yaz/log.h>
@@ -50,14 +50,17 @@ struct ISAMB_head {
 #define INT_ENCODE 1
 
 /* maximum size of encoded buffer */
-#define DST_ITEM_MAX 256
+#define DST_ITEM_MAX 5000
+
+/* max page size for _any_ isamb use */
+#define ISAMB_MAX_PAGE 32768
 
 #define ISAMB_MAX_LEVEL 10
 /* approx 2*max page + max size of item */
-#define DST_BUF_SIZE (2*4096+300)
+#define DST_BUF_SIZE (2*ISAMB_MAX_PAGE+DST_ITEM_MAX+100)
 
 /* should be maximum block size of multiple thereof */
-#define ISAMB_CACHE_ENTRY_SIZE 4096
+#define ISAMB_CACHE_ENTRY_SIZE ISAMB_MAX_PAGE
 
 /* CAT_MAX: _must_ be power of 2 */
 #define CAT_MAX 4
@@ -98,7 +101,7 @@ struct ISAMB_s {
     int log_io;        /* log level for bf_read/bf_write calls */
     int log_freelist;  /* log level for freelist handling */
     zint skipped_numbers; /* on a leaf node */
-    zint returned_numbers; 
+    zint returned_numbers;
     zint skipped_nodes[ISAMB_MAX_LEVEL]; /* [0]=skipped leaves, 1 = higher etc */
     zint accessed_nodes[ISAMB_MAX_LEVEL]; /* nodes we did not skip */
     zint number_of_int_splits;
@@ -133,7 +136,7 @@ struct ISAMB_PP_s {
     zint total_size;
     zint no_blocks;
     zint skipped_numbers; /* on a leaf node */
-    zint returned_numbers; 
+    zint returned_numbers;
     zint skipped_nodes[ISAMB_MAX_LEVEL]; /* [0]=skipped leaves, 1 = higher etc */
     zint accessed_nodes[ISAMB_MAX_LEVEL]; /* nodes we did not skip */
     struct ISAMB_block **block;
@@ -312,7 +315,7 @@ ISAMB isamb_open2(BFiles bfs, const char *name, int writeflag, ISAMC_M *method,
                pos++;
                if (!bf_read(isamb->file[i].bf, pos, 0, 0, hbuf + pos*sizes[i]))
                {
-                   yaz_log(YLOG_WARN, "truncated isamb header for " 
+                   yaz_log(YLOG_WARN, "truncated isamb header for "
                             "file=%s len=%d pos=%d",
                             fname, len, pos);
                     isamb_close(isamb);
@@ -349,7 +352,7 @@ ISAMB isamb_open(BFiles bfs, const char *name, int writeflag, ISAMC_M *method,
 {
     int sizes[CAT_NO];
     int i, b_size = ISAMB_MIN_SIZE;
-    
+
     for (i = 0; i<CAT_NO; i++)
     {
         sizes[i] = b_size;
@@ -379,7 +382,7 @@ static void flush_blocks(ISAMB b, int cat)
 static int cache_block(ISAMB b, ISAM_P pos, unsigned char *userbuf, int wr)
 {
     int cat = (int) (pos&CAT_MASK);
-    int off = (int) (((pos/CAT_MAX) & 
+    int off = (int) (((pos/CAT_MAX) &
                       (ISAMB_CACHE_ENTRY_SIZE / b->file[cat].head.block_size - 1))
                      * b->file[cat].head.block_size);
     zint norm = pos / (CAT_MASK*ISAMB_CACHE_ENTRY_SIZE / b->file[cat].head.block_size);
@@ -397,13 +400,13 @@ static int cache_block(ISAMB b, ISAM_P pos, unsigned char *userbuf, int wr)
         {
             ce_this = *ce;
             *ce = (*ce)->next;   /* remove from list */
-            
+
             ce_this->next = b->file[cat].cache_entries;  /* move to front */
             b->file[cat].cache_entries = ce_this;
-            
+
             if (wr)
             {
-                memcpy(ce_this->buf + off, userbuf, 
+                memcpy(ce_this->buf + off, userbuf,
                        b->file[cat].head.block_size);
                 ce_this->dirty = 1;
             }
@@ -510,9 +513,9 @@ void isamb_close(ISAMB isamb)
    0: leader byte, != 0 leaf, == 0, non-leaf
    1-2: used size of block
    3-7*: number of items and all children
-   
+
    * Reserve 5 bytes for large block sizes. 1 for small ones .. Number
-   of items. We can thus have at most 2^40 nodes. 
+   of items. We can thus have at most 2^40 nodes.
 */
 static struct ISAMB_block *open_block(ISAMB b, ISAM_P pos)
 {
@@ -569,6 +572,10 @@ struct ISAMB_block *new_block(ISAMB b, int leaf, int cat)
         zint block_no;
         block_no = b->file[cat].head.last_block++;
         p->pos = block_no * CAT_MAX + cat;
+        if (b->log_freelist)
+            yaz_log(b->log_freelist, "got block "
+                    ZINT_FORMAT " from last %d:" ZINT_FORMAT, p->pos,
+                    cat, p->pos/CAT_MAX);
     }
     else
     {
@@ -584,8 +591,10 @@ struct ISAMB_block *new_block(ISAMB b, int leaf, int cat)
                 zebra_exit("isamb:new_block");
             }
         }
-        yaz_log(b->log_freelist, "got block " ZINT_FORMAT " from freelist %d:" ZINT_FORMAT, p->pos,
-                cat, p->pos/CAT_MAX);
+        if (b->log_freelist)
+            yaz_log(b->log_freelist, "got block "
+                    ZINT_FORMAT " from freelist %d:" ZINT_FORMAT, p->pos,
+                    cat, p->pos/CAT_MAX);
         memcpy(&b->file[cat].head.free_list, p->buf, sizeof(zint));
     }
     p->cat = cat;
@@ -628,7 +637,7 @@ static void check_block(ISAMB b, struct ISAMB_block *p)
         char *endp = p->bytes + p->size;
         ISAM_P pos;
        void *c1 = (*b->method->codec.start)();
-            
+
         decode_ptr(&src, &pos);
         assert((pos&CAT_MASK) == p->cat);
         while (src != endp)
@@ -664,6 +673,7 @@ void close_block(ISAMB b, struct ISAMB_block *p)
                 p->pos, p->cat, p->pos/CAT_MAX);
         memcpy(p->buf, &b->file[p->cat].head.free_list, sizeof(zint));
         b->file[p->cat].head.free_list = p->pos;
+        b->file[p->cat].head_dirty = 1;
         if (!cache_block(b, p->pos, p->buf, 1))
         {
             yaz_log(b->log_io, "bf_write: close_block (deleted)");
@@ -676,7 +686,7 @@ void close_block(ISAMB b, struct ISAMB_block *p)
         int size = p->size + offset;
        char *dst =  (char*)p->buf + 3;
         assert(p->size >= 0);
-       
+
        /* memset becuase encode_ptr usually does not write all bytes */
        memset(p->buf, 0, b->file[p->cat].head.block_offset);
         p->buf[0] = p->leaf;
@@ -738,7 +748,7 @@ int insert_int(ISAMB b, struct ISAMB_block *p, void *lookahead_item,
             assert(sub_p1);
            diff_terms -= sub_p1->no_items;
             more = insert_sub(b, &sub_p1, lookahead_item, mode,
-                              stream, &sub_p2, 
+                              stream, &sub_p2,
                               sub_item, &sub_size, file_item_buf);
            diff_terms += sub_p1->no_items;
             src = src0;
@@ -754,7 +764,7 @@ int insert_int(ISAMB b, struct ISAMB_block *p, void *lookahead_item,
             assert(sub_p1);
            diff_terms -= sub_p1->no_items;
             more = insert_sub(b, &sub_p1, lookahead_item, mode,
-                              stream, &sub_p2, 
+                              stream, &sub_p2,
                               sub_item, &sub_size, src);
            diff_terms += sub_p1->no_items;
             src = src0;
@@ -770,7 +780,7 @@ int insert_int(ISAMB b, struct ISAMB_block *p, void *lookahead_item,
         sub_p1 = open_block(b, pos);
         assert(sub_p1);
        diff_terms -= sub_p1->no_items;
-        more = insert_sub(b, &sub_p1, lookahead_item, mode, stream, &sub_p2, 
+        more = insert_sub(b, &sub_p1, lookahead_item, mode, stream, &sub_p2,
                           sub_item, &sub_size, last_max_item);
        diff_terms += sub_p1->no_items;
     }
@@ -789,10 +799,10 @@ int insert_int(ISAMB b, struct ISAMB_block *p, void *lookahead_item,
 #if INT_ENCODE
        const char *sub_item_ptr = sub_item;
 #endif
-        assert(sub_size < 128 && sub_size > 1);
+        assert(sub_size < DST_ITEM_MAX && sub_size > 1);
 
         memcpy(dst, startp, src - startp);
-                
+
         dst += src - startp;
 
 #if INT_ENCODE
@@ -836,7 +846,7 @@ int insert_int(ISAMB b, struct ISAMB_block *p, void *lookahead_item,
             const char *half;
             src = dst_buf;
             endp = dst;
-            
+
             b->number_of_int_splits++;
 
            p->dirty = 1;
@@ -938,7 +948,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
     {
         char file_item_buf[DST_ITEM_MAX];
         char *file_item = file_item_buf;
-            
+
         src = p->bytes;
         endp = p->bytes + p->size;
         (*b->method->codec.decode)(c1, &file_item, &src);
@@ -948,12 +958,12 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
             char *lookahead_next;
            char *dst_0 = dst;
             int d = -1;
-            
+
             if (lookahead_item)
                 d = (*b->method->compare_item)(file_item_buf, lookahead_item);
-            
+
            /* d now holds comparison between existing file item and
-              lookahead item 
+              lookahead item
               d = 0: equal
                d > 0: lookahead before file
               d < 0: lookahead after file
@@ -971,7 +981,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
             }
             else if (d == 0 && *lookahead_mode == 2)
             {
-                /* For mode == 2, we insert the new key anyway - even 
+                /* For mode == 2, we insert the new key anyway - even
                    though the comparison is 0. */
                 dst_item = lookahead_item;
                 p->dirty = 1;
@@ -995,11 +1005,11 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
 
                /* encode the resulting item */
                 (*b->method->codec.encode)(c2, &dst, &dst_item);
-                
+
                 cut_item_size = dst_item - dst_item_0;
                assert(cut_item_size > 0);
                 memcpy(cut_item_buf, dst_item_0, cut_item_size);
-                
+
                 half2 = dst;
                no_items_1 = no_items;
                no_items++;
@@ -1012,7 +1022,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
            }
 
            /* now move "pointers" .. result has been encoded .. */
-            if (d > 0)  
+            if (d > 0)
             {
                /* we must move the lookahead pointer */
 
@@ -1039,7 +1049,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
                           leaf. Mark it as "gone" */
                         lookahead_item = 0;
                     }
-                    
+
                     p->dirty = 1;
                 }
             }
@@ -1080,7 +1090,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
         char *dst_item;
        const char *src = lookahead_item;
         char *dst_0 = dst;
-        
+
        /* if we have a lookahead item, we stop if we exceed the value of it */
         if (max_item &&
             (*b->method->compare_item)(max_item, lookahead_item) <= 0)
@@ -1098,13 +1108,13 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
         {
             const char *src_0 = src;
             half1 = dst; /* candidate for splitting */
-            
+
             (*b->method->codec.encode)(c2, &dst, &src);
-            
+
             cut_item_size = src - src_0;
            assert(cut_item_size > 0);
             memcpy(cut_item_buf, src_0, cut_item_size);
-            
+
            no_items_1 = no_items;
             half2 = dst;
         }
@@ -1128,7 +1138,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
         }
     }
     new_size = dst - dst_buf;
-    if (p && p->cat != b->no_cat-1 && 
+    if (p && p->cat != b->no_cat-1 &&
         new_size > b->file[p->cat].head.block_max)
     {
         /* non-btree block will be removed */
@@ -1156,7 +1166,7 @@ int insert_leaf(ISAMB b, struct ISAMB_block **sp1, void *lookahead_item,
         assert(half2);
 
        assert(cut_item_size > 0);
-       
+
        /* first half */
         p->size = half1 - dst_buf;
        assert(p->size <=  b->file[p->cat].head.block_max);
@@ -1204,7 +1214,7 @@ int insert_sub(ISAMB b, struct ISAMB_block **p, void *new_item,
                const void *max_item)
 {
     if (!*p || (*p)->leaf)
-        return insert_leaf(b, p, new_item, mode, stream, sp, sub_item, 
+        return insert_leaf(b, p, new_item, mode, stream, sp, sub_item,
                            sub_size, max_item);
     else
         return insert_int(b, *p, new_item, mode, stream, sp, sub_item,
@@ -1228,7 +1238,7 @@ int isamb_unlink(ISAMB b, ISAM_P pos)
 #endif
        decode_ptr(&src, &sub_p);
        isamb_unlink(b, sub_p);
-       
+
        while (src != p1->bytes + p1->size)
        {
 #if INT_ENCODE
@@ -1279,7 +1289,7 @@ void isamb_merge(ISAMB b, ISAM_P *pos, ISAMC_I *stream)
         struct ISAMB_block *p = 0, *sp = 0;
         char sub_item[DST_ITEM_MAX];
         int sub_size;
-        
+
         if (*pos)
             p = open_block(b, *pos);
         more = insert_sub(b, &p, item_buf, &i_mode, stream, &sp,
@@ -1294,7 +1304,7 @@ void isamb_merge(ISAMB b, ISAM_P *pos, ISAMC_I *stream)
 #endif
 
             encode_ptr(&dst, p->pos);
-           assert(sub_size < 128 && sub_size > 1);
+           assert(sub_size < DST_ITEM_MAX && sub_size > 1);
 #if INT_ENCODE
            (*b->method->codec.reset)(c1);
            (*b->method->codec.encode)(c1, &dst, &sub_item_ptr);
@@ -1304,7 +1314,7 @@ void isamb_merge(ISAMB b, ISAM_P *pos, ISAMC_I *stream)
             dst += sub_size;
 #endif
             encode_ptr(&dst, sp->pos);
-            
+
             p2->size = dst - p2->bytes;
            p2->no_items = p->no_items + sp->no_items;
             *pos = p2->pos;  /* return new super page */
@@ -1364,7 +1374,7 @@ ISAMB_PP isamb_pp_open_x(ISAMB isamb, ISAM_P pos, int *level, int scope)
         decode_ptr(&src, &pos);
         p->offset = src - p->bytes;
         pp->level++;
-        pp->accessed_nodes[pp->level]++; 
+        pp->accessed_nodes[pp->level]++;
     }
     pp->block[pp->level+1] = 0;
     pp->maxlevel = pp->level;
@@ -1383,7 +1393,7 @@ void isamb_pp_close_x(ISAMB_PP pp, zint *size, zint *blocks)
     int i;
     if (!pp)
         return;
-    yaz_log(YLOG_DEBUG, "isamb_pp_close lev=%d returned "ZINT_FORMAT" values, " 
+    yaz_log(YLOG_DEBUG, "isamb_pp_close lev=%d returned "ZINT_FORMAT" values, "
             "skipped "ZINT_FORMAT,
             pp->maxlevel, pp->skipped_numbers, pp->returned_numbers);
     for (i = pp->maxlevel; i>=0; i--)
@@ -1456,7 +1466,7 @@ static void isamb_dump_r(ISAMB b, ISAM_P pos, void (*pr)(const char *str),
            p->offset = src - (char*) p->bytes;
 
            isamb_dump_r(b, sub, pr, level+1);
-           
+
            while (p->offset < p->size)
            {
 #if INT_ENCODE
@@ -1473,11 +1483,11 @@ static void isamb_dump_r(ISAMB b, ISAM_P pos, void (*pr)(const char *str),
                src += item_len;
 #endif
                decode_ptr(&src, &sub);
-               
+
                p->offset = src - (char*) p->bytes;
-               
+
                isamb_dump_r(b, sub, pr, level+1);
-           }           
+           }
        }
        close_block(b, p);
     }
@@ -1494,417 +1504,12 @@ int isamb_pp_read(ISAMB_PP pp, void *buf)
 }
 
 
-static int isamb_pp_on_right_node(ISAMB_PP pp, int level, const void *untilbuf)
-{ /* looks one node higher to see if we should be on this node at all */
-  /* useful in backing off quickly, and in avoiding tail descends */
-  /* call with pp->level to begin with */
-    struct ISAMB_block *p;
-    int cmp;
-    const char *src;
-    ISAMB b = pp->isamb;
-
-    assert(level >= 0);
-    if (level == 0)
-    {
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true for root");
-#endif
-        return 1; /* we can never skip the root node */
-    }
-    level--;
-    p = pp->block[level];
-    assert(p->offset <= p->size);
-    if (p->offset < p->size)
-    {
-#if INT_ENCODE
-       char file_item_buf[DST_ITEM_MAX];
-       char *file_item = file_item_buf;
-       void *c1 = (*b->method->codec.start)();
-        assert(p->offset > 0); 
-        src = p->bytes + p->offset;
-        (*b->method->codec.decode)(c1, &file_item, &src);
-       (*b->method->codec.stop)(c1);
-       cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
-#else
-       zint item_len;
-        assert(p->offset > 0); 
-        src = p->bytes + p->offset;
-        decode_item_len(&src, &item_len);
-#if ISAMB_DEBUG
-        (*b->method->codec.log_item)(YLOG_DEBUG, untilbuf, "on_leaf: until");
-        (*b->method->codec.log_item)(YLOG_DEBUG, src, "on_leaf: value");
-#endif
-        cmp = (*b->method->compare_item)(untilbuf, src);
-#endif
-        if (cmp < pp->scope)
-       {  /* cmp<2 */
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning true "
-                    "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
-#endif
-            return 1; 
-        }
-        else
-       {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_on_right returning false "
-                    "cmp=%d lev=%d ofs=%d", cmp, level, p->offset);
-#endif
-            return 0; 
-        }
-    }
-    else {
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isamb_pp_on_right at tail, looking higher "
-                "lev=%d", level);
-#endif
-        return isamb_pp_on_right_node(pp, level, untilbuf);
-    }
-} /* isamb_pp_on_right_node */
-
-static int isamb_pp_read_on_leaf(ISAMB_PP pp, void *buf)
-{ 
-    /* reads the next item on the current leaf, returns 0 if end of leaf*/
-    struct ISAMB_block *p = pp->block[pp->level];
-    char *dst;
-    const char *src;
-    assert(pp);
-    assert(buf);
-    if (p->offset == p->size)
-    {
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isamb_pp_read_on_leaf returning 0 on "
-               "node %d", p->pos);
-#endif
-        return 0; /* at end of leaf */
-    }
-    src = p->bytes + p->offset;
-    dst = buf;
-    (*pp->isamb->method->codec.decode)(p->decodeClientData, &dst, &src);
-    p->offset = src - (char*) p->bytes;
-#if ISAMB_DEBUG
-    (*pp->isamb->method->codec.log_item)(YLOG_DEBUG, buf,
-                                        "read_on_leaf returning 1");
-#endif
-    pp->returned_numbers++;
-    return 1;
-} /* read_on_leaf */
-
-static int isamb_pp_forward_on_leaf(ISAMB_PP pp, void *buf, const void *untilbuf)
-{ /* forwards on the current leaf, returns 0 if not found */
-    int cmp;
-    int skips = 0;
-    while (1)
-    {
-        if (!isamb_pp_read_on_leaf(pp, buf))
-            return 0;
-        /* FIXME - this is an extra function call, inline the read? */
-        cmp=(*pp->isamb->method->compare_item)(untilbuf, buf);
-        if (cmp <pp->scope)
-       {  /* cmp<2  found a good one */
-#if ISAMB_DEBUG
-            if (skips)
-                yaz_log(YLOG_DEBUG, "isam_pp_fwd_on_leaf skipped %d items", skips);
-#endif
-            pp->returned_numbers++;
-            return 1;
-        }
-        if (!skips)
-            if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
-                return 0; /* never mind the rest of this leaf */
-        pp->skipped_numbers++;
-        skips++;
-    }
-} /* forward_on_leaf */
-
-static int isamb_pp_climb_level(ISAMB_PP pp, ISAM_P *pos)
-{ /* climbs higher in the tree, until finds a level with data left */
-  /* returns the node to (consider to) descend to in *pos) */
-    struct ISAMB_block *p = pp->block[pp->level];
-    const char *src;
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_climb_level starting "
-            "at level %d node %d ofs=%d sz=%d",
-            pp->level, p->pos, p->offset, p->size);
-#endif
-    assert(pp->level >= 0);
-    assert(p->offset <= p->size);
-    if (pp->level==0)
-    {
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isamb_pp_climb_level returning 0 at root");
-#endif
-        return 0;
-    }
-    assert(pp->level>0); 
-    close_block(pp->isamb, pp->block[pp->level]);
-    pp->block[pp->level] = 0;
-    (pp->level)--;
-    p = pp->block[pp->level];
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_climb_level climbed to level %d node %d ofs=%d",
-            pp->level, p->pos, p->offset);
-#endif
-    assert(!p->leaf);
-    assert(p->offset <= p->size);
-    if (p->offset == p->size)
-    {
-        /* we came from the last pointer, climb on */
-        if (!isamb_pp_climb_level(pp, pos))
-            return 0;
-        p = pp->block[pp->level];
-    }
-    else
-    {
-#if INT_ENCODE
-       char file_item_buf[DST_ITEM_MAX];
-       char *file_item = file_item_buf;
-        ISAMB b = pp->isamb;
-       void *c1 = (*b->method->codec.start)();
-#else
-       zint item_len;
-#endif
-        /* skip the child we just came from */
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isam_pp_climb_level: skipping lev=%d ofs=%d sz=%d", 
-                pp->level, p->offset, p->size);
-#endif
-        assert(p->offset < p->size);
-        src = p->bytes + p->offset;
-#if INT_ENCODE
-       (*b->method->codec.decode)(c1, &file_item, &src);
-       (*b->method->codec.stop)(c1);
-#else
-       decode_item_len(&src, &item_len);
-        src += item_len;
-#endif
-        decode_ptr(&src, pos);
-        p->offset = src - (char *)p->bytes;
-            
-    }
-    return 1;
-} /* climb_level */
-
-
-static zint isamb_pp_forward_unode(ISAMB_PP pp, zint pos, const void *untilbuf)
-{ /* scans a upper node until it finds a child <= untilbuf */
-  /* pp points to the key value, as always. pos is the child read from */
-  /* the buffer */
-  /* if all values are too small, returns the last child in the node */
-  /* FIXME - this can be detected, and avoided by looking at the */
-  /* parent node, but that gets messy. Presumably the cost is */
-  /* pretty low anyway */
-    ISAMB b = pp->isamb;
-    struct ISAMB_block *p = pp->block[pp->level];
-    const char *src = p->bytes + p->offset;
-    int cmp;
-    zint nxtpos;
-#if ISAMB_DEBUG
-    int skips = 0;
-    yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode starting "
-            "at level %d node %d ofs=%di sz=%d",
-            pp->level, p->pos, p->offset, p->size);
-#endif
-    assert(!p->leaf);
-    assert(p->offset <= p->size);
-    if (p->offset == p->size)
-    {
-#if ISAMB_DEBUG
-        yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at end "
-                "at level %d node %d ofs=%di sz=%d",
-                pp->level, p->pos, p->offset, p->size);
-#endif
-        return pos; /* already at the end of it */
-    }
-    while(p->offset < p->size)
-    {
-#if INT_ENCODE
-       char file_item_buf[DST_ITEM_MAX];
-       char *file_item = file_item_buf;
-       void *c1 = (*b->method->codec.start)();
-        (*b->method->codec.decode)(c1, &file_item, &src);
-       (*b->method->codec.stop)(c1);
-       cmp = (*b->method->compare_item)(untilbuf, file_item_buf);
-#else
-       zint item_len;
-        decode_item_len(&src, &item_len);
-        cmp = (*b->method->compare_item)(untilbuf, src);
-        src += item_len;
-#endif
-        decode_ptr(&src, &nxtpos);
-        if (cmp<pp->scope) /* cmp<2 */
-        {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning a hit "
-                    "at level %d node %d ofs=%d sz=%d",
-                    pp->level, p->pos, p->offset, p->size);
-#endif
-            return pos;
-        } /* found one */
-        pos = nxtpos;
-        p->offset = src-(char*)p->bytes;
-        (pp->skipped_nodes[pp->maxlevel - pp->level -1])++;
-#if ISAMB_DEBUG
-        skips++;
-#endif
-    }
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_forward_unode returning at tail "
-            "at level %d node %d ofs=%d sz=%d skips=%d",
-            pp->level, p->pos, p->offset, p->size, skips);
-#endif
-    return pos; /* that's the last one in the line */
-    
-} /* forward_unode */
-
-static void isamb_pp_descend_to_leaf(ISAMB_PP pp, ISAM_P pos,
-                                    const void *untilbuf)
-{ /* climbs down the tree, from pos, to the leftmost leaf */
-    struct ISAMB_block *p = pp->block[pp->level];
-    const char *src;
-    assert(!p->leaf);
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
-            "starting at lev %d node %d ofs=%d lf=%d u=%p", 
-            pp->level, p->pos, p->offset, p->leaf, untilbuf);
-#endif
-    if (untilbuf)
-        pos = isamb_pp_forward_unode(pp, pos, untilbuf);
-    ++(pp->level);
-    assert(pos);
-    p = open_block(pp->isamb, pos);
-    pp->block[pp->level] = p;
-    ++(pp->accessed_nodes[pp->maxlevel-pp->level]);
-    ++(pp->no_blocks);
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
-            "got lev %d node %d lf=%d", 
-            pp->level, p->pos, p->leaf);
-#endif
-    if (p->leaf)
-        return;
-    assert(p->offset==0);
-    src = p->bytes + p->offset;
-    decode_ptr(&src, &pos);
-    p->offset = src-(char*)p->bytes;
-    isamb_pp_descend_to_leaf(pp, pos, untilbuf);
-#if ISAMB_DEBUG
-    yaz_log(YLOG_DEBUG, "isamb_pp_descend_to_leaf "
-            "returning at lev %d node %d ofs=%d lf=%d", 
-            pp->level, p->pos, p->offset, p->leaf);
-#endif
-} /* descend_to_leaf */
-
-static int isamb_pp_find_next_leaf(ISAMB_PP pp)
-{ /* finds the next leaf by climbing up and down */
-    ISAM_P pos;
-    if (!isamb_pp_climb_level(pp, &pos))
-        return 0;
-    isamb_pp_descend_to_leaf(pp, pos, 0);
-    return 1;
-}
-
-static int isamb_pp_climb_desc(ISAMB_PP pp,  const void *untilbuf)
-{ /* climbs up and descends to a leaf where values >= *untilbuf are found */
-    ISAM_P pos;
-#if ISAMB_DEBUG
-    struct ISAMB_block *p = pp->block[pp->level];
-    yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc starting "
-            "at level %d node %d ofs=%d sz=%d",
-            pp->level, p->pos, p->offset, p->size);
-#endif
-    if (!isamb_pp_climb_level(pp, &pos))
-        return 0;
-    /* see if it would pay to climb one higher */
-    if (!isamb_pp_on_right_node(pp, pp->level, untilbuf))
-        if (!isamb_pp_climb_level(pp, &pos))
-            return 0;
-    isamb_pp_descend_to_leaf(pp, pos, untilbuf);
-#if ISAMB_DEBUG
-    p = pp->block[pp->level];
-    yaz_log(YLOG_DEBUG, "isamb_pp_climb_desc done "
-            "at level %d node %d ofs=%d sz=%d",
-            pp->level, p->pos, p->offset, p->size);
-#endif
-    return 1;
-} /* climb_desc */
-
-int isamb_pp_forward(ISAMB_PP pp, void *buf, const void *untilbuf)
-{
-#if ISAMB_DEBUG
-    struct ISAMB_block *p = pp->block[pp->level];
-    assert(p->leaf);
-    yaz_log(YLOG_DEBUG, "isamb_pp_forward starting "
-            "at level %d node %d ofs=%d sz=%d u=%p sc=%d",
-            pp->level, p->pos, p->offset, p->size, untilbuf, scope);
-#endif
-    if (untilbuf)
-    {
-        if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
-       {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (A) "
-                    "at level %d node %d ofs=%d sz=%d",
-                    pp->level, p->pos, p->offset, p->size);
-#endif
-            return 1;
-        }
-        if (! isamb_pp_climb_desc(pp, untilbuf))
-       {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning notfound (B) "
-                    "at level %d node %d ofs=%d sz=%d",
-                    pp->level, p->pos, p->offset, p->size);
-#endif
-            return 0; /* could not find a leaf */
-        }
-        do {
-            if (isamb_pp_forward_on_leaf(pp, buf, untilbuf))
-           {
-#if ISAMB_DEBUG
-               yaz_log(YLOG_DEBUG, "isamb_pp_forward (f) returning (c) "
-                       "at level %d node %d ofs=%d sz=%d",
-                       pp->level, p->pos, p->offset, p->size);
-#endif
-                return 1;
-            }
-        } while (isamb_pp_find_next_leaf(pp));
-        return 0; /* could not find at all */
-    }
-    else { /* no untilbuf, a straight read */
-        /* FIXME - this should be moved
-         * directly into the pp_read */
-        /* keeping here now, to keep same
-         * interface as the old fwd */
-        if (isamb_pp_read_on_leaf(pp, buf))
-       {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (D) "
-                    "at level %d node %d ofs=%d sz=%d",
-                    pp->level, p->pos, p->offset, p->size);
-#endif
-            return 1;
-        }
-        if (isamb_pp_find_next_leaf(pp))
-       {
-#if ISAMB_DEBUG
-            yaz_log(YLOG_DEBUG, "isamb_pp_forward (read) returning (E) "
-                    "at level %d node %d ofs=%d sz=%d",
-                    pp->level, p->pos, p->offset, p->size);
-#endif
-            return isamb_pp_read_on_leaf(pp, buf);
-        }
-        else
-            return 0;
-    }
-} /* isam_pp_forward (new version) */
-
 void isamb_pp_pos(ISAMB_PP pp, double *current, double *total)
 { /* return an estimate of the current position and of the total number of */
   /* occureences in the isam tree, based on the current leaf */
     assert(total);
     assert(current);
-    
+
     /* if end-of-stream PP may not be leaf */
 
     *total = (double) (pp->block[0]->no_items);
@@ -1915,7 +1520,7 @@ void isamb_pp_pos(ISAMB_PP pp, double *current, double *total)
 #endif
 }
 
-int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
+int isamb_pp_forward(ISAMB_PP pp, void *buf, const void *untilb)
 {
     char *dst = buf;
     const char *src;
@@ -1943,19 +1548,19 @@ int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
             pp->block[pp->level] = 0;
             (pp->level)--;
             p = pp->block[pp->level];
-            assert(!p->leaf);  
+            assert(!p->leaf);
         }
 
        assert(!p->leaf);
         src = p->bytes + p->offset;
-       
+
 #if INT_ENCODE
        c1 = (*b->method->codec.start)();
        (*b->method->codec.decode)(c1, &file_item, &src);
 #else
         decode_ptr(&src, &item_len);
         src += item_len;
-#endif        
+#endif
         decode_ptr(&src, &pos);
         p->offset = src - (char*) p->bytes;
 
@@ -1994,18 +1599,18 @@ int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
 
             pp->total_size += p->size;
             pp->no_blocks++;
-            
-            if (p->leaf) 
+
+            if (p->leaf)
             {
                 break;
             }
-           
+
             src = p->bytes + p->offset;
            while(1)
            {
                decode_ptr(&src, &pos);
                p->offset = src - (char*) p->bytes;
-               
+
                if (!untilb || p->offset == p->size)
                    break;
                assert(p->offset < p->size);
@@ -2045,6 +1650,7 @@ int isamb_pp_forward2(ISAMB_PP pp, void *buf, const void *untilb)
        dst = dst0;
        if (p->offset == p->size) goto again;
     }
+    pp->returned_numbers++;
     return 1;
 }
 
@@ -2072,6 +1678,7 @@ void isamb_set_root_ptr(ISAMB b, zint root_ptr)
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab