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