Fix unused var.
[idzebra-moved-to-github.git] / index / kinput.c
1 /*
2  * Copyright (C) 1994-2000, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss, Heikki Levanto
5  *
6  * (log at the end)
7  *
8  * Bugs
9  *  - Allocates a lot of memory for the merge process, but never releases it.
10  *    Doesn't matter, as the program terminates soon after.  
11  
12  */
13  
14 #include <fcntl.h>
15 #ifdef WIN32
16 #include <io.h>
17 #else
18 #include <unistd.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
24
25 #include "index.h"
26 #include "zserver.h"
27
28 #define KEY_SIZE (1+sizeof(struct it_key))
29 #define INP_NAME_MAX 768
30 #define INP_BUF_START 60000
31 #define INP_BUF_ADD  400000
32
33 static int no_diffs   = 0;
34 static int no_updates = 0;
35 static int no_deletions = 0;
36 static int no_insertions = 0;
37 static int no_iterations = 0;
38
39 struct key_file {
40     int   no;            /* file no */
41     off_t offset;        /* file offset */
42     unsigned char *buf;  /* buffer block */
43     size_t buf_size;     /* number of read bytes in block */
44     size_t chunk;        /* number of bytes allocated */
45     size_t buf_ptr;      /* current position in buffer */
46     char *prev_name;     /* last word read */
47     int   sysno;         /* last sysno */
48     int   seqno;         /* last seqno */
49     off_t length;        /* length of file */
50                          /* handler invoked in each read */
51     void (*readHandler)(struct key_file *keyp, void *rinfo);
52     void *readInfo;
53     Res res;
54 };
55
56 void getFnameTmp (Res res, char *fname, int no)
57 {
58     const char *pre;
59     
60     pre = res_get_def (res, "keyTmpDir", ".");
61     sprintf (fname, "%s/key%d.tmp", pre, no);
62 }
63
64 void extract_get_fname_tmp (ZebraHandle zh, char *fname, int no)
65 {
66     const char *pre;
67     
68     pre = res_get_def (zh->service->res, "keyTmpDir", ".");
69     sprintf (fname, "%s/key%d.tmp", pre, no);
70 }
71
72 void key_file_chunk_read (struct key_file *f)
73 {
74     int nr = 0, r = 0, fd;
75     char fname[1024];
76     getFnameTmp (f->res, fname, f->no);
77     fd = open (fname, O_BINARY|O_RDONLY);
78
79     f->buf_ptr = 0;
80     f->buf_size = 0;
81     if (fd == -1)
82     {
83         logf (LOG_WARN|LOG_ERRNO, "cannot open %s", fname);
84         return ;
85     }
86     if (!f->length)
87     {
88         if ((f->length = lseek (fd, 0L, SEEK_END)) == (off_t) -1)
89         {
90             logf (LOG_WARN|LOG_ERRNO, "cannot seek %s", fname);
91             close (fd);
92             return ;
93         }
94     }
95     if (lseek (fd, f->offset, SEEK_SET) == -1)
96     {
97         logf (LOG_WARN|LOG_ERRNO, "cannot seek %s", fname);
98         close(fd);
99         return ;
100     }
101     while (f->chunk - nr > 0)
102     {
103         r = read (fd, f->buf + nr, f->chunk - nr);
104         if (r <= 0)
105             break;
106         nr += r;
107     }
108     if (r == -1)
109     {
110         logf (LOG_WARN|LOG_ERRNO, "read of %s", fname);
111         close (fd);
112         return;
113     }
114     f->buf_size = nr;
115     if (f->readHandler)
116         (*f->readHandler)(f, f->readInfo);
117     close (fd);
118 }
119
120 struct key_file *key_file_init (int no, int chunk, Res res)
121 {
122     struct key_file *f;
123
124     f = (struct key_file *) xmalloc (sizeof(*f));
125     f->res = res;
126     f->sysno = 0;
127     f->seqno = 0;
128     f->no = no;
129     f->chunk = chunk;
130     f->offset = 0;
131     f->length = 0;
132     f->readHandler = NULL;
133     f->buf = (unsigned char *) xmalloc (f->chunk);
134     f->prev_name = (char *) xmalloc (INP_NAME_MAX);
135     *f->prev_name = '\0';
136     key_file_chunk_read (f);
137     return f;
138 }
139
140 int key_file_getc (struct key_file *f)
141 {
142     if (f->buf_ptr < f->buf_size)
143         return f->buf[(f->buf_ptr)++];
144     if (f->buf_size < f->chunk)
145         return EOF;
146     f->offset += f->buf_size;
147     key_file_chunk_read (f);
148     if (f->buf_ptr < f->buf_size)
149         return f->buf[(f->buf_ptr)++];
150     else
151         return EOF;
152 }
153
154 int key_file_decode (struct key_file *f)
155 {
156     int c, d;
157
158     c = key_file_getc (f);
159     switch (c & 192) 
160     {
161     case 0:
162         d = c;
163         break;
164     case 64:
165         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
166         break;
167     case 128:
168         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
169         d = (d << 8) + (key_file_getc (f) & 0xff);
170         break;
171     case 192:
172         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
173         d = (d << 8) + (key_file_getc (f) & 0xff);
174         d = (d << 8) + (key_file_getc (f) & 0xff);
175         break;
176     }
177     return d;
178 }
179
180 int key_file_read (struct key_file *f, char *key)
181 {
182     int i, d, c;
183     struct it_key itkey;
184
185     c = key_file_getc (f);
186     if (c == 0)
187     {
188         strcpy (key, f->prev_name);
189         i = 1+strlen (key);
190     }
191     else if (c == EOF)
192         return 0;
193     else
194     {
195         i = 0;
196         key[i++] = c;
197         while ((key[i++] = key_file_getc (f)))
198             ;
199         strcpy (f->prev_name, key);
200         f->sysno = 0;
201     }
202     d = key_file_decode (f);
203     key[i++] = d & 1;
204     d = d >> 1;
205     itkey.sysno = d + f->sysno;
206     if (d) 
207     {
208         f->sysno = itkey.sysno;
209         f->seqno = 0;
210     }
211     d = key_file_decode (f);
212     itkey.seqno = d + f->seqno;
213     f->seqno = itkey.seqno;
214     memcpy (key + i, &itkey, sizeof(struct it_key));
215     return i + sizeof (struct it_key);
216 }
217
218 struct heap_info {
219     struct {
220         struct key_file **file;
221         char   **buf;
222     } info;
223     int    heapnum;
224     int    *ptr;
225     int    (*cmp)(const void *p1, const void *p2);
226     Dict dict;
227     ISAMS isams;
228 #if ZMBOL
229     ISAM isam;
230     ISAMC isamc;
231     ISAMD isamd;
232 #endif
233 };
234
235 struct heap_info *key_heap_init (int nkeys,
236                                  int (*cmp)(const void *p1, const void *p2))
237 {
238     struct heap_info *hi;
239     int i;
240
241     hi = (struct heap_info *) xmalloc (sizeof(*hi));
242     hi->info.file = (struct key_file **)
243         xmalloc (sizeof(*hi->info.file) * (1+nkeys));
244     hi->info.buf = (char **) xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
245     hi->heapnum = 0;
246     hi->ptr = (int *) xmalloc (sizeof(*hi->ptr) * (1+nkeys));
247     hi->cmp = cmp;
248     for (i = 0; i<= nkeys; i++)
249     {
250         hi->ptr[i] = i;
251         hi->info.buf[i] = (char *) xmalloc (INP_NAME_MAX);
252     }
253     return hi;
254 }
255
256 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
257 {
258     int swap;
259
260     swap = hi->ptr[i1];
261     hi->ptr[i1] = hi->ptr[i2];
262     hi->ptr[i2] = swap;
263 }
264
265
266 static void key_heap_delete (struct heap_info *hi)
267 {
268     int cur = 1, child = 2;
269
270     assert (hi->heapnum > 0);
271
272     key_heap_swap (hi, 1, hi->heapnum);
273     hi->heapnum--;
274     while (child <= hi->heapnum) {
275         if (child < hi->heapnum &&
276             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
277                        &hi->info.buf[hi->ptr[child+1]]) > 0)
278             child++;
279         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
280                        &hi->info.buf[hi->ptr[child]]) > 0)
281         {            
282             key_heap_swap (hi, cur, child);
283             cur = child;
284             child = 2*cur;
285         }
286         else
287             break;
288     }
289 }
290
291 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
292                              struct key_file *kf)
293 {
294     int cur, parent;
295
296     cur = ++(hi->heapnum);
297     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
298     hi->info.file[hi->ptr[cur]] = kf;
299
300     parent = cur/2;
301     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
302                                 &hi->info.buf[hi->ptr[cur]]) > 0)
303     {
304         key_heap_swap (hi, cur, parent);
305         cur = parent;
306         parent = cur/2;
307     }
308 }
309
310 static int heap_read_one (struct heap_info *hi, char *name, char *key)
311 {
312     int n, r;
313     char rbuf[INP_NAME_MAX];
314     struct key_file *kf;
315
316     if (!hi->heapnum)
317         return 0;
318     n = hi->ptr[1];
319     strcpy (name, hi->info.buf[n]);
320     kf = hi->info.file[n];
321     r = strlen(name);
322     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
323     key_heap_delete (hi);
324     if ((r = key_file_read (kf, rbuf)))
325         key_heap_insert (hi, rbuf, r, kf);
326     no_iterations++;
327     return 1;
328 }
329
330 struct heap_cread_info {
331     char prev_name[INP_NAME_MAX];
332     char cur_name[INP_NAME_MAX];
333     char *key;
334     struct heap_info *hi;
335     int mode;
336     int more;
337 };
338       
339 int heap_cread_item (void *vp, char **dst, int *insertMode)
340 {
341     struct heap_cread_info *p = (struct heap_cread_info *) vp;
342     struct heap_info *hi = p->hi;
343
344     if (p->mode == 1)
345     {
346         *insertMode = p->key[0];
347         memcpy (*dst, p->key+1, sizeof(struct it_key));
348         (*dst) += sizeof(struct it_key);
349         p->mode = 2;
350         return 1;
351     }
352     strcpy (p->prev_name, p->cur_name);
353     if (!(p->more = heap_read_one (hi, p->cur_name, p->key)))
354         return 0;
355     if (*p->cur_name && strcmp (p->cur_name, p->prev_name))
356     {
357         p->mode = 1;
358         return 0;
359     }
360     *insertMode = p->key[0];
361     memcpy (*dst, p->key+1, sizeof(struct it_key));
362     (*dst) += sizeof(struct it_key);
363     return 1;
364 }
365
366 #if ZMBOL
367 int heap_inpc (struct heap_info *hi)
368 {
369     struct heap_cread_info hci;
370     ISAMC_I isamc_i = (ISAMC_I) xmalloc (sizeof(*isamc_i));
371
372     hci.key = (char *) xmalloc (KEY_SIZE);
373     hci.mode = 1;
374     hci.hi = hi;
375     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
376
377     isamc_i->clientData = &hci;
378     isamc_i->read_item = heap_cread_item;
379
380     while (hci.more)
381     {
382         char this_name[INP_NAME_MAX];
383         ISAMC_P isamc_p, isamc_p2;
384         char *dict_info;
385
386         strcpy (this_name, hci.cur_name);
387         assert (hci.cur_name[1]);
388         no_diffs++;
389         if ((dict_info = dict_lookup (hi->dict, hci.cur_name)))
390         {
391             memcpy (&isamc_p, dict_info+1, sizeof(ISAMC_P));
392             isamc_p2 = isc_merge (hi->isamc, isamc_p, isamc_i);
393             if (!isamc_p2)
394             {
395                 no_deletions++;
396                 if (!dict_delete (hi->dict, this_name))
397                     abort();
398             }
399             else 
400             {
401                 no_updates++;
402                 if (isamc_p2 != isamc_p)
403                     dict_insert (hi->dict, this_name,
404                                  sizeof(ISAMC_P), &isamc_p2);
405             }
406         } 
407         else
408         {
409             isamc_p = isc_merge (hi->isamc, 0, isamc_i);
410             no_insertions++;
411             dict_insert (hi->dict, this_name, sizeof(ISAMC_P), &isamc_p);
412         }
413     }
414     xfree (isamc_i);
415     return 0;
416
417
418 int heap_inpd (struct heap_info *hi)
419 {
420     struct heap_cread_info hci;
421     ISAMD_I isamd_i = (ISAMD_I) xmalloc (sizeof(*isamd_i));
422
423     hci.key = (char *) xmalloc (KEY_SIZE);
424     hci.mode = 1;
425     hci.hi = hi;
426     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
427
428     isamd_i->clientData = &hci;
429     isamd_i->read_item = heap_cread_item;
430
431     while (hci.more)
432     {
433         char this_name[INP_NAME_MAX];
434         ISAMD_P isamd_p, isamd_p2;
435         char *dict_info;
436
437         strcpy (this_name, hci.cur_name);
438         assert (hci.cur_name[1]);
439         no_diffs++;
440         if ((dict_info = dict_lookup (hi->dict, hci.cur_name)))
441         {
442             memcpy (&isamd_p, dict_info+1, sizeof(ISAMD_P));
443             isamd_p2 = isamd_append (hi->isamd, isamd_p, isamd_i);
444             if (!isamd_p2)
445             {
446                 no_deletions++;
447                 if (!dict_delete (hi->dict, this_name))
448                     abort();
449             }
450             else 
451             {
452                 no_updates++;
453                 if (isamd_p2 != isamd_p)
454                     dict_insert (hi->dict, this_name,
455                                  sizeof(ISAMD_P), &isamd_p2);
456             }
457         } 
458         else
459         {
460             isamd_p = isamd_append (hi->isamd, 0, isamd_i);
461             no_insertions++;
462             dict_insert (hi->dict, this_name, sizeof(ISAMD_P), &isamd_p);
463         }
464     }
465     xfree (isamd_i);
466     return 0;
467
468
469 int heap_inp (struct heap_info *hi)
470 {
471     char *info;
472     char next_name[INP_NAME_MAX];
473     char cur_name[INP_NAME_MAX];
474     int key_buf_size = INP_BUF_START;
475     int key_buf_ptr;
476     char *next_key;
477     char *key_buf;
478     int more;
479     
480     next_key = (char *) xmalloc (KEY_SIZE);
481     key_buf = (char *) xmalloc (key_buf_size);
482     more = heap_read_one (hi, cur_name, key_buf);
483     while (more)                   /* EOF ? */
484     {
485         int nmemb;
486         key_buf_ptr = KEY_SIZE;
487         while (1)
488         {
489             if (!(more = heap_read_one (hi, next_name, next_key)))
490                 break;
491             if (*next_name && strcmp (next_name, cur_name))
492                 break;
493             memcpy (key_buf + key_buf_ptr, next_key, KEY_SIZE);
494             key_buf_ptr += KEY_SIZE;
495             if (key_buf_ptr+(int) KEY_SIZE >= key_buf_size)
496             {
497                 char *new_key_buf;
498                 new_key_buf = (char *) xmalloc (key_buf_size + INP_BUF_ADD);
499                 memcpy (new_key_buf, key_buf, key_buf_size);
500                 key_buf_size += INP_BUF_ADD;
501                 xfree (key_buf);
502                 key_buf = new_key_buf;
503             }
504         }
505         no_diffs++;
506         nmemb = key_buf_ptr / KEY_SIZE;
507         assert (nmemb * (int) KEY_SIZE == key_buf_ptr);
508         if ((info = dict_lookup (hi->dict, cur_name)))
509         {
510             ISAM_P isam_p, isam_p2;
511             memcpy (&isam_p, info+1, sizeof(ISAM_P));
512             isam_p2 = is_merge (hi->isam, isam_p, nmemb, key_buf);
513             if (!isam_p2)
514             {
515                 no_deletions++;
516                 if (!dict_delete (hi->dict, cur_name))
517                     abort ();
518             }
519             else 
520             {
521                 no_updates++;
522                 if (isam_p2 != isam_p)
523                     dict_insert (hi->dict, cur_name, sizeof(ISAM_P), &isam_p2);
524             }
525         }
526         else
527         {
528             ISAM_P isam_p;
529             no_insertions++;
530             isam_p = is_merge (hi->isam, 0, nmemb, key_buf);
531             dict_insert (hi->dict, cur_name, sizeof(ISAM_P), &isam_p);
532         }
533         memcpy (key_buf, next_key, KEY_SIZE);
534         strcpy (cur_name, next_name);
535     }
536     return 0;
537 }
538
539 #endif
540
541 int heap_inps (struct heap_info *hi)
542 {
543     struct heap_cread_info hci;
544     ISAMS_I isams_i = (ISAMS_I) xmalloc (sizeof(*isams_i));
545
546     hci.key = (char *) xmalloc (KEY_SIZE);
547     hci.mode = 1;
548     hci.hi = hi;
549     hci.more = heap_read_one (hi, hci.cur_name, hci.key);
550
551     isams_i->clientData = &hci;
552     isams_i->read_item = heap_cread_item;
553
554     while (hci.more)
555     {
556         char this_name[INP_NAME_MAX];
557         ISAMS_P isams_p;
558         char *dict_info;
559
560         strcpy (this_name, hci.cur_name);
561         assert (hci.cur_name[1]);
562         no_diffs++;
563         if (!(dict_info = dict_lookup (hi->dict, hci.cur_name)))
564         {
565             isams_p = isams_merge (hi->isams, isams_i);
566             no_insertions++;
567             dict_insert (hi->dict, this_name, sizeof(ISAMS_P), &isams_p);
568         }
569         else
570         {
571             logf (LOG_FATAL, "isams doesn't support this kind of update");
572             break;
573         }
574     }
575     xfree (isams_i);
576     return 0;
577
578
579 struct progressInfo {
580     time_t   startTime;
581     time_t   lastTime;
582     off_t    totalBytes;
583     off_t    totalOffset;
584 };
585
586 void progressFunc (struct key_file *keyp, void *info)
587 {
588     struct progressInfo *p = (struct progressInfo *) info;
589     time_t now, remaining;
590
591     if (keyp->buf_size <= 0 || p->totalBytes <= 0)
592         return ;
593     time (&now);
594
595     if (now >= p->lastTime+10)
596     {
597         p->lastTime = now;
598         remaining = (time_t) ((now - p->startTime)*
599             ((double) p->totalBytes/p->totalOffset - 1.0));
600         if (remaining <= 130)
601             logf (LOG_LOG, "Merge %2.1f%% completed; %ld seconds remaining",
602                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining);
603         else
604             logf (LOG_LOG, "Merge %2.1f%% completed; %ld minutes remaining",
605                  (100.0*p->totalOffset) / p->totalBytes, (long) remaining/60);
606     }
607     p->totalOffset += keyp->buf_size;
608 }
609
610 #ifndef R_OK
611 #define R_OK 4
612 #endif
613
614 void zebra_index_merge (ZebraHandle zh)
615 {
616     struct key_file **kf;
617     char rbuf[1024];
618     int i, r;
619     struct heap_info *hi;
620     struct progressInfo progressInfo;
621     int nkeys = zh->key_file_no;
622     
623     if (nkeys < 0)
624     {
625         char fname[1024];
626         nkeys = 0;
627         while (1)
628         {
629             extract_get_fname_tmp  (zh, fname, nkeys+1);
630             if (access (fname, R_OK) == -1)
631                 break;
632             nkeys++;
633         }
634         if (!nkeys)
635             return ;
636     }
637     kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
638     progressInfo.totalBytes = 0;
639     progressInfo.totalOffset = 0;
640     time (&progressInfo.startTime);
641     time (&progressInfo.lastTime);
642     for (i = 1; i<=nkeys; i++)
643     {
644         kf[i] = key_file_init (i, 8192, zh->service->res);
645         kf[i]->readHandler = progressFunc;
646         kf[i]->readInfo = &progressInfo;
647         progressInfo.totalBytes += kf[i]->length;
648         progressInfo.totalOffset += kf[i]->buf_size;
649     }
650     hi = key_heap_init (nkeys, key_qsort_compare);
651     hi->dict = zh->service->dict;
652     hi->isams = zh->service->isams;
653 #if ZMBOL
654     hi->isam = zh->service->isam;
655     hi->isamc = zh->service->isamc;
656     hi->isamd = zh->service->isamd;
657 #endif
658     
659     for (i = 1; i<=nkeys; i++)
660         if ((r = key_file_read (kf[i], rbuf)))
661             key_heap_insert (hi, rbuf, r, kf[i]);
662     if (zh->service->isams)
663         heap_inps (hi);
664 #if ZMBOL
665     else if (zh->service->isamc)
666         heap_inpc (hi);
667     else if (zh->service->isam)
668         heap_inp (hi);
669     else if (zh->service->isamd)
670         heap_inpd (hi);
671 #endif
672         
673     for (i = 1; i<=nkeys; i++)
674     {
675         extract_get_fname_tmp  (zh, rbuf, i);
676         unlink (rbuf);
677     }
678     logf (LOG_LOG, "Iterations . . .%7d", no_iterations);
679     logf (LOG_LOG, "Distinct words .%7d", no_diffs);
680     logf (LOG_LOG, "Updates. . . . .%7d", no_updates);
681     logf (LOG_LOG, "Deletions. . . .%7d", no_deletions);
682     logf (LOG_LOG, "Insertions . . .%7d", no_insertions);
683     zh->key_file_no = 0;
684 }
685
686 void key_input (BFiles bfs, int nkeys, int cache, Res res)
687                 
688 {
689     Dict dict;
690     ISAMS isams = NULL;
691 #if ZMBOL
692     ISAM isam = NULL;
693     ISAMC isamc = NULL;
694     ISAMD isamd = NULL;
695 #endif
696     struct key_file **kf;
697     char rbuf[1024];
698     int i, r;
699     struct heap_info *hi;
700     struct progressInfo progressInfo;
701
702     if (nkeys < 0)
703     {
704         char fname[1024];
705         nkeys = 0;
706         while (1)
707         {
708             getFnameTmp (res, fname, nkeys+1);
709             if (access (fname, R_OK) == -1)
710                 break;
711             nkeys++;
712         }
713         if (!nkeys)
714             return ;
715     }
716     dict = dict_open (bfs, FNAME_DICT, cache, 1, 0);
717     if (!dict)
718     {
719         logf (LOG_FATAL, "dict_open fail");
720         exit (1);
721     }
722     if (res_get_match (res, "isam", "s", ISAM_DEFAULT))
723     {
724         struct ISAMS_M_s isams_m;
725         isams = isams_open (bfs, FNAME_ISAMS, 1,
726                             key_isams_m (res, &isams_m));
727         if (!isams)
728         {
729             logf (LOG_FATAL, "isams_open fail");
730             exit (1);
731         }
732         logf (LOG_LOG, "isams opened");
733     }
734 #if ZMBOL
735     else if (res_get_match (res, "isam", "i", ISAM_DEFAULT))
736     {
737         isam = is_open (bfs, FNAME_ISAM, key_compare, 1,
738                         sizeof(struct it_key), res);
739         if (!isam)
740         {
741             logf (LOG_FATAL, "is_open fail");
742             exit (1);
743         }
744     }
745     else if (res_get_match (res, "isam", "d", ISAM_DEFAULT))
746     {
747         struct ISAMD_M_s isamd_m;
748         isamd = isamd_open (bfs, FNAME_ISAMD, 1,
749                           key_isamd_m (res,&isamd_m));
750         if (!isamd)
751         {
752             logf (LOG_FATAL, "isamd_open fail");
753             exit (1);
754         }
755     }
756     else if (res_get_match (res, "isam", "c", ISAM_DEFAULT))
757     {
758         struct ISAMC_M_s isamc_m;
759         isamc = isc_open (bfs, FNAME_ISAMC, 1,
760                           key_isamc_m (res, &isamc_m));
761         if (!isamc)
762         {
763             logf (LOG_FATAL, "isc_open fail");
764             exit (1);
765         }
766     }
767 #endif
768     kf = (struct key_file **) xmalloc ((1+nkeys) * sizeof(*kf));
769     progressInfo.totalBytes = 0;
770     progressInfo.totalOffset = 0;
771     time (&progressInfo.startTime);
772     time (&progressInfo.lastTime);
773     for (i = 1; i<=nkeys; i++)
774     {
775         kf[i] = key_file_init (i, 8192, res);
776         kf[i]->readHandler = progressFunc;
777         kf[i]->readInfo = &progressInfo;
778         progressInfo.totalBytes += kf[i]->length;
779         progressInfo.totalOffset += kf[i]->buf_size;
780     }
781     hi = key_heap_init (nkeys, key_qsort_compare);
782     hi->dict = dict;
783     hi->isams = isams;
784 #if ZMBOL
785     hi->isam = isam;
786     hi->isamc = isamc;
787     hi->isamd = isamd;
788 #endif
789     
790     for (i = 1; i<=nkeys; i++)
791         if ((r = key_file_read (kf[i], rbuf)))
792             key_heap_insert (hi, rbuf, r, kf[i]);
793     if (isams)
794         heap_inps (hi);
795 #if ZMBOL
796     else if (isamc)
797         heap_inpc (hi);
798     else if (isam)
799         heap_inp (hi);
800     else if (isamd)
801         heap_inpd (hi);
802 #endif
803         
804     dict_close (dict);
805     if (isams)
806         isams_close (isams);
807 #if ZMBOL
808     if (isam)
809         is_close (isam);
810     if (isamc)
811         isc_close (isamc);
812     if (isamd)
813         isamd_close (isamd);
814 #endif
815    
816     for (i = 1; i<=nkeys; i++)
817     {
818         getFnameTmp (res, rbuf, i);
819         unlink (rbuf);
820     }
821     logf (LOG_LOG, "Iterations . . .%7d", no_iterations);
822     logf (LOG_LOG, "Distinct words .%7d", no_diffs);
823     logf (LOG_LOG, "Updates. . . . .%7d", no_updates);
824     logf (LOG_LOG, "Deletions. . . .%7d", no_deletions);
825     logf (LOG_LOG, "Insertions . . .%7d", no_insertions);
826
827     /* xmalloc_trav("unfreed"); while hunting leaks */     
828 }
829
830
831
832 /*
833  * $Log: kinput.c,v $
834  * Revision 1.44  2000-05-18 12:01:36  adam
835  * System call times(2) used again. More 64-bit fixes.
836  *
837  * Revision 1.43  2000/03/20 19:08:36  adam
838  * Added remote record import using Z39.50 extended services and Segment
839  * Requests.
840  *
841  * Revision 1.42  1999/12/01 21:58:48  adam
842  * Proper handle of illegal use of isams.
843  *
844  * Revision 1.41  1999/11/30 13:48:03  adam
845  * Improved installation. Updated for inclusion of YAZ header files.
846  *
847  * Revision 1.40  1999/09/08 12:12:39  adam
848  * Removed log message.
849  *
850  * Revision 1.39  1999/08/18 10:39:20  heikki
851  * Added a comment on memory leaks
852  *
853  * Revision 1.38  1999/08/18 08:38:04  heikki
854  * Memory leak hunting
855  *
856  * Revision 1.37  1999/07/14 13:21:34  heikki
857  * Added isam-d files. Compiles (almost) clean. Doesn't work at all
858  *
859  * Revision 1.36  1999/07/14 10:59:26  adam
860  * Changed functions isc_getmethod, isams_getmethod.
861  * Improved fatal error handling (such as missing EXPLAIN schema).
862  *
863  * Revision 1.35  1999/06/30 15:07:23  heikki
864  * Adding isamh stuff
865  *
866  * Revision 1.34  1999/05/26 07:49:13  adam
867  * C++ compilation.
868  *
869  * Revision 1.33  1999/05/15 14:36:38  adam
870  * Updated dictionary. Implemented "compression" of dictionary.
871  *
872  * Revision 1.32  1999/05/12 13:08:06  adam
873  * First version of ISAMS.
874  *
875  * Revision 1.31  1999/02/02 14:50:56  adam
876  * Updated WIN32 code specific sections. Changed header.
877  *
878  * Revision 1.30  1998/10/28 10:53:57  adam
879  * Added type cast to prevent warning.
880  *
881  * Revision 1.29  1998/06/11 15:41:39  adam
882  * Minor changes.
883  *
884  * Revision 1.28  1998/03/05 08:45:12  adam
885  * New result set model and modular ranking system. Moved towards
886  * descent server API. System information stored as "SGML" records.
887  *
888  * Revision 1.27  1998/02/17 10:32:52  adam
889  * Fixed bug: binary files weren't opened with flag b on NT.
890  *
891  * Revision 1.26  1998/01/29 13:39:13  adam
892  * Compress ISAM is default.
893  *
894  * Revision 1.25  1997/09/17 12:19:14  adam
895  * Zebra version corresponds to YAZ version 1.4.
896  * Changed Zebra server so that it doesn't depend on global common_resource.
897  *
898  * Revision 1.24  1997/09/09 13:38:07  adam
899  * Partial port to WIN95/NT.
900  *
901  * Revision 1.23  1997/09/04 13:57:39  adam
902  * Added O_BINARY for open calls.
903  *
904  * Revision 1.22  1997/02/12 20:39:45  adam
905  * Implemented options -f <n> that limits the log to the first <n>
906  * records.
907  * Changed some log messages also.
908  *
909  * Revision 1.21  1996/11/08 11:10:23  adam
910  * Buffers used during file match got bigger.
911  * Compressed ISAM support everywhere.
912  * Bug fixes regarding masking characters in queries.
913  * Redesigned Regexp-2 queries.
914  *
915  * Revision 1.20  1996/11/01 08:58:41  adam
916  * Interface to isamc system now includes update and delete.
917  *
918  * Revision 1.19  1996/10/29 14:09:46  adam
919  * Use of cisam system - enabled if setting isamc is 1.
920  *
921  * Revision 1.18  1996/06/04 10:18:59  adam
922  * Minor changes - removed include of ctype.h.
923  *
924  * Revision 1.17  1996/05/14  15:47:07  adam
925  * Cleanup of various buffer size entities.
926  *
927  * Revision 1.16  1996/04/09  10:05:20  adam
928  * Bug fix: prev_name buffer possibly too small; allocated in key_file_init.
929  *
930  * Revision 1.15  1996/03/21  14:50:09  adam
931  * File update uses modify-time instead of change-time.
932  *
933  * Revision 1.14  1996/02/07  14:06:37  adam
934  * Better progress report during register merge.
935  * New command: clean - removes temporary shadow files.
936  *
937  * Revision 1.13  1996/02/05  12:30:00  adam
938  * Logging reduced a bit.
939  * The remaining running time is estimated during register merge.
940  *
941  * Revision 1.12  1995/12/06  17:49:19  adam
942  * Uses dict_delete now.
943  *
944  * Revision 1.11  1995/12/06  16:06:43  adam
945  * Better diagnostics. Work on 'real' dictionary deletion.
946  *
947  * Revision 1.10  1995/12/06  12:41:22  adam
948  * New command 'stat' for the index program.
949  * Filenames can be read from stdin by specifying '-'.
950  * Bug fix/enhancement of the transformation from terms to regular
951  * expressons in the search engine.
952  *
953  * Revision 1.9  1995/10/10  12:24:39  adam
954  * Temporary sort files are compressed.
955  *
956  * Revision 1.8  1995/10/04  16:57:19  adam
957  * Key input and merge sort in one pass.
958  *
959  * Revision 1.7  1995/10/02  15:18:52  adam
960  * New member in recRetrieveCtrl: diagnostic.
961  *
962  * Revision 1.6  1995/09/29  15:51:56  adam
963  * First work on multi-way read.
964  *
965  * Revision 1.5  1995/09/29  14:01:43  adam
966  * Bug fixes.
967  *
968  * Revision 1.4  1995/09/28  14:22:57  adam
969  * Sort uses smaller temporary files.
970  *
971  * Revision 1.3  1995/09/06  16:11:17  adam
972  * Option: only one word key per file.
973  *
974  * Revision 1.2  1995/09/04  12:33:42  adam
975  * Various cleanup. YAZ util used instead.
976  *
977  * Revision 1.1  1995/09/04  09:10:37  adam
978  * More work on index add/del/update.
979  * Merge sort implemented.
980  * Initial work on z39 server.
981  *
982  */
983