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