Temporary sort files are compressed.
[idzebra-moved-to-github.git] / index / kinput.c
1 /*
2  * Copyright (C) 1994-1995, Index Data I/S 
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: kinput.c,v $
7  * Revision 1.9  1995-10-10 12:24:39  adam
8  * Temporary sort files are compressed.
9  *
10  * Revision 1.8  1995/10/04  16:57:19  adam
11  * Key input and merge sort in one pass.
12  *
13  * Revision 1.7  1995/10/02  15:18:52  adam
14  * New member in recRetrieveCtrl: diagnostic.
15  *
16  * Revision 1.6  1995/09/29  15:51:56  adam
17  * First work on multi-way read.
18  *
19  * Revision 1.5  1995/09/29  14:01:43  adam
20  * Bug fixes.
21  *
22  * Revision 1.4  1995/09/28  14:22:57  adam
23  * Sort uses smaller temporary files.
24  *
25  * Revision 1.3  1995/09/06  16:11:17  adam
26  * Option: only one word key per file.
27  *
28  * Revision 1.2  1995/09/04  12:33:42  adam
29  * Various cleanup. YAZ util used instead.
30  *
31  * Revision 1.1  1995/09/04  09:10:37  adam
32  * More work on index add/del/update.
33  * Merge sort implemented.
34  * Initial work on z39 server.
35  *
36  */
37
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <ctype.h>
44 #include <assert.h>
45
46 #include "index.h"
47
48 #define KEY_SIZE (1+sizeof(struct it_key))
49 #define INP_NAME_MAX 8192
50 #define INP_BUF_START 60000
51 #define INP_BUF_ADD  400000
52
53 static int no_diffs   = 0;
54 static int no_updates = 0;
55 static int no_insertions = 0;
56 static int no_iterations = 0;
57
58 struct key_file {
59     int   no;            /* file no */
60     off_t offset;        /* file offset */
61     unsigned char *buf;  /* buffer block */
62     size_t buf_size;     /* number of read bytes in block */
63     size_t chunk;        /* number of bytes allocated */
64     size_t buf_ptr;      /* current position in buffer */
65     char *prev_name;     /* last word read */
66     int   sysno;         /* last sysno */
67     int   seqno;         /* last seqno */
68 };
69
70 void key_file_chunk_read (struct key_file *f)
71 {
72     int nr = 0, r, fd;
73     char fname[256];
74     sprintf (fname, TEMP_FNAME, f->no);
75     fd = open (fname, O_RDONLY);
76     if (fd == -1)
77     {
78         logf (LOG_FATAL|LOG_ERRNO, "cannot open %s", fname);
79         exit (1);
80     }
81     logf (LOG_LOG, "reading chunk from %s", fname);
82     if (lseek (fd, f->offset, SEEK_SET) == -1)
83     {
84         logf (LOG_FATAL|LOG_ERRNO, "cannot seek %s", fname);
85         exit (1);
86     }
87     while (f->chunk - nr > 0)
88     {
89         r = read (fd, f->buf + nr, f->chunk - nr);
90         if (r <= 0)
91             break;
92         nr += r;
93     }
94     if (r == -1)
95     {
96         logf (LOG_FATAL|LOG_ERRNO, "read of %s", fname);
97         exit (1);
98     }
99     f->buf_size = nr;
100     f->buf_ptr = 0;
101     close (fd);
102 }
103
104 struct key_file *key_file_init (int no, int chunk)
105 {
106     struct key_file *f;
107
108     f = xmalloc (sizeof(*f));
109     f->sysno = 0;
110     f->seqno = 0;
111     f->no = no;
112     f->chunk = chunk;
113     f->offset = 0;
114     f->buf = xmalloc (f->chunk);
115     f->prev_name = xmalloc (256);
116     *f->prev_name = '\0';
117     key_file_chunk_read (f);
118     return f;
119 }
120
121 int key_file_getc (struct key_file *f)
122 {
123     if (f->buf_ptr < f->buf_size)
124         return f->buf[(f->buf_ptr)++];
125     if (f->buf_size < f->chunk)
126         return EOF;
127     f->offset += f->buf_size;
128     key_file_chunk_read (f);
129     if (f->buf_ptr < f->buf_size)
130         return f->buf[(f->buf_ptr)++];
131     else
132         return EOF;
133 }
134
135 int key_file_decode (struct key_file *f)
136 {
137     int c, d;
138
139     c = key_file_getc (f);
140     switch (c & 192) 
141     {
142     case 0:
143         d = c;
144         break;
145     case 64:
146         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
147         break;
148     case 128:
149         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
150         d = (d << 8) + (key_file_getc (f) & 0xff);
151         break;
152     case 192:
153         d = ((c&63) << 8) + (key_file_getc (f) & 0xff);
154         d = (d << 8) + (key_file_getc (f) & 0xff);
155         d = (d << 8) + (key_file_getc (f) & 0xff);
156         break;
157     }
158     return d;
159 }
160
161 int key_file_read (struct key_file *f, char *key)
162 {
163     int i, d, c;
164     struct it_key itkey;
165
166     c = key_file_getc (f);
167     if (c == 0)
168     {
169         strcpy (key, f->prev_name);
170         i = 1+strlen (key);
171     }
172     else if (c == EOF)
173         return 0;
174     else
175     {
176         i = 0;
177         key[i++] = c;
178         while ((key[i++] = key_file_getc (f)))
179             ;
180         strcpy (f->prev_name, key);
181         f->sysno = 0;
182     }
183     d = key_file_decode (f);
184     key[i++] = d & 1;
185     d = d >> 1;
186     itkey.sysno = d + f->sysno;
187     if (d) 
188     {
189         f->sysno = itkey.sysno;
190         f->seqno = 0;
191     }
192     d = key_file_decode (f);
193     itkey.seqno = d + f->seqno;
194     f->seqno = itkey.seqno;
195     memcpy (key + i, &itkey, sizeof(struct it_key));
196     return i + sizeof (struct it_key);
197 }
198
199 struct heap_info {
200     struct {
201         struct key_file **file;
202         char   **buf;
203     } info;
204     int    heapnum;
205     int    *ptr;
206     int    (*cmp)(const void *p1, const void *p2);
207 };
208
209 struct heap_info *key_heap_init (int nkeys,
210                                  int (*cmp)(const void *p1, const void *p2))
211 {
212     struct heap_info *hi;
213     int i;
214
215     hi = xmalloc (sizeof(*hi));
216     hi->info.file = xmalloc (sizeof(*hi->info.file) * (1+nkeys));
217     hi->info.buf = xmalloc (sizeof(*hi->info.buf) * (1+nkeys));
218     hi->heapnum = 0;
219     hi->ptr = xmalloc (sizeof(*hi->ptr) * (1+nkeys));
220     hi->cmp = cmp;
221     for (i = 0; i<= nkeys; i++)
222     {
223         hi->ptr[i] = i;
224         hi->info.buf[i] = xmalloc (512);
225     }
226     return hi;
227 }
228
229 static void key_heap_swap (struct heap_info *hi, int i1, int i2)
230 {
231     int swap;
232
233     swap = hi->ptr[i1];
234     hi->ptr[i1] = hi->ptr[i2];
235     hi->ptr[i2] = swap;
236 }
237
238
239 static void key_heap_delete (struct heap_info *hi)
240 {
241     int cur = 1, child = 2;
242
243     assert (hi->heapnum > 0);
244
245     key_heap_swap (hi, 1, hi->heapnum);
246     hi->heapnum--;
247     while (child <= hi->heapnum) {
248         if (child < hi->heapnum &&
249             (*hi->cmp)(&hi->info.buf[hi->ptr[child]],
250                        &hi->info.buf[hi->ptr[child+1]]) > 0)
251             child++;
252         if ((*hi->cmp)(&hi->info.buf[hi->ptr[cur]],
253                        &hi->info.buf[hi->ptr[child]]) > 0)
254         {            
255             key_heap_swap (hi, cur, child);
256             cur = child;
257             child = 2*cur;
258         }
259         else
260             break;
261     }
262 }
263
264 static void key_heap_insert (struct heap_info *hi, const char *buf, int nbytes,
265                              struct key_file *kf)
266 {
267     int cur, parent;
268
269     cur = ++(hi->heapnum);
270     memcpy (hi->info.buf[hi->ptr[cur]], buf, nbytes);
271     hi->info.file[hi->ptr[cur]] = kf;
272
273     parent = cur/2;
274     while (parent && (*hi->cmp)(&hi->info.buf[hi->ptr[parent]],
275                                 &hi->info.buf[hi->ptr[cur]]) > 0)
276     {
277         key_heap_swap (hi, cur, parent);
278         cur = parent;
279         parent = cur/2;
280     }
281 }
282
283 static int heap_read_one (struct heap_info *hi, char *name, char *key)
284 {
285     int n, r;
286     char rbuf[512];
287     struct key_file *kf;
288
289     if (!hi->heapnum)
290         return 0;
291     n = hi->ptr[1];
292     strcpy (name, hi->info.buf[n]);
293     kf = hi->info.file[n];
294     r = strlen(name);
295     memcpy (key, hi->info.buf[n] + r+1, KEY_SIZE);
296     key_heap_delete (hi);
297     if ((r = key_file_read (kf, rbuf)))
298         key_heap_insert (hi, rbuf, r, kf);
299     no_iterations++;
300     return 1;
301 }
302
303 int heap_inp (Dict dict, ISAM isam, struct heap_info *hi)
304 {
305     char *info;
306     char next_name[INP_NAME_MAX+1];
307     char cur_name[INP_NAME_MAX+1];
308     int key_buf_size = INP_BUF_START;
309     int key_buf_ptr;
310     char *next_key;
311     char *key_buf;
312     int more;
313     
314     next_key = xmalloc (KEY_SIZE);
315     key_buf = xmalloc (key_buf_size * (KEY_SIZE));
316     more = heap_read_one (hi, cur_name, key_buf);
317     while (more)                   /* EOF ? */
318     {
319         int nmemb;
320         key_buf_ptr = KEY_SIZE;
321         while (1)
322         {
323             if (!(more = heap_read_one (hi, next_name, next_key)))
324                 break;
325             if (*next_name && strcmp (next_name, cur_name))
326                 break;
327             memcpy (key_buf + key_buf_ptr, next_key, KEY_SIZE);
328             key_buf_ptr += KEY_SIZE;
329             if (key_buf_ptr+KEY_SIZE >= key_buf_size)
330             {
331                 char *new_key_buf;
332                 new_key_buf = xmalloc (key_buf_size + INP_BUF_ADD);
333                 memcpy (new_key_buf, key_buf, key_buf_size);
334                 key_buf_size += INP_BUF_ADD;
335                 xfree (key_buf);
336                 key_buf = new_key_buf;
337             }
338         }
339         no_diffs++;
340         nmemb = key_buf_ptr / KEY_SIZE;
341         assert (nmemb*KEY_SIZE == key_buf_ptr);
342         if ((info = dict_lookup (dict, cur_name)))
343         {
344             ISAM_P isam_p, isam_p2;
345             logf (LOG_DEBUG, "updating %s", cur_name);
346             no_updates++;
347             memcpy (&isam_p, info+1, sizeof(ISAM_P));
348             isam_p2 = is_merge (isam, isam_p, nmemb, key_buf);
349             if (isam_p2 != isam_p)
350                 dict_insert (dict, cur_name, sizeof(ISAM_P), &isam_p2);
351         }
352         else
353         {
354             ISAM_P isam_p;
355             logf (LOG_DEBUG, "inserting %s", cur_name);
356             no_insertions++;
357             isam_p = is_merge (isam, 0, nmemb, key_buf);
358             dict_insert (dict, cur_name, sizeof(ISAM_P), &isam_p);
359         }
360         memcpy (key_buf, next_key, KEY_SIZE);
361         strcpy (cur_name, next_name);
362     }
363     return 0;
364 }
365
366 void key_input (const char *dict_fname, const char *isam_fname,
367                  int nkeys, int cache)
368 {
369     Dict dict;
370     ISAM isam;
371     struct key_file **kf;
372     char rbuf[1024];
373     int i, r;
374     struct heap_info *hi;
375
376     dict = dict_open (dict_fname, cache, 1);
377     if (!dict)
378     {
379         logf (LOG_FATAL, "dict_open fail of `%s'", dict_fname);
380         exit (1);
381     }
382     isam = is_open (isam_fname, key_compare, 1, sizeof(struct it_key));
383     if (!isam)
384     {
385         logf (LOG_FATAL, "is_open fail of `%s'", isam_fname);
386         exit (1);
387     }
388
389     kf = xmalloc ((1+nkeys) * sizeof(*kf));
390     for (i = 1; i<=nkeys; i++)
391         kf[i] = key_file_init (i, 32768);
392     
393     hi = key_heap_init (nkeys, key_qsort_compare);
394     for (i = 1; i<=nkeys; i++)
395         if ((r = key_file_read (kf[i], rbuf)))
396             key_heap_insert (hi, rbuf, r, kf[i]);
397     heap_inp (dict, isam, hi);
398
399     dict_close (dict);
400     is_close (isam);
401
402     logf (LOG_LOG, "Iterations . . .%7d", no_iterations);
403     logf (LOG_LOG, "Distinct words .%7d", no_diffs);
404     logf (LOG_LOG, "Updates. . . . .%7d", no_updates);
405     logf (LOG_LOG, "Insertions . . .%7d", no_insertions);
406 }
407
408