Remove isamd. It's not been in use for a long time and isamb is better
[idzebra-moved-to-github.git] / index / kinput.c
1 /* $Id: kinput.c,v 1.60 2004-08-04 08:35:23 adam Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
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
10 version.
11
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
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22  
23 #include <fcntl.h>
24 #ifdef WIN32
25 #include <io.h>
26 #else
27 #include <unistd.h>
28 #endif
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <assert.h>
33
34 #include "index.h"
35
36 #define KEY_SIZE (1+sizeof(struct it_key))
37 #define INP_NAME_MAX 768
38 #define INP_BUF_START 60000
39 #define INP_BUF_ADD  400000
40
41
42 struct key_file {
43     int   no;            /* file no */
44     off_t offset;        /* file offset */
45     unsigned char *buf;  /* buffer block */
46     size_t buf_size;     /* number of read bytes in block */
47     size_t chunk;        /* number of bytes allocated */
48     size_t buf_ptr;      /* current position in buffer */
49     char *prev_name;     /* last word read */
50 #if IT_KEY_NEW
51     void *decode_handle;
52 #else
53     int   sysno;         /* last sysno */
54     int   seqno;         /* last seqno */
55 #endif
56     off_t length;        /* length of file */
57                          /* handler invoked in each read */
58     void (*readHandler)(struct key_file *keyp, void *rinfo);
59     void *readInfo;
60     Res res;
61 };
62
63 void getFnameTmp (Res res, char *fname, int no)
64 {
65     const char *pre;
66     
67     pre = res_get_def (res, "keyTmpDir", ".");
68     sprintf (fname, "%s/key%d.tmp", pre, no);
69 }
70
71 void extract_get_fname_tmp (ZebraHandle zh, char *fname, int no)
72 {
73     const char *pre;
74     
75     pre = res_get_def (zh->res, "keyTmpDir", ".");
76     sprintf (fname, "%s/key%d.tmp", pre, no);
77 }
78
79 void key_file_chunk_read (struct key_file *f)
80 {
81     int nr = 0, r = 0, fd;
82     char fname[1024];
83     getFnameTmp (f->res, fname, f->no);
84     fd = open (fname, O_BINARY|O_RDONLY);
85
86     f->buf_ptr = 0;
87     f->buf_size = 0;
88     if (fd == -1)
89     {
90         logf (LOG_WARN|LOG_ERRNO, "cannot open %s", fname);
91         return ;
92     }
93     if (!f->length)
94     {
95         if ((f->length = lseek (fd, 0L, SEEK_END)) == (off_t) -1)
96         {
97             logf (LOG_WARN|LOG_ERRNO, "cannot seek %s", fname);
98             close (fd);
99             return ;
100         }
101     }
102     if (lseek (fd, f->offset, SEEK_SET) == -1)
103     {
104         logf (LOG_WARN|LOG_ERRNO, "cannot seek %s", fname);
105         close(fd);
106         return ;
107     }
108     while (f->chunk - nr > 0)
109     {
110         r = read (fd, f->buf + nr, f->chunk - nr);
111         if (r <= 0)
112             break;
113         nr += r;
114     }
115     if (r == -1)
116     {
117         logf (LOG_WARN|LOG_ERRNO, "read of %s", fname);
118         close (fd);
119         return;
120     }
121     f->buf_size = nr;
122     if (f->readHandler)
123         (*f->readHandler)(f, f->readInfo);
124     close (fd);
125 }
126
127 void key_file_destroy (struct key_file *f)
128 {
129 #if IT_KEY_NEW
130     iscz1_stop(f->decode_handle);
131 #endif
132     xfree (f->buf);
133     xfree (f->prev_name);
134     xfree (f);
135 }
136
137 struct key_file *key_file_init (int no, int chunk, Res res)
138 {
139     struct key_file *f;
140
141     f = (struct key_file *) xmalloc (sizeof(*f));
142     f->res = res;
143 #if IT_KEY_NEW
144     f->decode_handle = iscz1_start();
145 #else
146     f->sysno = 0;
147     f->seqno = 0;
148 #endif
149     f->no = no;
150     f->chunk = chunk;
151     f->offset = 0;
152     f->length = 0;
153     f->readHandler = NULL;
154     f->buf = (unsigned char *) xmalloc (f->chunk);
155     f->prev_name = (char *) xmalloc (INP_NAME_MAX);
156     *f->prev_name = '\0';
157     key_file_chunk_read (f);
158     return f;
159 }
160
161 int key_file_getc (struct key_file *f)
162 {
163     if (f->buf_ptr < f->buf_size)
164         return f->buf[(f->buf_ptr)++];
165     if (f->buf_size < f->chunk)
166         return EOF;
167     f->offset += f->buf_size;
168     key_file_chunk_read (f);
169     if (f->buf_ptr < f->buf_size)
170         return f->buf[(f->buf_ptr)++];
171     else
172         return EOF;
173 }
174
175 int key_file_decode (struct key_file *f)
176 {
177     int c, d;
178
179     c = key_file_getc (f);
180     switch (c & 192) 
181     {
182     case 0:
183         d = c;
184         break;
185     case 64:
186         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
187         break;
188     case 128:
189         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
190         d = (d << 8) + (key_file_getc (f) & 0xff);
191         break;
192     default: /* 192 */
193         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
194         d = (d << 8) + (key_file_getc (f) & 0xff);
195         d = (d << 8) + (key_file_getc (f) & 0xff);
196         break;
197     }
198     return d;
199 }
200
201 int key_file_read (struct key_file *f, char *key)
202 {
203     int i, c;
204     char srcbuf[128];
205 #if IT_KEY_NEW
206     const char *src = srcbuf;
207     char *dst;
208     int j;
209 #else
210     struct it_key itkey;
211     int d;
212 #endif
213
214     c = key_file_getc (f);
215     if (c == 0)
216     {
217         strcpy (key, f->prev_name);
218         i = 1+strlen (key);
219     }
220     else if (c == EOF)
221         return 0;
222     else
223     {
224         i = 0;
225         key[i++] = c;
226         while ((key[i++] = key_file_getc (f)))
227             ;
228         strcpy (f->prev_name, key);
229 #if IT_KEY_NEW
230         iscz1_reset(f->decode_handle);
231 #endif
232     }
233 #if IT_KEY_NEW
234     c = key_file_getc(f); /* length +  insert/delete combined */
235     key[i++] = c & 128;
236     c = c & 127;
237     for (j = 0; j < c; j++)
238         srcbuf[j] = key_file_getc(f);
239     dst = key + i;
240     iscz1_decode(f->decode_handle, &dst, &src);
241     return i + sizeof(struct it_key);
242 #else
243     d = key_file_decode (f);
244     key[i++] = d & 1;
245     d = d >> 1;
246     itkey.sysno = d + f->sysno;
247     if (d) 
248     {
249         f->sysno = itkey.sysno;
250         f->seqno = 0;
251     }
252     d = key_file_decode (f);
253     itkey.seqno = d + f->seqno;
254     f->seqno = itkey.seqno;
255     memcpy (key + i, &itkey, sizeof(struct it_key));
256     return i + sizeof (struct it_key);
257 #endif
258 }
259
260 struct heap_info {
261     struct {
262         struct key_file **file;
263         char   **buf;
264     } info;
265     int    heapnum;
266     int    *ptr;
267     int    (*cmp)(const void *p1, const void *p2);
268     struct zebra_register *reg;
269     ZebraHandle zh; /* only used for raw reading that bypasses the heaps */
270     int no_diffs;
271     int no_updates;
272     int no_deletions;
273     int no_insertions;
274     int no_iterations;
275 };
276
277 static struct heap_info *key_heap_malloc()
278 {  /* malloc and clear it */
279     struct heap_info *hi;
280     hi = (struct heap_info *) xmalloc (sizeof(*hi));
281     hi->info.file = 0;
282     hi->info.buf = 0;
283     hi->heapnum = 0;
284     hi->ptr = 0;
285     hi->zh=0;
286     hi->no_diffs = 0;
287     hi->no_diffs = 0;
288     hi->no_updates = 0;
289     hi->no_deletions = 0;
290     hi->no_insertions = 0;
291     hi->no_iterations = 0;
292     return hi;
293 }
294
295 struct heap_info *key_heap_init (int nkeys,
296                                  int (*cmp)(const void *p1, const void *p2))
297 {
298     struct heap_info *hi;
299     int i;
300
301     hi = key_heap_malloc();
302     hi->info.file = (struct key_file **)
303         xmalloc (sizeof(*hi->info.file) * (1+nkeys));
304     hi->info.buf = (char **) xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
305     hi->ptr = (int *) xmalloc (sizeof(*hi->ptr) * (1+nkeys));
306     hi->cmp = cmp;
307     for (i = 0; i<= nkeys; i++)
308     {
309         hi->ptr[i] = i;
310         hi->info.buf[i] = (char *) xmalloc (INP_NAME_MAX);
311     }
312     return hi;
313 }
314
315 struct heap_info *key_heap_init_buff ( ZebraHandle zh,
316                                  int (*cmp)(const void *p1, const void *p2))
317 {
318     struct heap_info *hi=key_heap_malloc();
319     hi->cmp=cmp;
320     hi->zh=zh;
321     return hi;
322 }
323
324 void key_heap_destroy (struct heap_info *hi, int nkeys)
325 {
326     int i;
327     yaz_log (LOG_DEBUG, "key_heap_destroy");
328     yaz_log (LOG_DEBUG, "key_heap_destroy nk=%d",nkeys);
329     if (!hi->zh)
330         for (i = 0; i<=nkeys; i++)
331             xfree (hi->info.buf[i]);
332     
333     xfree (hi->info.buf);
334     xfree (hi->ptr);
335     xfree (hi->info.file);
336     xfree (hi);
337 }
338
339 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
340 {
341     int swap;
342
343     swap = hi->ptr[i1];
344     hi->ptr[i1] = hi->ptr[i2];
345     hi->ptr[i2] = swap;
346 }
347
348
349 static void key_heap_delete (struct heap_info *hi)
350 {
351     int cur = 1, child = 2;
352
353     assert (hi->heapnum > 0);
354
355     key_heap_swap (hi, 1, hi->heapnum);
356     hi->heapnum--;
357     while (child <= hi->heapnum) {
358         if (child < hi->heapnum &&
359             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
360                        &hi->info.buf[hi->ptr[child+1]]) > 0)
361             child++;
362         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
363                        &hi->info.buf[hi->ptr[child]]) > 0)
364         {            
365             key_heap_swap (hi, cur, child);
366             cur = child;
367             child = 2*cur;
368         }
369         else
370             break;
371     }
372 }
373
374 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
375                              struct key_file *kf)
376 {
377     int cur, parent;
378
379     cur = ++(hi->heapnum);
380     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
381     hi->info.file[hi->ptr[cur]] = kf;
382
383     parent = cur/2;
384     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
385                                 &hi->info.buf[hi->ptr[cur]]) > 0)
386     {
387         key_heap_swap (hi, cur, parent);
388         cur = parent;
389         parent = cur/2;
390     }
391 }
392
393 static int heap_read_one_raw (struct heap_info *hi, char *name, char *key)
394 {
395     ZebraHandle zh=hi->zh;
396     size_t ptr_i = zh->reg->ptr_i;
397     char *cp;
398     if (!ptr_i)
399         return 0;
400     --(zh->reg->ptr_i);
401     cp=(zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
402     logf (LOG_DEBUG, " raw: i=%ld top=%ld cp=%p", (long) ptr_i,
403           (long) zh->reg->ptr_top, cp);
404     strcpy(name, cp);
405     memcpy(key, cp+strlen(name)+1, KEY_SIZE);
406     hi->no_iterations++;
407     return 1;
408 }
409
410 static int heap_read_one (struct heap_info *hi, char *name, char *key)
411 {
412     int n, r;
413     char rbuf[INP_NAME_MAX];
414     struct key_file *kf;
415
416     if (hi->zh) /* bypass the heap stuff, we have a readymade buffer */
417         return heap_read_one_raw(hi, name, key);
418
419     if (!hi->heapnum)
420         return 0;
421     n = hi->ptr[1];
422     strcpy (name, hi->info.buf[n]);
423     kf = hi->info.file[n];
424     r = strlen(name);
425     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
426     key_heap_delete (hi);
427     if ((r = key_file_read (kf, rbuf)))
428         key_heap_insert (hi, rbuf, r, kf);
429     hi->no_iterations++;
430     return 1;
431 }
432
433 #define PR_KEY 0
434
435 #if PR_KEY
436 static void pkey(const char *b, int mode)
437 {
438     struct it_key *key = (struct it_key *) b;
439     printf ("%c %d:%d\n", mode + 48, key->sysno, key->seqno);
440 }
441 #endif
442
443 struct heap_cread_info {
444     char prev_name[INP_NAME_MAX];
445     char cur_name[INP_NAME_MAX];
446     char *key;
447     char *key_1, *key_2;
448     int mode_1, mode_2;
449     int sz_1, sz_2;
450     struct heap_info *hi;
451     int first_in_list;
452     int more;
453     int ret;
454 };
455
456 static int heap_cread_item (void *vp, char **dst, int *insertMode);
457
458 int heap_cread_item2 (void *vp, char **dst, int *insertMode)
459 {
460     struct heap_cread_info *p = (struct heap_cread_info *) vp;
461     int level = 0;
462
463     if (p->ret == 0)    /* lookahead was 0?. Return that in read next round */
464     {
465         p->ret = -1;
466         return 0;
467     }
468     else if (p->ret == -1) /* Must read new item ? */
469     {
470         char *dst_1 = p->key_1;
471         p->ret = heap_cread_item(vp, &dst_1, &p->mode_1);
472         p->sz_1 = dst_1 - p->key_1;
473     }
474     else
475     {        /* lookahead in 2 . Now in 1. */
476         p->sz_1 = p->sz_2;
477         p->mode_1 = p->mode_2;
478         memcpy (p->key_1, p->key_2, p->sz_2);
479     }
480     if (p->mode_1)
481         level = 1;     /* insert */
482     else
483         level = -1;    /* delete */
484     while(1)
485     {
486         char *dst_2 = p->key_2;
487         p->ret = heap_cread_item(vp, &dst_2, &p->mode_2);
488         if (!p->ret)
489         {
490             if (level)
491                 break;
492             p->ret = -1;
493             return 0;
494         }
495         p->sz_2 = dst_2 - p->key_2;
496         if (p->sz_1 == p->sz_2 && memcmp(p->key_1, p->key_2, p->sz_1) == 0)
497         {
498             if (p->mode_2) /* adjust level according to deletes/inserts */
499                 level++;
500             else
501                 level--;
502         }
503         else
504         {
505             if (level)
506                 break;
507             /* all the same. new round .. */
508             p->sz_1 = p->sz_2;
509             p->mode_1 = p->mode_2;
510             memcpy (p->key_1, p->key_2, p->sz_1);
511             if (p->mode_1)
512                 level = 1;     /* insert */
513             else
514                 level = -1;    /* delete */
515         }
516     }
517     /* outcome is insert (1) or delete (0) depending on final level */
518     if (level > 0)
519         *insertMode = 1;
520     else
521         *insertMode = 0;
522     memcpy (*dst, p->key_1, p->sz_1);
523 #if PR_KEY
524     printf ("top: ");
525     pkey(*dst, *insertMode); fflush(stdout);
526 #endif
527     (*dst) += p->sz_1;
528     return 1;
529 }
530       
531 int heap_cread_item (void *vp, char **dst, int *insertMode)
532 {
533     struct heap_cread_info *p = (struct heap_cread_info *) vp;
534     struct heap_info *hi = p->hi;
535
536     if (p->first_in_list)
537     {
538         *insertMode = p->key[0];
539         memcpy (*dst, p->key+1, sizeof(struct it_key));
540 #if PR_KEY
541         printf ("sub1: ");
542         pkey(*dst, *insertMode);
543 #endif
544         (*dst) += sizeof(struct it_key);
545         p->first_in_list = 0;
546         return 1;
547     }
548     strcpy (p->prev_name, p->cur_name);
549     if (!(p->more = heap_read_one (hi, p->cur_name, p->key)))
550         return 0;
551     if (*p->cur_name && strcmp (p->cur_name, p->prev_name))
552     {
553         p->first_in_list = 1;
554         return 0;
555     }
556     *insertMode = p->key[0];
557     memcpy (*dst, p->key+1, sizeof(struct it_key));
558 #if PR_KEY
559     printf ("sub2: ");
560     pkey(*dst, *insertMode);
561 #endif
562     (*dst) += sizeof(struct it_key);
563     return 1;
564 }
565
566 int heap_inpc (struct heap_info *hi)
567 {
568     struct heap_cread_info hci;
569     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
570
571     hci.key = (char *) xmalloc (KEY_SIZE);
572     hci.key_1 = (char *) xmalloc (KEY_SIZE);
573     hci.key_2 = (char *) xmalloc (KEY_SIZE);
574     hci.ret = -1;
575     hci.first_in_list = 1;
576     hci.hi = hi;
577     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
578
579     isamc_i->clientData = &hci;
580     isamc_i->read_item = heap_cread_item2;
581
582     while (hci.more)
583     {
584         char this_name[INP_NAME_MAX];
585         ISAMC_P isamc_p, isamc_p2;
586         char *dict_info;
587
588         strcpy (this_name, hci.cur_name);
589         assert (hci.cur_name[1]);
590         hi->no_diffs++;
591         if ((dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
592         {
593             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
594             isamc_p2 = isc_merge (hi->reg->isamc, isamc_p, isamc_i);
595             if (!isamc_p2)
596             {
597                 hi->no_deletions++;
598                 if (!dict_delete (hi->reg->dict, this_name))
599                     abort();
600             }
601             else 
602             {
603                 hi->no_updates++;
604                 if (isamc_p2 != isamc_p)
605                     dict_insert (hi->reg->dict, this_name,
606                                  sizeof(ISAMC_P), &isamc_p2);
607             }
608         } 
609         else
610         {
611             isamc_p = isc_merge (hi->reg->isamc, 0, isamc_i);
612             hi->no_insertions++;
613             dict_insert (hi->reg->dict, this_name, sizeof(ISAMC_P), &isamc_p);
614         }
615     }
616     xfree (isamc_i);
617     xfree (hci.key);
618     xfree (hci.key_1);
619     xfree (hci.key_2);
620     return 0;
621
622
623 #if 0
624 /* for debugging only */
625 static void print_dict_item (ZebraMaps zm, const char *s)
626 {
627     int reg_type = s[1];
628     char keybuf[IT_MAX_WORD+1];
629     char *to = keybuf;
630     const char *from = s + 2;
631
632     while (*from)
633     {
634         const char *res = zebra_maps_output (zm, reg_type, &from);
635         if (!res)
636             *to++ = *from++;
637         else
638             while (*res)
639                 *to++ = *res++;
640     }
641     *to = '\0';
642     yaz_log (LOG_LOG, "%s", keybuf);
643 }
644 #endif
645
646 int heap_inpb (struct heap_info *hi)
647 {
648     struct heap_cread_info hci;
649     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
650
651     hci.key = (char *) xmalloc (KEY_SIZE);
652     hci.key_1 = (char *) xmalloc (KEY_SIZE);
653     hci.key_2 = (char *) xmalloc (KEY_SIZE);
654     hci.ret = -1;
655     hci.first_in_list = 1;
656     hci.hi = hi;
657     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
658
659     isamc_i->clientData = &hci;
660     isamc_i->read_item = heap_cread_item2;
661
662     while (hci.more)
663     {
664         char this_name[INP_NAME_MAX];
665         ISAMC_P isamc_p, isamc_p2;
666         char *dict_info;
667
668         strcpy (this_name, hci.cur_name);
669         assert (hci.cur_name[1]);
670         hi->no_diffs++;
671
672 #if 0
673         print_dict_item (hi->reg->zebra_maps, hci.cur_name);
674 #endif
675         if ((dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
676         {
677             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
678             isamc_p2 = isamb_merge (hi->reg->isamb, isamc_p, isamc_i);
679             if (!isamc_p2)
680             {
681                 hi->no_deletions++;
682                 if (!dict_delete (hi->reg->dict, this_name))
683                     abort();
684             }
685             else 
686             {
687                 hi->no_updates++;
688                 if (isamc_p2 != isamc_p)
689                     dict_insert (hi->reg->dict, this_name,
690                                  sizeof(ISAMC_P), &isamc_p2);
691             }
692         } 
693         else
694         {
695             isamc_p = isamb_merge (hi->reg->isamb, 0, isamc_i);
696             hi->no_insertions++;
697             dict_insert (hi->reg->dict, this_name, sizeof(ISAMC_P), &isamc_p);
698         }
699     }
700     xfree (isamc_i);
701     xfree (hci.key);
702     xfree (hci.key_1);
703     xfree (hci.key_2);
704     return 0;
705
706
707 int heap_inp (struct heap_info *hi)
708 {
709     char *info;
710     char next_name[INP_NAME_MAX];
711     char cur_name[INP_NAME_MAX];
712     int key_buf_size = INP_BUF_START;
713     int key_buf_ptr;
714     char *next_key;
715     char *key_buf;
716     int more;
717     
718     next_key = (char *) xmalloc (KEY_SIZE);
719     key_buf = (char *) xmalloc (key_buf_size);
720     more = heap_read_one (hi, cur_name, key_buf);
721     while (more)                   /* EOF ? */
722     {
723         int nmemb;
724         key_buf_ptr = KEY_SIZE;
725         while (1)
726         {
727             if (!(more = heap_read_one (hi, next_name, next_key)))
728                 break;
729             if (*next_name && strcmp (next_name, cur_name))
730                 break;
731             memcpy (key_buf + key_buf_ptr, next_key, KEY_SIZE);
732             key_buf_ptr += KEY_SIZE;
733             if (key_buf_ptr+(int) KEY_SIZE >= key_buf_size)
734             {
735                 char *new_key_buf;
736                 new_key_buf = (char *) xmalloc (key_buf_size + INP_BUF_ADD);
737                 memcpy (new_key_buf, key_buf, key_buf_size);
738                 key_buf_size += INP_BUF_ADD;
739                 xfree (key_buf);
740                 key_buf = new_key_buf;
741             }
742         }
743         hi->no_diffs++;
744         nmemb = key_buf_ptr / KEY_SIZE;
745         assert (nmemb * (int) KEY_SIZE == key_buf_ptr);
746         if ((info = dict_lookup (hi->reg->dict, cur_name)))
747         {
748             ISAM_P isam_p, isam_p2;
749             memcpy (&isam_p, info+1, sizeof(ISAM_P));
750             isam_p2 = is_merge (hi->reg->isam, isam_p, nmemb, key_buf);
751             if (!isam_p2)
752             {
753                 hi->no_deletions++;
754                 if (!dict_delete (hi->reg->dict, cur_name))
755                     abort ();
756             }
757             else 
758             {
759                 hi->no_updates++;
760                 if (isam_p2 != isam_p)
761                     dict_insert (hi->reg->dict, cur_name,
762                                  sizeof(ISAM_P), &isam_p2);
763             }
764         }
765         else
766         {
767             ISAM_P isam_p;
768             hi->no_insertions++;
769             isam_p = is_merge (hi->reg->isam, 0, nmemb, key_buf);
770             dict_insert (hi->reg->dict, cur_name, sizeof(ISAM_P), &isam_p);
771         }
772         memcpy (key_buf, next_key, KEY_SIZE);
773         strcpy (cur_name, next_name);
774     }
775     return 0;
776 }
777
778 int heap_inps (struct heap_info *hi)
779 {
780     struct heap_cread_info hci;
781     ISAMS_I isams_i = (ISAMS_I) xmalloc (sizeof(*isams_i));
782
783     hci.key = (char *) xmalloc (KEY_SIZE);
784     hci.key_1 = (char *) xmalloc (KEY_SIZE);
785     hci.key_2 = (char *) xmalloc (KEY_SIZE);
786     hci.first_in_list = 1;
787     hci.ret = -1;
788     hci.hi = hi;
789     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
790
791     isams_i->clientData = &hci;
792     isams_i->read_item = heap_cread_item;
793
794     while (hci.more)
795     {
796         char this_name[INP_NAME_MAX];
797         ISAMS_P isams_p;
798         char *dict_info;
799
800         strcpy (this_name, hci.cur_name);
801         assert (hci.cur_name[1]);
802         hi->no_diffs++;
803         if (!(dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
804         {
805             isams_p = isams_merge (hi->reg->isams, isams_i);
806             hi->no_insertions++;
807             dict_insert (hi->reg->dict, this_name, sizeof(ISAMS_P), &isams_p);
808         }
809         else
810         {
811             logf (LOG_FATAL, "isams doesn't support this kind of update");
812             break;
813         }
814     }
815     xfree (isams_i);
816     return 0;
817
818
819 struct progressInfo {
820     time_t   startTime;
821     time_t   lastTime;
822     off_t    totalBytes;
823     off_t    totalOffset;
824 };
825
826 void progressFunc (struct key_file *keyp, void *info)
827 {
828     struct progressInfo *p = (struct progressInfo *) info;
829     time_t now, remaining;
830
831     if (keyp->buf_size <= 0 || p->totalBytes <= 0)
832         return ;
833     time (&now);
834
835     if (now >= p->lastTime+10)
836     {
837         p->lastTime = now;
838         remaining = (time_t) ((now - p->startTime)*
839             ((double) p->totalBytes/p->totalOffset - 1.0));
840         if (remaining <= 130)
841             logf (LOG_LOG, "Merge %2.1f%% completed; %ld seconds remaining",
842                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining);
843         else
844             logf (LOG_LOG, "Merge %2.1f%% completed; %ld minutes remaining",
845                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining/60);
846     }
847     p->totalOffset += keyp->buf_size;
848 }
849
850 #ifndef R_OK
851 #define R_OK 4
852 #endif
853
854 void zebra_index_merge (ZebraHandle zh)
855 {
856     struct key_file **kf = 0;
857     char rbuf[1024];
858     int i, r;
859     struct heap_info *hi;
860     struct progressInfo progressInfo;
861     int nkeys = zh->reg->key_file_no;
862     int usefile; 
863     
864     logf (LOG_DEBUG, " index_merge called with nk=%d b=%p", 
865                     nkeys, zh->reg->key_buf);
866     if ( (nkeys==0) && (zh->reg->key_buf==0) )
867         return; /* nothing to merge - probably flush after end-trans */
868     
869     usefile = (nkeys!=0); 
870
871     if (usefile)
872     {
873         if (nkeys < 0)
874         {
875             char fname[1024];
876             nkeys = 0;
877             while (1)
878             {
879                 extract_get_fname_tmp  (zh, fname, nkeys+1);
880                 if (access (fname, R_OK) == -1)
881                         break;
882                 nkeys++;
883             }
884             if (!nkeys)
885                 return ;
886         }
887         kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
888         progressInfo.totalBytes = 0;
889         progressInfo.totalOffset = 0;
890         time (&progressInfo.startTime);
891         time (&progressInfo.lastTime);
892         for (i = 1; i<=nkeys; i++)
893         {
894             kf[i] = key_file_init (i, 8192, zh->res);
895             kf[i]->readHandler = progressFunc;
896             kf[i]->readInfo = &progressInfo;
897             progressInfo.totalBytes += kf[i]->length;
898             progressInfo.totalOffset += kf[i]->buf_size;
899         }
900         hi = key_heap_init (nkeys, key_qsort_compare);
901         hi->reg = zh->reg;
902         
903         for (i = 1; i<=nkeys; i++)
904             if ((r = key_file_read (kf[i], rbuf)))
905                 key_heap_insert (hi, rbuf, r, kf[i]);
906     }  /* use file */
907     else 
908     { /* do not use file, read straight from buffer */
909         hi = key_heap_init_buff (zh,key_qsort_compare);
910         hi->reg = zh->reg;
911     }
912     if (zh->reg->isams)
913         heap_inps (hi);
914     if (zh->reg->isamc)
915         heap_inpc (hi);
916     if (zh->reg->isam)
917         heap_inp (hi);
918     if (zh->reg->isamb)
919         heap_inpb (hi);
920         
921     if (usefile)
922     {
923         for (i = 1; i<=nkeys; i++)
924         {
925             extract_get_fname_tmp  (zh, rbuf, i);
926             unlink (rbuf);
927         }
928         for (i = 1; i<=nkeys; i++)
929             key_file_destroy (kf[i]);
930         xfree (kf);
931     }
932     if (hi->no_iterations)
933     { /* do not log if nothing happened */
934         logf (LOG_LOG, "Iterations . . .%7d", hi->no_iterations);
935         logf (LOG_LOG, "Distinct words .%7d", hi->no_diffs);
936         logf (LOG_LOG, "Updates. . . . .%7d", hi->no_updates);
937         logf (LOG_LOG, "Deletions. . . .%7d", hi->no_deletions);
938         logf (LOG_LOG, "Insertions . . .%7d", hi->no_insertions);
939     }
940     zh->reg->key_file_no = 0;
941
942     key_heap_destroy (hi, nkeys);
943 }