Use zint for numbers in update statistics.
[idzebra-moved-to-github.git] / index / kinput.c
1 /* $Id: kinput.c,v 1.80 2006-12-06 22:52:38 adam Exp $
2    Copyright (C) 1995-2006
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 #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 1
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_read (struct key_file *f, char *key)
172 {
173     int i, c;
174     char srcbuf[128];
175     const char *src = srcbuf;
176     char *dst;
177     int j;
178
179     c = key_file_getc (f);
180     if (c == 0)
181     {
182         strcpy (key, f->prev_name);
183         i = 1+strlen (key);
184     }
185     else if (c == EOF)
186         return 0;
187     else
188     {
189         i = 0;
190         key[i++] = c;
191         while ((key[i++] = key_file_getc (f)))
192             ;
193         strcpy (f->prev_name, key);
194         iscz1_reset(f->decode_handle);
195     }
196     c = key_file_getc(f); /* length +  insert/delete combined */
197     key[i++] = c & 128;
198     c = c & 127;
199     for (j = 0; j < c; j++)
200         srcbuf[j] = key_file_getc(f);
201     dst = key + i;
202     iscz1_decode(f->decode_handle, &dst, &src);
203
204 #if 0
205     /* debugging */
206     if (1)
207     {
208         struct it_key k;
209         memcpy(&k, key+i, sizeof(k));
210         if (!k.mem[1])
211             yaz_log(YLOG_LOG, "00 KEY");
212     }
213 #endif
214     return i + sizeof(struct it_key);
215 }
216
217 struct heap_info {
218     struct {
219         struct key_file **file;
220         char   **buf;
221     } info;
222     int    heapnum;
223     int    *ptr;
224     int    (*cmp)(const void *p1, const void *p2);
225     struct zebra_register *reg;
226     ZebraHandle zh;
227     int raw_reading; /* 1=raw /mem read. 0=file reading */
228     zint no_diffs;
229     zint no_updates;
230     zint no_deletions;
231     zint no_insertions;
232     zint no_iterations;
233 };
234
235 static struct heap_info *key_heap_malloc(void)
236 {  /* malloc and clear it */
237     struct heap_info *hi;
238     hi = (struct heap_info *) xmalloc (sizeof(*hi));
239     hi->info.file = 0;
240     hi->info.buf = 0;
241     hi->heapnum = 0;
242     hi->ptr = 0;
243     hi->raw_reading = 0;
244     hi->no_diffs = 0;
245     hi->no_diffs = 0;
246     hi->no_updates = 0;
247     hi->no_deletions = 0;
248     hi->no_insertions = 0;
249     hi->no_iterations = 0;
250     return hi;
251 }
252
253 struct heap_info *key_heap_init_file(ZebraHandle zh,
254                                      int nkeys,
255                                      int (*cmp)(const void *p1, const void *p2))
256 {
257     struct heap_info *hi;
258     int i;
259
260     hi = key_heap_malloc();
261     hi->zh = zh;
262     hi->info.file = (struct key_file **)
263         xmalloc (sizeof(*hi->info.file) * (1+nkeys));
264     hi->info.buf = (char **) xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
265     hi->ptr = (int *) xmalloc (sizeof(*hi->ptr) * (1+nkeys));
266     hi->cmp = cmp;
267     for (i = 0; i<= nkeys; i++)
268     {
269         hi->ptr[i] = i;
270         hi->info.buf[i] = (char *) xmalloc (INP_NAME_MAX);
271     }
272     return hi;
273 }
274
275 struct heap_info *key_heap_init_raw(ZebraHandle zh,
276                                     int (*cmp)(const void *p1, const void *p2))
277 {
278     struct heap_info *hi=key_heap_malloc();
279     hi->cmp = cmp;
280     hi->zh = zh;
281     hi->raw_reading = 1;
282     return hi;
283 }
284
285 void key_heap_destroy (struct heap_info *hi, int nkeys)
286 {
287     int i;
288     if (!hi->raw_reading)
289         for (i = 0; i<=nkeys; i++)
290             xfree (hi->info.buf[i]);
291     
292     xfree (hi->info.buf);
293     xfree (hi->ptr);
294     xfree (hi->info.file);
295     xfree (hi);
296 }
297
298 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
299 {
300     int swap;
301
302     swap = hi->ptr[i1];
303     hi->ptr[i1] = hi->ptr[i2];
304     hi->ptr[i2] = swap;
305 }
306
307
308 static void key_heap_delete (struct heap_info *hi)
309 {
310     int cur = 1, child = 2;
311
312     assert (hi->heapnum > 0);
313
314     key_heap_swap (hi, 1, hi->heapnum);
315     hi->heapnum--;
316     while (child <= hi->heapnum) {
317         if (child < hi->heapnum &&
318             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
319                        &hi->info.buf[hi->ptr[child+1]]) > 0)
320             child++;
321         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
322                        &hi->info.buf[hi->ptr[child]]) > 0)
323         {            
324             key_heap_swap (hi, cur, child);
325             cur = child;
326             child = 2*cur;
327         }
328         else
329             break;
330     }
331 }
332
333 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
334                              struct key_file *kf)
335 {
336     int cur, parent;
337
338     cur = ++(hi->heapnum);
339     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
340     hi->info.file[hi->ptr[cur]] = kf;
341
342     parent = cur/2;
343     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
344                                 &hi->info.buf[hi->ptr[cur]]) > 0)
345     {
346         key_heap_swap (hi, cur, parent);
347         cur = parent;
348         parent = cur/2;
349     }
350 }
351
352 static int heap_read_one (struct heap_info *hi, char *name, char *key)
353 {
354     int n, r;
355     char rbuf[INP_NAME_MAX];
356     struct key_file *kf;
357
358     if (!hi->heapnum)
359         return 0;
360     n = hi->ptr[1];
361     strcpy (name, hi->info.buf[n]);
362     kf = hi->info.file[n];
363     r = strlen(name);
364     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
365     key_heap_delete (hi);
366     if ((r = key_file_read (kf, rbuf)))
367         key_heap_insert (hi, rbuf, r, kf);
368     hi->no_iterations++;
369     return 1;
370 }
371
372 #define PR_KEY_LOW 0
373 #define PR_KEY_TOP 0
374
375 /* for debugging only */
376 void zebra_log_dict_entry(ZebraHandle zh, const char *s)
377 {
378     char dst[IT_MAX_WORD+1];
379     int ord;
380     int len = key_SU_decode(&ord, (const unsigned char *) s);
381     int index_type;
382
383     if (!zh)
384         yaz_log(YLOG_LOG, "ord=%d", ord);
385     else
386     {
387         const char *string_index;
388         const char *db = 0;
389         zebraExplain_lookup_ord(zh->reg->zei,
390                                 ord, &index_type, &db, &string_index);
391
392         zebra_term_untrans(zh, index_type, dst, s + len);
393
394         yaz_log(YLOG_LOG, "ord=%d index_type=%c index=%s term=%s",
395                 ord, index_type, string_index, dst);
396     }
397 }
398
399 struct heap_cread_info {
400     char prev_name[INP_NAME_MAX];
401     char cur_name[INP_NAME_MAX];
402     char *key;
403     char *key_1, *key_2;
404     int mode_1, mode_2;
405     int sz_1, sz_2;
406     struct heap_info *hi;
407     int first_in_list;
408     int more;
409     int ret;
410     int look_level;
411 };
412
413 static int heap_cread_item (void *vp, char **dst, int *insertMode);
414
415 int heap_cread_item2(void *vp, char **dst, int *insertMode)
416 {
417     struct heap_cread_info *p = (struct heap_cread_info *) vp;
418     int level = 0;
419
420     if (p->look_level)
421     {
422         if (p->look_level > 0)
423         {
424             *insertMode = 1;
425             p->look_level--;
426         }
427         else
428         {
429             *insertMode = 0;
430             p->look_level++;
431         }
432         memcpy (*dst, p->key_1, p->sz_1);
433 #if 0
434         yaz_log(YLOG_LOG, "DUP level=%d", p->look_level);
435         pkey(*dst, *insertMode);
436 #endif
437         (*dst) += p->sz_1;
438         return 1;
439     }
440     if (p->ret == 0)    /* lookahead was 0?. Return that in read next round */
441     {
442         p->ret = -1;
443         return 0;
444     }
445     else if (p->ret == -1) /* Must read new item ? */
446     {
447         char *dst_1 = p->key_1;
448         p->ret = heap_cread_item(vp, &dst_1, &p->mode_1);
449         p->sz_1 = dst_1 - p->key_1;
450     }
451     else
452     {        /* lookahead in 2 . Now in 1. */
453         p->sz_1 = p->sz_2;
454         p->mode_1 = p->mode_2;
455         memcpy (p->key_1, p->key_2, p->sz_2);
456     }
457     if (p->mode_1)
458         level = 1;     /* insert */
459     else
460         level = -1;    /* delete */
461     while(1)
462     {
463         char *dst_2 = p->key_2;
464         p->ret = heap_cread_item(vp, &dst_2, &p->mode_2);
465         if (!p->ret)
466         {
467             if (level)
468                 break;
469             p->ret = -1;
470             return 0;
471         }
472         p->sz_2 = dst_2 - p->key_2;
473
474         if (key_compare(p->key_1, p->key_2) == 0)
475         {
476             if (p->mode_2) /* adjust level according to deletes/inserts */
477                 level++;
478             else
479                 level--;
480         }
481         else
482         {
483             if (level)
484                 break;
485             /* all the same. new round .. */
486             p->sz_1 = p->sz_2;
487             p->mode_1 = p->mode_2;
488             memcpy (p->key_1, p->key_2, p->sz_1);
489             if (p->mode_1)
490                 level = 1;     /* insert */
491             else
492                 level = -1;    /* delete */
493         }
494     }
495     /* outcome is insert (1) or delete (0) depending on final level */
496     if (level > 0)
497     {
498         *insertMode = 1;
499         level--;
500     }
501     else
502     {
503         *insertMode = 0;
504         level++;
505     }
506     p->look_level = level;
507     memcpy (*dst, p->key_1, p->sz_1);
508 #if 0
509     pkey(*dst, *insertMode);
510 #endif
511     (*dst) += p->sz_1;
512     return 1;
513 }
514       
515 int heap_cread_item (void *vp, char **dst, int *insertMode)
516 {
517     struct heap_cread_info *p = (struct heap_cread_info *) vp;
518     struct heap_info *hi = p->hi;
519
520     if (p->first_in_list)
521     {
522         *insertMode = p->key[0];
523         memcpy (*dst, p->key+1, sizeof(struct it_key));
524 #if PR_KEY_LOW
525         zebra_log_dict_entry(hi->zh, p->cur_name);
526         pkey(*dst, *insertMode);
527 #endif
528         (*dst) += sizeof(struct it_key);
529         p->first_in_list = 0;
530         return 1;
531     }
532     strcpy (p->prev_name, p->cur_name);
533     if (!(p->more = heap_read_one (hi, p->cur_name, p->key)))
534         return 0;
535     if (*p->cur_name && strcmp (p->cur_name, p->prev_name))
536     {
537         p->first_in_list = 1;
538         return 0;
539     }
540     *insertMode = p->key[0];
541     memcpy (*dst, p->key+1, sizeof(struct it_key));
542 #if PR_KEY_LOW
543     zebra_log_dict_entry(hi->zh, p->cur_name);
544     pkey(*dst, *insertMode);
545 #endif
546     (*dst) += sizeof(struct it_key);
547     return 1;
548 }
549
550 int heap_inpc (struct heap_cread_info *hci, struct heap_info *hi)
551 {
552     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
553
554     isamc_i->clientData = hci;
555     isamc_i->read_item = heap_cread_item2;
556
557     while (hci->more)
558     {
559         char this_name[INP_NAME_MAX];
560         ISAM_P isamc_p, isamc_p2;
561         char *dict_info;
562
563         strcpy (this_name, hci->cur_name);
564         assert (hci->cur_name[0]);
565         hi->no_diffs++;
566         if ((dict_info = dict_lookup (hi->reg->dict, hci->cur_name)))
567         {
568             memcpy (&isamc_p, dict_info+1, sizeof(ISAM_P));
569             isamc_p2 = isamc_p;
570             isamc_merge (hi->reg->isamc, &isamc_p2, isamc_i);
571             if (!isamc_p2)
572             {
573                 hi->no_deletions++;
574                 if (!dict_delete (hi->reg->dict, this_name))
575                     abort();
576             }
577             else 
578             {
579                 hi->no_updates++;
580                 if (isamc_p2 != isamc_p)
581                     dict_insert (hi->reg->dict, this_name,
582                                  sizeof(ISAM_P), &isamc_p2);
583             }
584         } 
585         else
586         {
587             isamc_p = 0;
588             isamc_merge (hi->reg->isamc, &isamc_p, isamc_i);
589             hi->no_insertions++;
590             if (isamc_p)
591                 dict_insert (hi->reg->dict, this_name,
592                              sizeof(ISAM_P), &isamc_p);
593         }
594     }
595     xfree (isamc_i);
596     return 0;
597
598
599 int heap_inp0(struct heap_cread_info *hci, struct heap_info *hi)
600 {
601     while (hci->more)
602     {
603         char this_name[INP_NAME_MAX];
604         char mybuf[1024];
605         char *dst = mybuf;
606         int mode;
607
608         strcpy (this_name, hci->cur_name);
609         assert (hci->cur_name[0]);
610         hi->no_diffs++;
611
612         while (heap_cread_item2(hci, &dst, &mode))
613             ;
614     }
615     return 0;
616
617
618
619 int heap_inpb(struct heap_cread_info *hci, struct heap_info *hi)
620 {
621     ISAMC_I *isamc_i = (ISAMC_I *) xmalloc (sizeof(*isamc_i));
622
623     isamc_i->clientData = hci;
624     isamc_i->read_item = heap_cread_item2;
625
626     while (hci->more)
627     {
628         char this_name[INP_NAME_MAX];
629         ISAM_P isamc_p, isamc_p2;
630         char *dict_info;
631
632         strcpy (this_name, hci->cur_name);
633         assert (hci->cur_name[0]);
634         hi->no_diffs++;
635
636 #if 0
637         assert(hi->zh);
638         zebra_log_dict_entry(hi->zh, hci->cur_name);
639 #endif
640         if ((dict_info = dict_lookup (hi->reg->dict, hci->cur_name)))
641         {
642             memcpy (&isamc_p, dict_info+1, sizeof(ISAM_P));
643             isamc_p2 = isamc_p;
644             isamb_merge (hi->reg->isamb, &isamc_p2, isamc_i);
645             if (!isamc_p2)
646             {
647                 hi->no_deletions++;
648                 if (!dict_delete (hi->reg->dict, this_name))
649                     abort();
650             }
651             else 
652             {
653                 hi->no_updates++;
654                 if (isamc_p2 != isamc_p)
655                     dict_insert (hi->reg->dict, this_name,
656                                  sizeof(ISAM_P), &isamc_p2);
657             }
658         } 
659         else
660         {
661             isamc_p = 0;
662             isamb_merge (hi->reg->isamb, &isamc_p, isamc_i);
663             hi->no_insertions++;
664             if (isamc_p)
665                 dict_insert (hi->reg->dict, this_name,
666                              sizeof(ISAM_P), &isamc_p);
667         }
668     }
669     xfree(isamc_i);
670     return 0;
671
672
673 int heap_inps (struct heap_cread_info *hci, struct heap_info *hi)
674 {
675     ISAMS_I isams_i = (ISAMS_I) xmalloc (sizeof(*isams_i));
676
677     isams_i->clientData = hci;
678     isams_i->read_item = heap_cread_item;
679
680     while (hci->more)
681     {
682         char this_name[INP_NAME_MAX];
683         ISAM_P isams_p;
684         char *dict_info;
685
686         strcpy (this_name, hci->cur_name);
687         assert (hci->cur_name[0]);
688         hi->no_diffs++;
689         if (!(dict_info = dict_lookup (hi->reg->dict, hci->cur_name)))
690         {
691             isams_p = isams_merge (hi->reg->isams, isams_i);
692             hi->no_insertions++;
693             dict_insert (hi->reg->dict, this_name, sizeof(ISAM_P), &isams_p);
694         }
695         else
696         {
697             yaz_log(YLOG_FATAL, "isams doesn't support this kind of update");
698             break;
699         }
700     }
701     xfree (isams_i);
702     return 0;
703
704
705 struct progressInfo {
706     time_t   startTime;
707     time_t   lastTime;
708     off_t    totalBytes;
709     off_t    totalOffset;
710 };
711
712 void progressFunc (struct key_file *keyp, void *info)
713 {
714     struct progressInfo *p = (struct progressInfo *) info;
715     time_t now, remaining;
716
717     if (keyp->buf_size <= 0 || p->totalBytes <= 0)
718         return ;
719     time (&now);
720
721     if (now >= p->lastTime+10)
722     {
723         p->lastTime = now;
724         remaining = (time_t) ((now - p->startTime)*
725             ((double) p->totalBytes/p->totalOffset - 1.0));
726         if (remaining <= 130)
727             yaz_log(YLOG_LOG, "Merge %2.1f%% completed; %ld seconds remaining",
728                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining);
729         else
730             yaz_log(YLOG_LOG, "Merge %2.1f%% completed; %ld minutes remaining",
731                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining/60);
732     }
733     p->totalOffset += keyp->buf_size;
734 }
735
736 #ifndef R_OK
737 #define R_OK 4
738 #endif
739
740 void zebra_index_merge (ZebraHandle zh)
741 {
742     struct key_file **kf = 0;
743     char rbuf[1024];
744     int i, r;
745     struct heap_info *hi;
746     struct progressInfo progressInfo;
747     int nkeys = key_block_get_no_files(zh->reg->key_block);
748
749     if (nkeys == 0)
750         return;
751     
752     if (nkeys < 0)
753     {
754         char fname[1024];
755         nkeys = 0;
756         while (1)
757         {
758             extract_get_fname_tmp  (zh, fname, nkeys+1);
759             if (access (fname, R_OK) == -1)
760                 break;
761             nkeys++;
762         }
763         if (!nkeys)
764             return ;
765     }
766     kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
767     progressInfo.totalBytes = 0;
768     progressInfo.totalOffset = 0;
769     time (&progressInfo.startTime);
770     time (&progressInfo.lastTime);
771     for (i = 1; i<=nkeys; i++)
772     {
773         kf[i] = key_file_init (i, 8192, zh->res);
774         kf[i]->readHandler = progressFunc;
775         kf[i]->readInfo = &progressInfo;
776         progressInfo.totalBytes += kf[i]->length;
777         progressInfo.totalOffset += kf[i]->buf_size;
778     }
779     hi = key_heap_init_file(zh, nkeys, key_qsort_compare);
780     hi->reg = zh->reg;
781     
782     for (i = 1; i<=nkeys; i++)
783         if ((r = key_file_read (kf[i], rbuf)))
784             key_heap_insert (hi, rbuf, r, kf[i]);
785
786     if (1)
787     {
788         struct heap_cread_info hci;
789         
790         hci.key = (char *) xmalloc (KEY_SIZE);
791         hci.key_1 = (char *) xmalloc (KEY_SIZE);
792         hci.key_2 = (char *) xmalloc (KEY_SIZE);
793         hci.ret = -1;
794         hci.first_in_list = 1;
795         hci.hi = hi;
796         hci.look_level = 0;
797         hci.more = heap_read_one (hi, hci.cur_name, hci.key);    
798         
799         if (zh->reg->isams)
800             heap_inps(&hci, hi);
801         if (zh->reg->isamc)
802             heap_inpc(&hci, hi);
803         if (zh->reg->isamb)
804             heap_inpb(&hci, hi);
805         
806         xfree (hci.key);
807         xfree (hci.key_1);
808         xfree (hci.key_2);
809     }
810         
811     for (i = 1; i<=nkeys; i++)
812     {
813         extract_get_fname_tmp  (zh, rbuf, i);
814         unlink (rbuf);
815     }
816     for (i = 1; i<=nkeys; i++)
817         key_file_destroy (kf[i]);
818     xfree (kf);
819     if (hi->no_iterations)
820     { /* do not log if nothing happened */
821         yaz_log(YLOG_LOG, "Iterations     %9" ZINT_FORMAT0, hi->no_iterations);
822         yaz_log(YLOG_LOG, "Distinct words %9" ZINT_FORMAT0, hi->no_diffs);
823         yaz_log(YLOG_LOG, "Updates        %9" ZINT_FORMAT0, hi->no_updates);
824         yaz_log(YLOG_LOG, "Deletions      %9" ZINT_FORMAT0, hi->no_deletions);
825         yaz_log(YLOG_LOG, "Insertions     %9" ZINT_FORMAT0, hi->no_insertions);
826     }
827     key_block_destroy(&zh->reg->key_block);
828     key_heap_destroy(hi, nkeys);
829 }
830 /*
831  * Local variables:
832  * c-basic-offset: 4
833  * indent-tabs-mode: nil
834  * End:
835  * vim: shiftwidth=4 tabstop=8 expandtab
836  */
837