72eef0915bdcc79dd4c8ea1a958c46329fe369d1
[idzebra-moved-to-github.git] / index / kinput.c
1 /* $Id: kinput.c,v 1.59 2004-06-15 10:56:31 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 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
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     else if (c == EOF)
204         return 0;
205     else
206     {
207         i = 0;
208         key[i++] = c;
209         while ((key[i++] = key_file_getc (f)))
210             ;
211         strcpy (f->prev_name, key);
212         f->sysno = 0;
213     }
214     d = key_file_decode (f);
215     key[i++] = d & 1;
216     d = d >> 1;
217     itkey.sysno = d + f->sysno;
218     if (d) 
219     {
220         f->sysno = itkey.sysno;
221         f->seqno = 0;
222     }
223     d = key_file_decode (f);
224     itkey.seqno = d + f->seqno;
225     f->seqno = itkey.seqno;
226     memcpy (key + i, &itkey, sizeof(struct it_key));
227     return i + sizeof (struct it_key);
228 }
229
230 struct heap_info {
231     struct {
232         struct key_file **file;
233         char   **buf;
234     } info;
235     int    heapnum;
236     int    *ptr;
237     int    (*cmp)(const void *p1, const void *p2);
238     struct zebra_register *reg;
239     ZebraHandle zh; /* only used for raw reading that bypasses the heaps */
240     int no_diffs;
241     int no_updates;
242     int no_deletions;
243     int no_insertions;
244     int no_iterations;
245 };
246
247 static struct heap_info *key_heap_malloc()
248 {  /* malloc and clear it */
249     struct heap_info *hi;
250     hi = (struct heap_info *) xmalloc (sizeof(*hi));
251     hi->info.file = 0;
252     hi->info.buf = 0;
253     hi->heapnum = 0;
254     hi->ptr = 0;
255     hi->zh=0;
256     hi->no_diffs = 0;
257     hi->no_diffs = 0;
258     hi->no_updates = 0;
259     hi->no_deletions = 0;
260     hi->no_insertions = 0;
261     hi->no_iterations = 0;
262     return hi;
263 }
264
265 struct heap_info *key_heap_init (int nkeys,
266                                  int (*cmp)(const void *p1, const void *p2))
267 {
268     struct heap_info *hi;
269     int i;
270
271     hi = key_heap_malloc();
272     hi->info.file = (struct key_file **)
273         xmalloc (sizeof(*hi->info.file) * (1+nkeys));
274     hi->info.buf = (char **) xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
275     hi->ptr = (int *) xmalloc (sizeof(*hi->ptr) * (1+nkeys));
276     hi->cmp = cmp;
277     for (i = 0; i<= nkeys; i++)
278     {
279         hi->ptr[i] = i;
280         hi->info.buf[i] = (char *) xmalloc (INP_NAME_MAX);
281     }
282     return hi;
283 }
284
285 struct heap_info *key_heap_init_buff ( ZebraHandle zh,
286                                  int (*cmp)(const void *p1, const void *p2))
287 {
288     struct heap_info *hi=key_heap_malloc();
289     hi->cmp=cmp;
290     hi->zh=zh;
291     return hi;
292 }
293
294 void key_heap_destroy (struct heap_info *hi, int nkeys)
295 {
296     int i;
297     yaz_log (LOG_DEBUG, "key_heap_destroy");
298     yaz_log (LOG_DEBUG, "key_heap_destroy nk=%d",nkeys);
299     if (!hi->zh)
300         for (i = 0; i<=nkeys; i++)
301             xfree (hi->info.buf[i]);
302     
303     xfree (hi->info.buf);
304     xfree (hi->ptr);
305     xfree (hi->info.file);
306     xfree (hi);
307 }
308
309 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
310 {
311     int swap;
312
313     swap = hi->ptr[i1];
314     hi->ptr[i1] = hi->ptr[i2];
315     hi->ptr[i2] = swap;
316 }
317
318
319 static void key_heap_delete (struct heap_info *hi)
320 {
321     int cur = 1, child = 2;
322
323     assert (hi->heapnum > 0);
324
325     key_heap_swap (hi, 1, hi->heapnum);
326     hi->heapnum--;
327     while (child <= hi->heapnum) {
328         if (child < hi->heapnum &&
329             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
330                        &hi->info.buf[hi->ptr[child+1]]) > 0)
331             child++;
332         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
333                        &hi->info.buf[hi->ptr[child]]) > 0)
334         {            
335             key_heap_swap (hi, cur, child);
336             cur = child;
337             child = 2*cur;
338         }
339         else
340             break;
341     }
342 }
343
344 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
345                              struct key_file *kf)
346 {
347     int cur, parent;
348
349     cur = ++(hi->heapnum);
350     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
351     hi->info.file[hi->ptr[cur]] = kf;
352
353     parent = cur/2;
354     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
355                                 &hi->info.buf[hi->ptr[cur]]) > 0)
356     {
357         key_heap_swap (hi, cur, parent);
358         cur = parent;
359         parent = cur/2;
360     }
361 }
362
363 static int heap_read_one_raw (struct heap_info *hi, char *name, char *key)
364 {
365     ZebraHandle zh=hi->zh;
366     size_t ptr_i = zh->reg->ptr_i;
367     char *cp;
368     if (!ptr_i)
369         return 0;
370     --(zh->reg->ptr_i);
371     cp=(zh->reg->key_buf)[zh->reg->ptr_top - ptr_i];
372     logf (LOG_DEBUG, " raw: i=%ld top=%ld cp=%p", (long) ptr_i,
373           (long) zh->reg->ptr_top, cp);
374     strcpy(name, cp);
375     memcpy(key, cp+strlen(name)+1, KEY_SIZE);
376     hi->no_iterations++;
377     return 1;
378 }
379
380 static int heap_read_one (struct heap_info *hi, char *name, char *key)
381 {
382     int n, r;
383     char rbuf[INP_NAME_MAX];
384     struct key_file *kf;
385
386     if (hi->zh) /* bypass the heap stuff, we have a readymade buffer */
387         return heap_read_one_raw(hi, name, key);
388
389     if (!hi->heapnum)
390         return 0;
391     n = hi->ptr[1];
392     strcpy (name, hi->info.buf[n]);
393     kf = hi->info.file[n];
394     r = strlen(name);
395     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
396     key_heap_delete (hi);
397     if ((r = key_file_read (kf, rbuf)))
398         key_heap_insert (hi, rbuf, r, kf);
399     hi->no_iterations++;
400     return 1;
401 }
402
403 #define PR_KEY 0
404
405 #if PR_KEY
406 static void pkey(const char *b, int mode)
407 {
408     struct it_key *key = (struct it_key *) b;
409     printf ("%c %d:%d\n", mode + 48, key->sysno, key->seqno);
410 }
411 #endif
412
413 struct heap_cread_info {
414     char prev_name[INP_NAME_MAX];
415     char cur_name[INP_NAME_MAX];
416     char *key;
417     char *key_1, *key_2;
418     int mode_1, mode_2;
419     int sz_1, sz_2;
420     struct heap_info *hi;
421     int first_in_list;
422     int more;
423     int ret;
424 };
425
426 static int heap_cread_item (void *vp, char **dst, int *insertMode);
427
428 int heap_cread_item2 (void *vp, char **dst, int *insertMode)
429 {
430     struct heap_cread_info *p = (struct heap_cread_info *) vp;
431     int level = 0;
432
433     if (p->ret == 0)    /* lookahead was 0?. Return that in read next round */
434     {
435         p->ret = -1;
436         return 0;
437     }
438     else if (p->ret == -1) /* Must read new item ? */
439     {
440         char *dst_1 = p->key_1;
441         p->ret = heap_cread_item(vp, &dst_1, &p->mode_1);
442         p->sz_1 = dst_1 - p->key_1;
443     }
444     else
445     {        /* lookahead in 2 . Now in 1. */
446         p->sz_1 = p->sz_2;
447         p->mode_1 = p->mode_2;
448         memcpy (p->key_1, p->key_2, p->sz_2);
449     }
450     if (p->mode_1)
451         level = 1;     /* insert */
452     else
453         level = -1;    /* delete */
454     while(1)
455     {
456         char *dst_2 = p->key_2;
457         p->ret = heap_cread_item(vp, &dst_2, &p->mode_2);
458         if (!p->ret)
459         {
460             if (level)
461                 break;
462             p->ret = -1;
463             return 0;
464         }
465         p->sz_2 = dst_2 - p->key_2;
466         if (p->sz_1 == p->sz_2 && memcmp(p->key_1, p->key_2, p->sz_1) == 0)
467         {
468             if (p->mode_2) /* adjust level according to deletes/inserts */
469                 level++;
470             else
471                 level--;
472         }
473         else
474         {
475             if (level)
476                 break;
477             /* all the same. new round .. */
478             p->sz_1 = p->sz_2;
479             p->mode_1 = p->mode_2;
480             memcpy (p->key_1, p->key_2, p->sz_1);
481             if (p->mode_1)
482                 level = 1;     /* insert */
483             else
484                 level = -1;    /* delete */
485         }
486     }
487     /* outcome is insert (1) or delete (0) depending on final level */
488     if (level > 0)
489         *insertMode = 1;
490     else
491         *insertMode = 0;
492     memcpy (*dst, p->key_1, p->sz_1);
493 #if PR_KEY
494     printf ("top: ");
495     pkey(*dst, *insertMode); fflush(stdout);
496 #endif
497     (*dst) += p->sz_1;
498     return 1;
499 }
500       
501 int heap_cread_item (void *vp, char **dst, int *insertMode)
502 {
503     struct heap_cread_info *p = (struct heap_cread_info *) vp;
504     struct heap_info *hi = p->hi;
505
506     if (p->first_in_list)
507     {
508         *insertMode = p->key[0];
509         memcpy (*dst, p->key+1, sizeof(struct it_key));
510 #if PR_KEY
511         printf ("sub1: ");
512         pkey(*dst, *insertMode);
513 #endif
514         (*dst) += sizeof(struct it_key);
515         p->first_in_list = 0;
516         return 1;
517     }
518     strcpy (p->prev_name, p->cur_name);
519     if (!(p->more = heap_read_one (hi, p->cur_name, p->key)))
520         return 0;
521     if (*p->cur_name && strcmp (p->cur_name, p->prev_name))
522     {
523         p->first_in_list = 1;
524         return 0;
525     }
526     *insertMode = p->key[0];
527     memcpy (*dst, p->key+1, sizeof(struct it_key));
528 #if PR_KEY
529     printf ("sub2: ");
530     pkey(*dst, *insertMode);
531 #endif
532     (*dst) += sizeof(struct it_key);
533     return 1;
534 }
535
536 int heap_inpc (struct heap_info *hi)
537 {
538     struct heap_cread_info hci;
539     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
540
541     hci.key = (char *) xmalloc (KEY_SIZE);
542     hci.key_1 = (char *) xmalloc (KEY_SIZE);
543     hci.key_2 = (char *) xmalloc (KEY_SIZE);
544     hci.ret = -1;
545     hci.first_in_list = 1;
546     hci.hi = hi;
547     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
548
549     isamc_i->clientData = &hci;
550     isamc_i->read_item = heap_cread_item2;
551
552     while (hci.more)
553     {
554         char this_name[INP_NAME_MAX];
555         ISAMC_P isamc_p, isamc_p2;
556         char *dict_info;
557
558         strcpy (this_name, hci.cur_name);
559         assert (hci.cur_name[1]);
560         hi->no_diffs++;
561         if ((dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
562         {
563             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
564             isamc_p2 = isc_merge (hi->reg->isamc, isamc_p, isamc_i);
565             if (!isamc_p2)
566             {
567                 hi->no_deletions++;
568                 if (!dict_delete (hi->reg->dict, this_name))
569                     abort();
570             }
571             else 
572             {
573                 hi->no_updates++;
574                 if (isamc_p2 != isamc_p)
575                     dict_insert (hi->reg->dict, this_name,
576                                  sizeof(ISAMC_P), &isamc_p2);
577             }
578         } 
579         else
580         {
581             isamc_p = isc_merge (hi->reg->isamc, 0, isamc_i);
582             hi->no_insertions++;
583             dict_insert (hi->reg->dict, this_name, sizeof(ISAMC_P), &isamc_p);
584         }
585     }
586     xfree (isamc_i);
587     xfree (hci.key);
588     xfree (hci.key_1);
589     xfree (hci.key_2);
590     return 0;
591
592
593 #if 0
594 /* for debugging only */
595 static void print_dict_item (ZebraMaps zm, const char *s)
596 {
597     int reg_type = s[1];
598     char keybuf[IT_MAX_WORD+1];
599     char *to = keybuf;
600     const char *from = s + 2;
601
602     while (*from)
603     {
604         const char *res = zebra_maps_output (zm, reg_type, &from);
605         if (!res)
606             *to++ = *from++;
607         else
608             while (*res)
609                 *to++ = *res++;
610     }
611     *to = '\0';
612     yaz_log (LOG_LOG, "%s", keybuf);
613 }
614 #endif
615
616 int heap_inpb (struct heap_info *hi)
617 {
618     struct heap_cread_info hci;
619     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
620
621     hci.key = (char *) xmalloc (KEY_SIZE);
622     hci.key_1 = (char *) xmalloc (KEY_SIZE);
623     hci.key_2 = (char *) xmalloc (KEY_SIZE);
624     hci.ret = -1;
625     hci.first_in_list = 1;
626     hci.hi = hi;
627     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
628
629     isamc_i->clientData = &hci;
630     isamc_i->read_item = heap_cread_item2;
631
632     while (hci.more)
633     {
634         char this_name[INP_NAME_MAX];
635         ISAMC_P isamc_p, isamc_p2;
636         char *dict_info;
637
638         strcpy (this_name, hci.cur_name);
639         assert (hci.cur_name[1]);
640         hi->no_diffs++;
641
642 #if 0
643         print_dict_item (hi->reg->zebra_maps, hci.cur_name);
644 #endif
645         if ((dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
646         {
647             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
648             isamc_p2 = isamb_merge (hi->reg->isamb, isamc_p, isamc_i);
649             if (!isamc_p2)
650             {
651                 hi->no_deletions++;
652                 if (!dict_delete (hi->reg->dict, this_name))
653                     abort();
654             }
655             else 
656             {
657                 hi->no_updates++;
658                 if (isamc_p2 != isamc_p)
659                     dict_insert (hi->reg->dict, this_name,
660                                  sizeof(ISAMC_P), &isamc_p2);
661             }
662         } 
663         else
664         {
665             isamc_p = isamb_merge (hi->reg->isamb, 0, isamc_i);
666             hi->no_insertions++;
667             dict_insert (hi->reg->dict, this_name, sizeof(ISAMC_P), &isamc_p);
668         }
669     }
670     xfree (isamc_i);
671     xfree (hci.key);
672     xfree (hci.key_1);
673     xfree (hci.key_2);
674     return 0;
675
676
677 int heap_inpd (struct heap_info *hi)
678 {
679     struct heap_cread_info hci;
680     ISAMD_I isamd_i = (ISAMD_I) xmalloc (sizeof(*isamd_i));
681
682     hci.key = (char *) xmalloc (KEY_SIZE);
683     hci.key_1 = (char *) xmalloc (KEY_SIZE);
684     hci.key_2 = (char *) xmalloc (KEY_SIZE);
685     hci.ret = -1;
686     hci.first_in_list = 1;
687     hci.hi = hi;
688     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
689
690     isamd_i->clientData = &hci;
691     isamd_i->read_item = heap_cread_item;
692
693     while (hci.more)
694     {
695         char this_name[INP_NAME_MAX];
696         char *dict_info;
697         char dictentry[ISAMD_MAX_DICT_LEN+1];
698         char dictlen;
699
700         strcpy (this_name, hci.cur_name);
701         
702         /* print_dict_item (hi->reg->zebra_maps, hci.cur_name); */
703         /*!*/ /* FIXME: depend on isamd-debug */
704
705         assert (hci.cur_name[1]);
706         hi->no_diffs++;
707         if ((dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
708         {
709             dictlen=dict_info[0];
710             memcpy (dictentry, dict_info+1, dictlen );
711 #ifdef SKIPTHIS
712             logf(LOG_LOG,"dictentry before. len=%d: %d %d %d %d %d %d %d %d %d",
713                dictlen,dictentry[0], dictentry[1], dictentry[2],
714                        dictentry[3], dictentry[4], dictentry[5],
715                        dictentry[6], dictentry[7], dictentry[8]); /*!*/
716 #endif
717             dictlen= isamd_append(hi->reg->isamd, dictentry, dictlen, isamd_i);
718              /* logf dictentry after */
719             if (dictlen)
720             {
721                 hi->no_updates++;
722                 if ( (dictlen!=dict_info[0]) ||
723                      (0!=memcmp(dictentry, dict_info+1, dictlen)) )
724                 {
725                     dict_insert(hi->reg->dict, this_name,
726                                 dictlen,dictentry);
727                 }
728             }
729             else
730             {
731                 hi->no_deletions++;
732                 if (!dict_delete (hi->reg->dict, this_name)) 
733                 {
734                     logf (LOG_FATAL, "dict_delete failed");
735                     abort();
736                 }
737             }
738         } 
739         else
740         {
741             dictlen=0;
742             memset (dictentry, '\0', ISAMD_MAX_DICT_LEN);
743             dictlen= isamd_append(hi->reg->isamd, dictentry, dictlen, isamd_i);
744              /* logf dictentry first */
745             hi->no_insertions++;
746             if (dictlen)
747                 dict_insert(hi->reg->dict, this_name,
748                                 dictlen,dictentry);
749         }
750     }
751     xfree (isamd_i);
752     xfree (hci.key);
753     xfree (hci.key_1);
754     xfree (hci.key_2);
755     return 0;
756
757
758 int heap_inp (struct heap_info *hi)
759 {
760     char *info;
761     char next_name[INP_NAME_MAX];
762     char cur_name[INP_NAME_MAX];
763     int key_buf_size = INP_BUF_START;
764     int key_buf_ptr;
765     char *next_key;
766     char *key_buf;
767     int more;
768     
769     next_key = (char *) xmalloc (KEY_SIZE);
770     key_buf = (char *) xmalloc (key_buf_size);
771     more = heap_read_one (hi, cur_name, key_buf);
772     while (more)                   /* EOF ? */
773     {
774         int nmemb;
775         key_buf_ptr = KEY_SIZE;
776         while (1)
777         {
778             if (!(more = heap_read_one (hi, next_name, next_key)))
779                 break;
780             if (*next_name && strcmp (next_name, cur_name))
781                 break;
782             memcpy (key_buf + key_buf_ptr, next_key, KEY_SIZE);
783             key_buf_ptr += KEY_SIZE;
784             if (key_buf_ptr+(int) KEY_SIZE >= key_buf_size)
785             {
786                 char *new_key_buf;
787                 new_key_buf = (char *) xmalloc (key_buf_size + INP_BUF_ADD);
788                 memcpy (new_key_buf, key_buf, key_buf_size);
789                 key_buf_size += INP_BUF_ADD;
790                 xfree (key_buf);
791                 key_buf = new_key_buf;
792             }
793         }
794         hi->no_diffs++;
795         nmemb = key_buf_ptr / KEY_SIZE;
796         assert (nmemb * (int) KEY_SIZE == key_buf_ptr);
797         if ((info = dict_lookup (hi->reg->dict, cur_name)))
798         {
799             ISAM_P isam_p, isam_p2;
800             memcpy (&isam_p, info+1, sizeof(ISAM_P));
801             isam_p2 = is_merge (hi->reg->isam, isam_p, nmemb, key_buf);
802             if (!isam_p2)
803             {
804                 hi->no_deletions++;
805                 if (!dict_delete (hi->reg->dict, cur_name))
806                     abort ();
807             }
808             else 
809             {
810                 hi->no_updates++;
811                 if (isam_p2 != isam_p)
812                     dict_insert (hi->reg->dict, cur_name,
813                                  sizeof(ISAM_P), &isam_p2);
814             }
815         }
816         else
817         {
818             ISAM_P isam_p;
819             hi->no_insertions++;
820             isam_p = is_merge (hi->reg->isam, 0, nmemb, key_buf);
821             dict_insert (hi->reg->dict, cur_name, sizeof(ISAM_P), &isam_p);
822         }
823         memcpy (key_buf, next_key, KEY_SIZE);
824         strcpy (cur_name, next_name);
825     }
826     return 0;
827 }
828
829 int heap_inps (struct heap_info *hi)
830 {
831     struct heap_cread_info hci;
832     ISAMS_I isams_i = (ISAMS_I) xmalloc (sizeof(*isams_i));
833
834     hci.key = (char *) xmalloc (KEY_SIZE);
835     hci.key_1 = (char *) xmalloc (KEY_SIZE);
836     hci.key_2 = (char *) xmalloc (KEY_SIZE);
837     hci.first_in_list = 1;
838     hci.ret = -1;
839     hci.hi = hi;
840     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
841
842     isams_i->clientData = &hci;
843     isams_i->read_item = heap_cread_item;
844
845     while (hci.more)
846     {
847         char this_name[INP_NAME_MAX];
848         ISAMS_P isams_p;
849         char *dict_info;
850
851         strcpy (this_name, hci.cur_name);
852         assert (hci.cur_name[1]);
853         hi->no_diffs++;
854         if (!(dict_info = dict_lookup (hi->reg->dict, hci.cur_name)))
855         {
856             isams_p = isams_merge (hi->reg->isams, isams_i);
857             hi->no_insertions++;
858             dict_insert (hi->reg->dict, this_name, sizeof(ISAMS_P), &isams_p);
859         }
860         else
861         {
862             logf (LOG_FATAL, "isams doesn't support this kind of update");
863             break;
864         }
865     }
866     xfree (isams_i);
867     return 0;
868
869
870 struct progressInfo {
871     time_t   startTime;
872     time_t   lastTime;
873     off_t    totalBytes;
874     off_t    totalOffset;
875 };
876
877 void progressFunc (struct key_file *keyp, void *info)
878 {
879     struct progressInfo *p = (struct progressInfo *) info;
880     time_t now, remaining;
881
882     if (keyp->buf_size <= 0 || p->totalBytes <= 0)
883         return ;
884     time (&now);
885
886     if (now >= p->lastTime+10)
887     {
888         p->lastTime = now;
889         remaining = (time_t) ((now - p->startTime)*
890             ((double) p->totalBytes/p->totalOffset - 1.0));
891         if (remaining <= 130)
892             logf (LOG_LOG, "Merge %2.1f%% completed; %ld seconds remaining",
893                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining);
894         else
895             logf (LOG_LOG, "Merge %2.1f%% completed; %ld minutes remaining",
896                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining/60);
897     }
898     p->totalOffset += keyp->buf_size;
899 }
900
901 #ifndef R_OK
902 #define R_OK 4
903 #endif
904
905 void zebra_index_merge (ZebraHandle zh)
906 {
907     struct key_file **kf = 0;
908     char rbuf[1024];
909     int i, r;
910     struct heap_info *hi;
911     struct progressInfo progressInfo;
912     int nkeys = zh->reg->key_file_no;
913     int usefile; 
914     
915     logf (LOG_DEBUG, " index_merge called with nk=%d b=%p", 
916                     nkeys, zh->reg->key_buf);
917     if ( (nkeys==0) && (zh->reg->key_buf==0) )
918         return; /* nothing to merge - probably flush after end-trans */
919     
920     usefile = (nkeys!=0); 
921
922     if (usefile)
923     {
924         if (nkeys < 0)
925         {
926             char fname[1024];
927             nkeys = 0;
928             while (1)
929             {
930                 extract_get_fname_tmp  (zh, fname, nkeys+1);
931                 if (access (fname, R_OK) == -1)
932                         break;
933                 nkeys++;
934             }
935             if (!nkeys)
936                 return ;
937         }
938         kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
939         progressInfo.totalBytes = 0;
940         progressInfo.totalOffset = 0;
941         time (&progressInfo.startTime);
942         time (&progressInfo.lastTime);
943         for (i = 1; i<=nkeys; i++)
944         {
945             kf[i] = key_file_init (i, 8192, zh->res);
946             kf[i]->readHandler = progressFunc;
947             kf[i]->readInfo = &progressInfo;
948             progressInfo.totalBytes += kf[i]->length;
949             progressInfo.totalOffset += kf[i]->buf_size;
950         }
951         hi = key_heap_init (nkeys, key_qsort_compare);
952         hi->reg = zh->reg;
953         
954         for (i = 1; i<=nkeys; i++)
955             if ((r = key_file_read (kf[i], rbuf)))
956                 key_heap_insert (hi, rbuf, r, kf[i]);
957     }  /* use file */
958     else 
959     { /* do not use file, read straight from buffer */
960         hi = key_heap_init_buff (zh,key_qsort_compare);
961         hi->reg = zh->reg;
962     }
963     if (zh->reg->isams)
964         heap_inps (hi);
965     if (zh->reg->isamc)
966         heap_inpc (hi);
967     if (zh->reg->isam)
968         heap_inp (hi);
969     if (zh->reg->isamd)
970         heap_inpd (hi);
971     if (zh->reg->isamb)
972         heap_inpb (hi);
973         
974     if (usefile)
975     {
976         for (i = 1; i<=nkeys; i++)
977         {
978             extract_get_fname_tmp  (zh, rbuf, i);
979             unlink (rbuf);
980         }
981         for (i = 1; i<=nkeys; i++)
982             key_file_destroy (kf[i]);
983         xfree (kf);
984     }
985     if (hi->no_iterations)
986     { /* do not log if nothing happened */
987         logf (LOG_LOG, "Iterations . . .%7d", hi->no_iterations);
988         logf (LOG_LOG, "Distinct words .%7d", hi->no_diffs);
989         logf (LOG_LOG, "Updates. . . . .%7d", hi->no_updates);
990         logf (LOG_LOG, "Deletions. . . .%7d", hi->no_deletions);
991         logf (LOG_LOG, "Insertions . . .%7d", hi->no_insertions);
992     }
993     zh->reg->key_file_no = 0;
994
995     key_heap_destroy (hi, nkeys);
996 }
997
998