System call times(2) used again. More 64-bit fixes.
[idzebra-moved-to-github.git] / index / trunc.c
1 /*
2  * Copyright (C) 1994-1999, Index Data
3  * All rights reserved.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: trunc.c,v $
7  * Revision 1.18  2000-05-18 12:01:36  adam
8  * System call times(2) used again. More 64-bit fixes.
9  *
10  * Revision 1.17  2000/03/15 15:00:30  adam
11  * First work on threaded version.
12  *
13  * Revision 1.16  1999/11/30 13:48:03  adam
14  * Improved installation. Updated for inclusion of YAZ header files.
15  *
16  * Revision 1.15  1999/07/20 13:59:18  adam
17  * Fixed bug that occurred when phrases had 0 hits.
18  *
19  * Revision 1.14  1999/05/26 07:49:13  adam
20  * C++ compilation.
21  *
22  * Revision 1.13  1999/05/12 13:08:06  adam
23  * First version of ISAMS.
24  *
25  * Revision 1.12  1999/02/02 14:51:10  adam
26  * Updated WIN32 code specific sections. Changed header.
27  *
28  * Revision 1.11  1998/03/25 13:48:02  adam
29  * Fixed bug in rset_trunc_r.
30  *
31  * Revision 1.10  1998/03/05 08:45:13  adam
32  * New result set model and modular ranking system. Moved towards
33  * descent server API. System information stored as "SGML" records.
34  *
35  * Revision 1.9  1998/01/12 15:04:09  adam
36  * The test option (-s) only uses read-lock (and not write lock).
37  *
38  * Revision 1.8  1997/10/31 12:34:27  adam
39  * Bug fix: memory leak.
40  *
41  * Revision 1.7  1997/09/29 09:07:29  adam
42  * Minor change.
43  *
44  * Revision 1.6  1997/09/22 12:39:06  adam
45  * Added get_pos method for the ranked result sets.
46  *
47  * Revision 1.5  1997/09/17 12:19:17  adam
48  * Zebra version corresponds to YAZ version 1.4.
49  * Changed Zebra server so that it doesn't depend on global common_resource.
50  *
51  * Revision 1.4  1996/12/23 15:30:44  adam
52  * Work on truncation.
53  * Bug fix: result sets weren't deleted after server shut down.
54  *
55  * Revision 1.3  1996/12/20 11:07:14  adam
56  * Multi-or result set.
57  *
58  * Revision 1.2  1996/11/08 11:10:28  adam
59  * Buffers used during file match got bigger.
60  * Compressed ISAM support everywhere.
61  * Bug fixes regarding masking characters in queries.
62  * Redesigned Regexp-2 queries.
63  *
64  * Revision 1.1  1996/11/04 14:07:40  adam
65  * Moved truncation code to trunc.c.
66  *
67  */
68 #include <stdio.h>
69 #include <assert.h>
70
71 #define NEW_TRUNC 1
72
73 #include "zserver.h"
74 #include <rstemp.h>
75 #include <rsnull.h>
76 #include <rsisams.h>
77 #if ZMBOL
78 #include <rsisam.h>
79 #include <rsisamc.h>
80 #if NEW_TRUNC
81 #include <rsm_or.h>
82 #endif
83 #endif
84
85 struct trunc_info {
86     int  *ptr;
87     int  *indx;
88     char **heap;
89     int  heapnum;
90     int  (*cmp)(const void *p1, const void *p2);
91     int  keysize;
92     char *swapbuf;
93     char *tmpbuf;
94     char *buf;
95 };
96
97 static void heap_swap (struct trunc_info *ti, int i1, int i2)
98 {
99     int swap;
100
101     swap = ti->ptr[i1];
102     ti->ptr[i1] = ti->ptr[i2];
103     ti->ptr[i2] = swap;
104 }
105
106 static void heap_delete (struct trunc_info *ti)
107 {
108     int cur = 1, child = 2;
109
110     heap_swap (ti, 1, ti->heapnum--);
111     while (child <= ti->heapnum) {
112         if (child < ti->heapnum &&
113             (*ti->cmp)(ti->heap[ti->ptr[child]],
114                        ti->heap[ti->ptr[1+child]]) > 0)
115             child++;
116         if ((*ti->cmp)(ti->heap[ti->ptr[cur]],
117                        ti->heap[ti->ptr[child]]) > 0)
118         {
119             heap_swap (ti, cur, child);
120             cur = child;
121             child = 2*cur;
122         }
123         else
124             break;
125     }
126 }
127
128 static void heap_insert (struct trunc_info *ti, const char *buf, int indx)
129 {
130     int cur, parent;
131
132     cur = ++(ti->heapnum);
133     memcpy (ti->heap[ti->ptr[cur]], buf, ti->keysize);
134     ti->indx[ti->ptr[cur]] = indx;
135     parent = cur/2;
136     while (parent && (*ti->cmp)(ti->heap[ti->ptr[parent]],
137                                 ti->heap[ti->ptr[cur]]) > 0)
138     {
139         heap_swap (ti, cur, parent);
140         cur = parent;
141         parent = cur/2;
142     }
143 }
144
145 static struct trunc_info *heap_init (int size, int key_size,
146                                      int (*cmp)(const void *p1,
147                                                 const void *p2))
148 {
149     struct trunc_info *ti = (struct trunc_info *) xmalloc (sizeof(*ti));
150     int i;
151
152     ++size;
153     ti->heapnum = 0;
154     ti->keysize = key_size;
155     ti->cmp = cmp;
156     ti->indx = (int *) xmalloc (size * sizeof(*ti->indx));
157     ti->heap = (char **) xmalloc (size * sizeof(*ti->heap));
158     ti->ptr = (int *) xmalloc (size * sizeof(*ti->ptr));
159     ti->swapbuf = (char *) xmalloc (ti->keysize);
160     ti->tmpbuf = (char *) xmalloc (ti->keysize);
161     ti->buf = (char *) xmalloc (size * ti->keysize);
162     for (i = size; --i >= 0; )
163     {
164         ti->ptr[i] = i;
165         ti->heap[i] = ti->buf + ti->keysize * i;
166     }
167     return ti;
168 }
169
170 static void heap_close (struct trunc_info *ti)
171 {
172     xfree (ti->ptr);
173     xfree (ti->indx);
174     xfree (ti->heap);
175     xfree (ti->swapbuf);
176     xfree (ti->tmpbuf);
177     xfree (ti->buf);
178     xfree (ti);
179 }
180
181 static RSET rset_trunc_r (ZebraHandle zi, const char *term, int length,
182                          const char *flags, ISAMS_P *isam_p, int from, int to,
183                          int merge_chunk)
184 {
185     RSET result; 
186     RSFD result_rsfd;
187     rset_temp_parms parms;
188
189     parms.key_size = sizeof(struct it_key);
190     parms.temp_path = res_get (zi->service->res, "setTmpDir");
191     parms.rset_term = rset_term_create (term, length, flags);
192     result = rset_create (rset_kind_temp, &parms);
193     result_rsfd = rset_open (result, RSETF_WRITE);
194
195     if (to - from > merge_chunk)
196     {
197         RSFD *rsfd;
198         RSET *rset;
199         int term_index;
200         int i, i_add = (to-from)/merge_chunk + 1;
201         struct trunc_info *ti;
202         int rscur = 0;
203         int rsmax = (to-from)/i_add + 1;
204         
205         rset = (RSET *) xmalloc (sizeof(*rset) * rsmax);
206         rsfd = (RSFD *) xmalloc (sizeof(*rsfd) * rsmax);
207         
208         for (i = from; i < to; i += i_add)
209         {
210             if (i_add <= to - i)
211                 rset[rscur] = rset_trunc_r (zi, term, length, flags,
212                                             isam_p, i, i+i_add, merge_chunk);
213             else
214                 rset[rscur] = rset_trunc_r (zi, term, length, flags,
215                                             isam_p, i, to, merge_chunk);
216             rscur++;
217         }
218         ti = heap_init (rscur, sizeof(struct it_key), key_compare_it);
219         for (i = rscur; --i >= 0; )
220         {
221             rsfd[i] = rset_open (rset[i], RSETF_READ);
222             if (rset_read (rset[i], rsfd[i], ti->tmpbuf, &term_index))
223                 heap_insert (ti, ti->tmpbuf, i);
224             else
225             {
226                 rset_close (rset[i], rsfd[i]);
227                 rset_delete (rset[i]);
228             }
229         }
230         while (ti->heapnum)
231         {
232             int n = ti->indx[ti->ptr[1]];
233
234             rset_write (result, result_rsfd, ti->heap[ti->ptr[1]]);
235
236             while (1)
237             {
238                 if (!rset_read (rset[n], rsfd[n], ti->tmpbuf, &term_index))
239                 {
240                     heap_delete (ti);
241                     rset_close (rset[n], rsfd[n]);
242                     rset_delete (rset[n]);
243                     break;
244                 }
245                 if ((*ti->cmp)(ti->tmpbuf, ti->heap[ti->ptr[1]]) > 1)
246                 {
247                     heap_delete (ti);
248                     heap_insert (ti, ti->tmpbuf, n);
249                     break;
250                 }
251             }
252         }
253         xfree (rset);
254         xfree (rsfd);
255         heap_close (ti);
256     }
257 #if ZMBOL
258     else if (zi->service->isam)
259     {
260         ISPT *ispt;
261         int i;
262         struct trunc_info *ti;
263
264         ispt = (ISPT *) xmalloc (sizeof(*ispt) * (to-from));
265
266         ti = heap_init (to-from, sizeof(struct it_key),
267                         key_compare_it);
268         for (i = to-from; --i >= 0; )
269         {
270             ispt[i] = is_position (zi->service->isam, isam_p[from+i]);
271             if (is_readkey (ispt[i], ti->tmpbuf))
272                 heap_insert (ti, ti->tmpbuf, i);
273             else
274                 is_pt_free (ispt[i]);
275         }
276         while (ti->heapnum)
277         {
278             int n = ti->indx[ti->ptr[1]];
279
280             rset_write (result, result_rsfd, ti->heap[ti->ptr[1]]);
281 #if 1
282 /* section that preserve all keys */
283             heap_delete (ti);
284             if (is_readkey (ispt[n], ti->tmpbuf))
285                 heap_insert (ti, ti->tmpbuf, n);
286             else
287                 is_pt_free (ispt[n]);
288 #else
289 /* section that preserve all keys with unique sysnos */
290             while (1)
291             {
292                 if (!is_readkey (ispt[n], ti->tmpbuf))
293                 {
294                     heap_delete (ti);
295                     is_pt_free (ispt[n]);
296                     break;
297                 }
298                 if ((*ti->cmp)(ti->tmpbuf, ti->heap[ti->ptr[1]]) > 1)
299                 {
300                     heap_delete (ti);
301                     heap_insert (ti, ti->tmpbuf, n);
302                     break;
303                 }
304             }
305 #endif
306         }
307         heap_close (ti);
308         xfree (ispt);
309     }
310     else if (zi->service->isamc)
311     {
312         ISAMC_PP *ispt;
313         int i;
314         struct trunc_info *ti;
315
316         ispt = (ISAMC_PP *) xmalloc (sizeof(*ispt) * (to-from));
317
318         ti = heap_init (to-from, sizeof(struct it_key),
319                         key_compare_it);
320         for (i = to-from; --i >= 0; )
321         {
322             ispt[i] = isc_pp_open (zi->service->isamc, isam_p[from+i]);
323             if (isc_pp_read (ispt[i], ti->tmpbuf))
324                 heap_insert (ti, ti->tmpbuf, i);
325             else
326                 isc_pp_close (ispt[i]);
327         }
328         while (ti->heapnum)
329         {
330             int n = ti->indx[ti->ptr[1]];
331
332             rset_write (result, result_rsfd, ti->heap[ti->ptr[1]]);
333 #if 0
334 /* section that preserve all keys */
335             heap_delete (ti);
336             if (isc_pp_read (ispt[n], ti->tmpbuf))
337                 heap_insert (ti, ti->tmpbuf, n);
338             else
339                 isc_pp_close (ispt[n]);
340 #else
341 /* section that preserve all keys with unique sysnos */
342             while (1)
343             {
344                 if (!isc_pp_read (ispt[n], ti->tmpbuf))
345                 {
346                     heap_delete (ti);
347                     isc_pp_close (ispt[n]);
348                     break;
349                 }
350                 if ((*ti->cmp)(ti->tmpbuf, ti->heap[ti->ptr[1]]) > 1)
351                 {
352                     heap_delete (ti);
353                     heap_insert (ti, ti->tmpbuf, n);
354                     break;
355                 }
356             }
357 #endif
358         }
359         heap_close (ti);
360         xfree (ispt);
361     }
362 #endif
363     else if (zi->service->isams)
364     {
365         ISAMS_PP *ispt;
366         int i;
367         struct trunc_info *ti;
368
369         ispt = (ISAMS_PP *) xmalloc (sizeof(*ispt) * (to-from));
370
371         ti = heap_init (to-from, sizeof(struct it_key),
372                         key_compare_it);
373         for (i = to-from; --i >= 0; )
374         {
375             ispt[i] = isams_pp_open (zi->service->isams, isam_p[from+i]);
376             if (isams_pp_read (ispt[i], ti->tmpbuf))
377                 heap_insert (ti, ti->tmpbuf, i);
378             else
379                 isams_pp_close (ispt[i]);
380         }
381         while (ti->heapnum)
382         {
383             int n = ti->indx[ti->ptr[1]];
384
385             rset_write (result, result_rsfd, ti->heap[ti->ptr[1]]);
386             while (1)
387             {
388                 if (!isams_pp_read (ispt[n], ti->tmpbuf))
389                 {
390                     heap_delete (ti);
391                     isams_pp_close (ispt[n]);
392                     break;
393                 }
394                 if ((*ti->cmp)(ti->tmpbuf, ti->heap[ti->ptr[1]]) > 1)
395                 {
396                     heap_delete (ti);
397                     heap_insert (ti, ti->tmpbuf, n);
398                     break;
399                 }
400             }
401         }
402         heap_close (ti);
403         xfree (ispt);
404     }
405     rset_close (result, result_rsfd);
406     return result;
407 }
408
409 static int isams_trunc_cmp (const void *p1, const void *p2)
410 {
411     ISAMS_P i1 = *(ISAMS_P*) p1;
412     ISAMS_P i2 = *(ISAMS_P*) p2;
413
414     return i1 - i2;
415 }
416
417 #if ZMBOL
418 static int isam_trunc_cmp (const void *p1, const void *p2)
419 {
420     ISAM_P i1 = *(ISAM_P*) p1;
421     ISAM_P i2 = *(ISAM_P*) p2;
422     int d;
423
424     d = is_type (i1) - is_type (i2);
425     if (d)
426         return d;
427     return is_block (i1) - is_block (i2);
428 }
429
430 static int isamc_trunc_cmp (const void *p1, const void *p2)
431 {
432     ISAMC_P i1 = *(ISAMC_P*) p1;
433     ISAMC_P i2 = *(ISAMC_P*) p2;
434     int d;
435
436     d = isc_type (i1) - isc_type (i2);
437     if (d)
438         return d;
439     return isc_block (i1) - isc_block (i2);
440 }
441 #endif
442
443 RSET rset_trunc (ZebraHandle zi, ISAMS_P *isam_p, int no,
444                  const char *term, int length, const char *flags)
445 {
446     logf (LOG_DEBUG, "rset_trunc no=%d", no);
447     if (no < 1)
448     {
449         rset_null_parms parms;
450         parms.rset_term = rset_term_create (term, length, flags);
451         return rset_create (rset_kind_null, &parms);
452     }
453     if (zi->service->isams)
454     {
455         if (no == 1)
456         {
457             rset_isams_parms parms;
458
459             parms.pos = *isam_p;
460             parms.is = zi->service->isams;
461             parms.rset_term = rset_term_create (term, length, flags);
462             return rset_create (rset_kind_isams, &parms);
463         }
464         qsort (isam_p, no, sizeof(*isam_p), isams_trunc_cmp);
465     }
466 #if ZMBOL
467     else if (zi->service->isam)
468     {
469         if (no == 1)
470         {
471             rset_isam_parms parms;
472
473             parms.pos = *isam_p;
474             parms.is = zi->service->isam;
475             parms.rset_term = rset_term_create (term, length, flags);
476             return rset_create (rset_kind_isam, &parms);
477         }
478         qsort (isam_p, no, sizeof(*isam_p), isam_trunc_cmp);
479     }
480     else if (zi->service->isamc)
481     {
482         if (no == 1)
483         {
484             rset_isamc_parms parms;
485
486             parms.pos = *isam_p;
487             parms.is = zi->service->isamc;
488             parms.rset_term = rset_term_create (term, length, flags);
489             return rset_create (rset_kind_isamc, &parms);
490         }
491 #if NEW_TRUNC
492         else if (no < 10000)
493         {
494             rset_m_or_parms parms;
495
496             parms.key_size = sizeof(struct it_key);
497             parms.cmp = key_compare_it;
498             parms.isc = zi->service->isamc;
499             parms.isam_positions = isam_p;
500             parms.no_isam_positions = no;
501             parms.no_save_positions = 100000;
502             parms.rset_term = rset_term_create (term, length, flags);
503             return rset_create (rset_kind_m_or, &parms);
504         }
505 #endif
506         qsort (isam_p, no, sizeof(*isam_p), isamc_trunc_cmp);
507     }
508 #endif
509     else
510     {
511         logf (LOG_WARN, "Neither isam / isamc / isams set in rset_trunc");
512         return rset_create (rset_kind_null, NULL);
513     }
514     return rset_trunc_r (zi, term, length, flags, isam_p, 0, no, 100);
515 }
516