isamd write and read functions ok, except when diff block full.
[idzebra-moved-to-github.git] / isamc / merge-d.c
1 /*
2  * Copyright (c) 1996-1998, Index Data.
3  * See the file LICENSE for details.
4  * Heikki Levanto
5  *
6  * merge-d.c: merge routines for isamd
7  *
8  * todo
9  *  - merge when needed
10  *  - single-entry optimizing
11  *  - study and optimize block sizes (later)
12  *
13  * bugs
14  *  not yet ready
15  *
16  * caveat
17  *  There is aconfusion about the block addresses. cat or type is the category,
18  *  pos or block is the block number. pp structures keep these two separate,
19  *  and combine when saving the pp. The next pointer in the pp structure is
20  *  also a combined address, but needs to be combined every time it is needed,
21  *  and separated when the partss are needed... This is done with the isamd_
22  *  _block, _type, and _addr macros. The _addr takes block and type as args,
23  *  in that order. This conflicts with the order these are often mentioned in 
24  *  the debug log calls, and other places, leading to small mistakes here
25  *  and there. 
26  */
27
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <log.h>
33 #include "../index/index.h"
34 #include "isamd-p.h"
35
36
37 struct ISAMD_DIFF_s {
38   int diffidx;
39   int maxidx;
40   struct it_key key;
41   void *decodeData;
42   int mode;
43 };
44
45
46
47 static char *hexdump(unsigned char *p, int len, char *buff) {
48   static char localbuff[128];
49   char bytebuff[8];
50   if (!buff) buff=localbuff;
51   *buff='\0';
52   while (len--) {
53     sprintf(bytebuff,"%02x",*p);
54     p++;
55     strcat(buff,bytebuff);
56     if (len) strcat(buff,",");
57   }
58   return buff;
59 }
60
61
62 static int separateDiffBlock(ISAMD_PP pp)
63 {
64   return ( 0 != pp->next);
65 }
66
67
68 static void getDiffInfo(ISAMD_PP pp, int diffidx)
69 { /* builds the diff info structures from a diffblock */
70    int maxinfos = pp->is->method->filecat[pp->cat].bsize / 5 +1;
71     /* Each diff takes at least 5 bytes. Probably more, but this is safe */
72    int i=1;  /* [0] is used for the main data */
73    int diffsz= maxinfos * sizeof(struct ISAMD_DIFF_s);
74    pp->diffinfo = xmalloc( diffsz );
75    memset(pp->diffinfo,'\0',diffsz);
76    if (pp->is->method->debug > 4)
77      logf(LOG_LOG,"isamd_getDiffInfo: %d (%d:%d), ix=%d mx=%d",
78          isamd_addr(pp->pos, pp->cat), pp->cat, pp->pos, diffidx,maxinfos);
79
80    while (i<maxinfos) 
81    {  
82       if ( diffidx+sizeof(int) > pp->is->method->filecat[pp->cat].bsize )
83       {
84          if (pp->is->method->debug > 4)
85            logf(LOG_LOG,"isamd_getDiffInfo:Near end (no room for len) at ix=%d n=%d",
86                diffidx, i);
87          return; /* whole block done */
88       }
89       memcpy( &pp->diffinfo[i].maxidx, &pp->diffbuf[diffidx], sizeof(int) );
90       if (0==pp->diffinfo[i].maxidx)
91       {
92          if (pp->is->method->debug > 4)
93            logf(LOG_LOG,"isamd_getDiffInfo:End mark at ix=%d n=%d",
94                diffidx, i);
95          return; /* end marker */
96       }
97       diffidx += sizeof(int);
98       pp->diffinfo[i].decodeData = (*pp->is->method->code_start)(ISAMD_DECODE);
99       pp->diffinfo[i].diffidx = diffidx;
100       if (pp->is->method->debug > 4)
101         logf(LOG_LOG,"isamd_getDiff[%d]:%d-%d %s",
102           i,diffidx-sizeof(int),pp->diffinfo[i].maxidx,
103           hexdump((char *)&pp->diffbuf[diffidx-4],8,0) );
104       diffidx=pp->diffinfo[i].maxidx;
105       if ( diffidx > pp->is->method->filecat[pp->cat].bsize )
106         return; /* whole block done */
107       ++i;
108    }
109    assert ("too many diff sequences in the block");
110 }
111
112 static void loadDiffs(ISAMD_PP pp)
113 {  /* assumes pp is a firstblock! */
114    int diffidx;
115    int diffaddr;
116    if (0==pp->diffs)
117      return; /* no diffs to talk about */
118    if (pp->diffs & 1 )
119    { /* separate diff block, load it */
120       pp->diffbuf= xmalloc( pp->is->method->filecat[pp->cat].bsize);
121       diffaddr=pp->diffs/2;
122       isamd_read_block (pp->is, isamd_type(diffaddr), 
123                                 isamd_block(diffaddr), pp->diffbuf );
124       diffidx= ISAMD_BLOCK_OFFSET_N; 
125    }
126    else
127    { /* integrated block, just set the pointers */
128      pp->diffbuf = pp->buf;
129      diffidx = pp->size;  /* size is the beginning of diffs, diffidx the end*/
130    }
131    getDiffInfo(pp,diffidx);
132 } /* loadDiffs */
133
134
135 void isamd_free_diffs(ISAMD_PP pp)
136 {
137   int i;
138   if (!pp->diffinfo) 
139     return;
140   for (i=0;pp->diffinfo[i].decodeData;i++) 
141       (*pp->is->method->code_stop)(ISAMD_DECODE,pp->diffinfo[i].decodeData);    
142   xfree(pp->diffinfo);
143   if (pp->diffbuf != pp->buf)
144     xfree (pp->diffbuf);  
145 } /* isamd_free_diffs */
146
147
148 /* Reads one item and corrects for the diffs, if any */
149 /* return 1 for ok, 0 for eof */
150 int isamd_read_item (ISAMD_PP pp, char **dst)
151 {
152   char *keyptr;
153   char *codeptr;
154   char *codestart;
155   int winner=0; /* which diff holds the day */
156   int i; /* looping diffs */
157   int cmp;
158   int retry=1;
159   if (pp->diffs==0)  /* no diffs, just read the thing */
160      return isamd_read_main_item(pp,dst);
161
162   if (!pp->diffinfo)
163     loadDiffs(pp);
164   while (retry)
165   {
166      retry=0;
167      if (0==pp->diffinfo[0].key.sysno) 
168      { /* 0 is special case, main data. */
169         keyptr=(char*) &(pp->diffinfo[0].key);
170         pp->diffinfo[0].mode = ! isamd_read_main_item(pp,&keyptr);
171         if (pp->is->method->debug > 4)
172           logf(LOG_LOG,"isamd_read_item: read main %d.%d (%x.%x)",
173             pp->diffinfo[0].key.sysno, pp->diffinfo[0].key.seqno,
174             pp->diffinfo[0].key.sysno, pp->diffinfo[0].key.seqno);
175      } /* get main data */
176      winner = 0;
177      for (i=1; (!retry) && (pp->diffinfo[i].decodeData); i++)
178      {
179         if (pp->is->method->debug > 4)
180           logf(LOG_LOG,"isamd_read_item: considering d%d %d.%d ix=%d mx=%d",
181                i, pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
182                   pp->diffinfo[i].diffidx,   pp->diffinfo[i].maxidx);
183             
184         if ( (0==pp->diffinfo[i].key.sysno) &&
185              (pp->diffinfo[i].diffidx < pp->diffinfo[i].maxidx))
186         {/* read a new one, if possible */
187            codeptr= codestart = &(pp->diffbuf[pp->diffinfo[i].diffidx]);
188            keyptr=(char *)&(pp->diffinfo[i].key);
189            (*pp->is->method->code_item)(ISAMD_DECODE,
190                  pp->diffinfo[i].decodeData, &keyptr, &codeptr);
191            pp->diffinfo[i].diffidx += codeptr-codestart;
192            pp->diffinfo[i].mode = pp->diffinfo[i].key.seqno & 1;
193            pp->diffinfo[i].key.seqno = pp->diffinfo[i].key.seqno >>1 ;
194            if (pp->is->method->debug > 4)
195              logf(LOG_LOG,"isamd_read_item: read diff[%d] %d.%d (%x.%x)",i,
196                pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
197                pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno);
198         } 
199         if ( 0!= pp->diffinfo[i].key.sysno)
200         { /* got a key, compare */
201           cmp=key_compare(&pp->diffinfo[i].key, &pp->diffinfo[winner].key);
202           if (0==pp->diffinfo[winner].key.sysno)
203             cmp=-1; /* end of main sequence, take all diffs */
204           if (cmp<0)
205           {
206              if (pp->is->method->debug > 4)
207                logf(LOG_LOG,"isamd_read_item: ins %d<%d %d.%d (%x.%x) < %d.%d (%x.%x)",
208                  i, winner,
209                  pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
210                  pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
211                  pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno,
212                  pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno);
213              if (pp->diffinfo[i].mode)  /* insert diff, should always be */
214                winner = i;
215              else
216                assert("delete diff for nonexisting item");  
217                /* is an assert too steep here?*/
218           } /* earlier key */
219           else if (cmp==0)
220           {
221              if (!pp->diffinfo[i].mode) /* delete diff. should always be */
222              {
223                 if (pp->is->method->debug > 4)
224                   logf(LOG_LOG,"isamd_read_item: del %d at%d %d.%d (%x.%x)",
225                     i, winner,
226                     pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
227                     pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno);
228                 pp->diffinfo[winner].key.sysno=0; /* delete it */
229              }
230              else
231                 if (pp->is->method->debug > 4)
232                   logf(LOG_LOG,"isamd_read_item: duplicate ins %d at%d %d.%d (%x.%x)",
233                     i, winner,
234                     pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno,
235                     pp->diffinfo[i].key.sysno, pp->diffinfo[i].key.seqno);
236                 /* skip the insert, since we already have it in the base */
237              pp->diffinfo[i].key.sysno=0; /* done with the delete */
238              retry=1; /* start all over again */
239           } /* matching key */
240           /* else it is a later key, its turn will come */
241         } /* got a key */
242      } /* for each diff */
243   } /* not retry */
244
245   if ( pp->diffinfo[winner].key.sysno)
246   {
247     if (pp->is->method->debug > 4)
248       logf(LOG_LOG,"isamd_read_item: got %d  %d.%d (%x.%x)",
249         winner,
250         pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno,
251         pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno);
252     memcpy(*dst, &pp->diffinfo[winner].key, sizeof(struct it_key) );
253     *dst += sizeof(struct it_key);
254     pp->diffinfo[winner].key.sysno=0; /* used that one up */
255     cmp= 1;
256   } 
257   else 
258   {
259     if (pp->is->method->debug > 4)
260       logf(LOG_LOG,"isamd_read_item: eof w=%d  %d.%d (%x.%x)",
261         winner,
262         pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno,
263         pp->diffinfo[winner].key.sysno, pp->diffinfo[winner].key.seqno);
264     assert(winner==0); /* if nothing found, nothing comes from a diff */
265     cmp= 0; /* eof */
266   }
267   return cmp;
268    
269 } /* isamd_read_item */
270
271
272 static void isamd_reduceblock(ISAMD_PP pp)
273 /* takes a large block, and reduces its category if possible */
274 /* Presumably the first block in an isam-list */
275 {
276    if (pp->pos)
277       return; /* existing block, do not touch */
278    if (pp->is->method->debug > 2)
279      logf(LOG_LOG,"isamd_reduce: start p=%d c=%d sz=%d",
280        pp->pos, pp->cat, pp->size); 
281    while ( ( pp->cat > 0 ) && (!pp->next) && 
282            (pp->offset < pp->is->method->filecat[pp->cat-1].bsize ) )
283       pp->cat--;
284    pp->pos = isamd_alloc_block(pp->is, pp->cat);
285    if (pp->is->method->debug > 2)
286      logf(LOG_LOG,"isamd_reduce:  got  p=%d c=%d sz=%d",
287        pp->pos, pp->cat, pp->size);    
288 } /* reduceblock */
289
290
291 static int isamd_build_first_block(ISAMD is, ISAMD_I data) 
292 {
293    char i_item[128];    /* one input item */
294    char *i_ptr=i_item;
295    int i_more =1;
296    int i_mode;     /* 0 for delete, 1 for insert */ 
297
298    ISAMD_PP firstpp;
299    ISAMD_PP pp;
300    void *encoder_data;
301    int maxsize;
302    
303    char codebuff[128];
304    char *c_ptr = codebuff;
305    int codelen;
306    
307    char hexbuff[64];
308    int newblock;
309    int retval=0;
310    
311    firstpp=pp=isamd_pp_open(is, isamd_addr(0,is->max_cat));
312    firstpp->size = firstpp->offset = ISAMD_BLOCK_OFFSET_1;
313    encoder_data=(*is->method->code_start)(ISAMD_ENCODE);
314    maxsize = is->method->filecat[is->max_cat].bsize; 
315    
316    if (is->method->debug >3)
317       logf(LOG_LOG,"isamd_bld start: p=%d c=%d sz=%d maxsz=%d ",
318          pp->pos, pp->cat, pp->size, maxsize);
319
320    /* read first input */
321    i_ptr = i_item;
322    i_more = (*data->read_item)(data->clientData, &i_ptr, &i_mode); 
323
324    if (is->method->debug >3)
325       logf(LOG_LOG,"isamd: build_fi start: m=%d %s",
326          i_mode, hexdump(i_item,i_ptr-i_item,hexbuff) );
327
328    while (i_more)
329    { 
330       if (i_mode!=0) 
331       { /* ignore deletes here, should not happen */
332       
333          c_ptr=codebuff;
334          i_ptr=i_item;
335          (*is->method->code_item)(ISAMD_ENCODE, encoder_data, &c_ptr, &i_ptr);
336          codelen = c_ptr - codebuff;
337          assert ( (codelen<128) && (codelen>0));
338          if (is->method->debug >3)
339             logf(LOG_LOG,"isamd:build: coded into %s  (nk=%d)",
340                 hexdump(codebuff, c_ptr-codebuff,hexbuff), firstpp->numKeys+1);
341      
342          if (pp->offset + codelen > maxsize )
343          { /* oops, block full - get a new one */
344             if (firstpp==pp) 
345             { /* special case: it was the first block. Save much later */
346                if (0==firstpp->pos)
347                { /* firstpp not allocated yet, do so now, */
348                  /* to keep blocks in order. Don't save yet, though */
349                   firstpp->pos = isamd_alloc_block(is, firstpp->cat);
350                }
351                newblock = isamd_alloc_block(is, firstpp->cat);
352                firstpp->next = isamd_addr(newblock,firstpp->cat);
353                  /* keep the largest category */
354                pp=isamd_pp_open(is,isamd_addr(0,firstpp->cat));/*don't load*/
355                pp->pos=newblock; 
356                pp->size = pp->offset = ISAMD_BLOCK_OFFSET_N; 
357                pp->next=0;
358                if (is->method->debug >3)
359                   logf(LOG_LOG,"isamd_build: Alloc2 f=%d (%d:%d) n=%d(%d:%d)",
360                      isamd_addr(firstpp->pos,firstpp->cat), 
361                      firstpp->cat, firstpp->pos,
362                      isamd_addr(pp->pos,pp->cat), pp->cat, pp->pos );
363             }
364             else
365             { /* it was not the first block */
366                newblock = isamd_alloc_block(is, firstpp->cat);
367                pp->next = isamd_addr(newblock,firstpp->cat);
368                isamd_buildlaterblock(pp);
369                isamd_write_block(is,pp->cat,pp->pos,pp->buf);
370                pp->size = pp->offset = ISAMD_BLOCK_OFFSET_N;
371                pp->next=0;
372                pp->cat = firstpp->cat;
373                pp->pos = isamd_block(firstpp->next);
374             }
375             /* reset encoging and code again */
376             (*is->method->code_reset)(encoder_data);
377             c_ptr=codebuff;
378             i_ptr=i_item;
379             (*is->method->code_item)(ISAMD_ENCODE, encoder_data, &c_ptr, &i_ptr);
380             codelen = c_ptr - codebuff;
381             assert ( (codelen<128) && (codelen>0));
382             if (is->method->debug >3)
383                logf(LOG_LOG,"isamd:build: recoded into %s  (nk=%d)",
384                    hexdump(codebuff, c_ptr-codebuff,hexbuff), firstpp->numKeys+1);
385          } /* block full */    
386          
387          /* write the data into pp, now we have room */ 
388          memcpy(&(pp->buf[pp->offset]),codebuff,codelen);
389          pp->offset += codelen;
390          pp->size += codelen;
391          firstpp->numKeys++;
392       } /* not delete */
393       
394       /* (try to) read the next item */
395       i_ptr = i_item;
396       i_more = (*data->read_item)(data->clientData, &i_ptr, &i_mode); 
397       
398       if ( (i_more) && (is->method->debug >3) )
399          logf(LOG_LOG,"isamd: build_fi start: m=%d %s",
400             i_mode, hexdump(i_item,i_ptr-i_item,hexbuff) );
401       
402       
403    } /* i_more */
404
405    /* order of things: Better to save firstpp first, if there are just two */
406    /* blocks, but last if there are blocks in between, as these have already */
407    /* been saved... optimise later */
408
409    /* save the first block */
410    isamd_reduceblock(firstpp);
411    isamd_buildfirstblock(firstpp);
412    isamd_write_block(is,firstpp->cat,firstpp->pos,firstpp->buf);   
413    retval = isamd_addr(firstpp->pos,firstpp->cat);
414
415    if (firstpp!=pp){  /* and the last one */
416       pp->next = 0;/* just to be sure */
417       isamd_buildlaterblock(pp);
418       isamd_write_block(is,pp->cat,pp->pos,pp->buf);
419       isamd_pp_close(pp);
420    }
421
422    isamd_pp_close(firstpp);
423    
424    return retval;
425 } /* build_first_block */
426
427
428
429 static int append_diffs(ISAMD is, ISAMD_P ipos, ISAMD_I data)
430 {
431    struct it_key i_key;    /* one input item */
432    char *i_item = (char *) &i_key;  /* same as chars */
433    char *i_ptr=i_item;
434    int i_more =1;
435    int i_mode;     /* 0 for delete, 1 for insert */ 
436
437    ISAMD_PP firstpp;
438    ISAMD_PP pp;
439    void *encoder_data;
440    char hexbuff[64];
441    int retval=ipos;  /* by default we do not change the firstblock addr */
442    int diffidx=0;
443    int maxsize=0;
444    int difflenidx;
445    char codebuff[128];
446    char *c_ptr = codebuff;
447    int codelen;
448
449    pp=firstpp=isamd_pp_open(is, ipos);
450
451    /* TODO: Turn these ifs around! Check first diffs==0, and create new */
452    /* according to separateDiffBlock. if !=0, read according to its type */
453    /* bit. Much more robust this way around! */
454    
455    if (separateDiffBlock(firstpp))
456    { /* multi-block item, get the diff block */
457      if (firstpp->diffs==0) 
458      { /* allocate first diff block */
459        pp=isamd_pp_open(is,isamd_addr(0,firstpp->cat));
460        pp->pos = isamd_alloc_block(pp->is, pp->cat);
461        firstpp->diffs = pp->pos*2 +1;
462        diffidx = pp->size = pp->offset = ISAMD_BLOCK_OFFSET_N;
463        if (is->method->debug >3) 
464            logf(LOG_LOG,"isamd_appd: alloc diff  (%d) %d %d:%d ix=%d",
465                  firstpp->diffs,
466                  isamd_addr(pp->pos,pp->cat), pp->cat, pp->pos, 
467                  diffidx);
468      }
469      else
470      { /* find pointers within the existing block */
471         pp=isamd_pp_open(is, firstpp->diffs/2);
472         diffidx = pp->offset= pp->size;
473         if (is->method->debug >3) 
474            logf(LOG_LOG,"isamd_appd: load diff (%d) %d (%d:%d) ix=%d",
475                  firstpp->diffs,
476                  isamd_addr(pp->pos,pp->cat), pp->cat, pp->pos, 
477                  diffidx);
478      }
479    } 
480    else
481    { /* single-block item, get idx right */
482      diffidx= pp->diffs/2;
483      if (is->method->debug >3) 
484         logf(LOG_LOG,"isamd_appd: diffs in head %d (%d:%d) ix=%d sz=%d",
485                  isamd_addr(pp->pos,pp->cat), pp->cat, pp->pos, 
486                  diffidx, pp->size);
487      if (0==diffidx)
488      { /* no diffs yet, make them */
489         diffidx = pp->size;
490         pp->diffs = diffidx *2 +0;  
491      }
492    }
493    
494    encoder_data=(*is->method->code_start)(ISAMD_ENCODE);
495    maxsize = is->method->filecat[pp->cat].bsize; 
496    
497    difflenidx = diffidx;
498    diffidx+=sizeof(int);  /* difflen will be stored here */
499    
500    /* read first input */
501    i_ptr = i_item;
502    i_more = (*data->read_item)(data->clientData, &i_ptr, &i_mode); 
503
504    if (is->method->debug >3)
505       logf(LOG_LOG,"isamd_appd: start with m=%d %s",
506          i_mode, hexdump(i_item,i_ptr-i_item,hexbuff) );
507
508    while (i_more)
509    {     
510       assert( ((i_key.seqno<<1)>>1) == i_key.seqno); /* can spare the bit */
511       i_key.seqno = i_key.seqno * 2 + i_mode;
512       c_ptr=codebuff;
513       i_ptr=i_item;
514       (*is->method->code_item)(ISAMD_ENCODE, encoder_data, &c_ptr, &i_ptr);
515       codelen = c_ptr - codebuff;
516       assert ( (codelen<128) && (codelen>0));
517       if (is->method->debug >3)
518          logf(LOG_LOG,"isamd_appd: coded into %d: %s (nk=%d) (ix=%d)",
519              codelen, hexdump(codebuff, codelen,hexbuff), 
520              firstpp->numKeys,diffidx);
521
522       if (diffidx + codelen > maxsize )
523       { /* block full */
524          logf(LOG_LOG,"isamd_appd: block full (ix=%d mx=%d)",
525             diffidx, maxsize);
526          return 0;         /*!*/ /* do something about it!!! */
527       } /* block full */
528       
529       /* save the diff */ 
530       memcpy(&(pp->buf[diffidx]),codebuff,codelen);
531       diffidx += codelen;
532       if (i_mode)
533         firstpp->numKeys++; /* insert diff */
534       else
535         firstpp->numKeys--; /* delete diff */ 
536       memcpy(&(pp->buf[difflenidx]),&diffidx,sizeof(diffidx));
537       if (firstpp==pp)
538         firstpp->diffs =diffidx*2+0;
539       else
540         pp->size =diffidx;
541       
542       /* try to read the next input */
543       i_ptr = i_item;
544       i_more = (*data->read_item)(data->clientData, &i_ptr, &i_mode); 
545       if ( (i_more) && (is->method->debug >3) )
546          logf(LOG_LOG,"isamd_appd: got m=%d %s",
547             i_mode, hexdump(i_item,i_ptr-i_item,hexbuff) );
548    } /* more loop */
549
550    /* clear the next difflen, if room for such */
551    difflenidx = diffidx;
552    while ( (difflenidx-diffidx<=sizeof(int)) && (difflenidx<maxsize))
553      pp->buf[difflenidx++]='\0';
554    
555    /* ok, save the block(s) */
556    if (firstpp != pp) 
557    { /* save the diff block */
558       pp->next = 0;  /* just to be sure */
559       isamd_buildlaterblock(pp);
560       isamd_write_block(is,pp->cat,pp->pos,pp->buf);
561       isamd_pp_close(pp);
562    }
563
564    isamd_buildfirstblock(firstpp);
565    isamd_write_block(is,firstpp->cat,firstpp->pos,firstpp->buf);   
566    retval = isamd_addr(firstpp->pos,firstpp->cat);
567    isamd_pp_close(firstpp);
568
569    return retval;
570 } /* append_diffs */
571
572
573
574 ISAMD_P isamd_append (ISAMD is, ISAMD_P ipos, ISAMD_I data)
575 {
576    int retval=0;
577
578    if (0==ipos)
579       retval = isamd_build_first_block(is,data);
580    else
581       retval = append_diffs(is,ipos,data);
582
583    return retval;
584 } /*  isamd_append */
585
586
587 /*
588  * $Log: merge-d.c,v $
589  * Revision 1.3  1999-07-21 14:24:50  heikki
590  * isamd write and read functions ok, except when diff block full.
591  * (merge not yet done)
592  *
593  * Revision 1.1  1999/07/14 13:14:47  heikki
594  * Created empty
595  *
596  *
597  */
598
599
600
601