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