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