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