Removed the VOLATILE flag from rsets
[idzebra-moved-to-github.git] / rset / rsbool.c
1 /* $Id: rsbool.c,v 1.39 2004-08-23 12:38:53 heikki Exp $
2    Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004
3    Index Data Aps
4
5 This file is part of the Zebra server.
6
7 Zebra is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Zebra; see the file LICENSE.zebra.  If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include <zebrautl.h>
29 #include <rset.h>
30 #include <rsbool.h>
31
32 #ifndef RSET_DEBUG
33 #define RSET_DEBUG 0
34 #endif
35
36 static void *r_create(RSET ct, const struct rset_control *sel, void *parms);
37 static RSFD r_open (RSET ct, int flag);
38 static void r_close (RSFD rfd);
39 static void r_delete (RSET ct);
40 static void r_rewind (RSFD rfd);
41 static int r_forward(RSET ct, RSFD rfd, void *buf,
42                      int (*cmpfunc)(const void *p1, const void *p2),
43                      const void *untilbuf);
44 static void r_pos (RSFD rfd, double *current, double *total); 
45 static int r_read_and (RSFD rfd, void *buf);
46 static int r_read_or (RSFD rfd, void *buf);
47 static int r_read_not (RSFD rfd, void *buf);
48 static int r_write (RSFD rfd, const void *buf);
49
50 static const struct rset_control control_and = 
51 {
52     "and",
53     r_create,
54     r_open,
55     r_close,
56     r_delete,
57     r_rewind,
58     r_forward, 
59     r_pos,    
60     r_read_and,
61     r_write,
62 };
63
64 static const struct rset_control control_or = 
65 {
66     "or",
67     r_create,
68     r_open,
69     r_close,
70     r_delete,
71     r_rewind,
72     r_forward, 
73     r_pos,
74     r_read_or,
75     r_write,
76 };
77
78 static const struct rset_control control_not = 
79 {
80     "not",
81     r_create,
82     r_open,
83     r_close,
84     r_delete,
85     r_rewind,
86     r_forward, 
87     r_pos,
88     r_read_not,
89     r_write,
90 };
91
92
93 const struct rset_control *rset_kind_and = &control_and;
94 const struct rset_control *rset_kind_or = &control_or;
95 const struct rset_control *rset_kind_not = &control_not;
96
97 struct rset_bool_info {
98     int key_size;
99     RSET rset_l;
100     RSET rset_r;
101     int (*cmp)(const void *p1, const void *p2);
102     void (*log_item)(int logmask, const void *p, const char *txt);
103     struct rset_bool_rfd *rfd_list;
104 };
105
106 struct rset_bool_rfd {
107     zint hits;
108     RSFD rfd_l;
109     RSFD rfd_r;
110     int  more_l;
111     int  more_r;
112     void *buf_l;
113     void *buf_r;
114     int tail;
115     struct rset_bool_rfd *next;
116     struct rset_bool_info *info;
117 };    
118
119 static void *r_create (RSET ct, const struct rset_control *sel, void *parms)
120 {
121     rset_bool_parms *bool_parms = (rset_bool_parms *) parms;
122     struct rset_bool_info *info;
123
124     info = (struct rset_bool_info *) xmalloc (sizeof(*info));
125     info->key_size = bool_parms->key_size;
126     info->rset_l = bool_parms->rset_l;
127     info->rset_r = bool_parms->rset_r;
128     info->cmp = bool_parms->cmp;
129     info->log_item = bool_parms->log_item;
130     info->rfd_list = NULL;
131     
132     return info;
133 }
134
135 static RSFD r_open (RSET ct, int flag)
136 {
137     struct rset_bool_info *info = (struct rset_bool_info *) ct->buf;
138     struct rset_bool_rfd *rfd;
139
140     if (flag & RSETF_WRITE)
141     {
142         logf (LOG_FATAL, "bool set type is read-only");
143         return NULL;
144     }
145     rfd = (struct rset_bool_rfd *) xmalloc (sizeof(*rfd));
146     logf(LOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
147     rfd->next = info->rfd_list;
148     info->rfd_list = rfd;
149     rfd->info = info;
150     rfd->hits=0;
151
152     rfd->buf_l = xmalloc (info->key_size);
153     rfd->buf_r = xmalloc (info->key_size);
154     rfd->rfd_l = rset_open (info->rset_l, RSETF_READ);
155     rfd->rfd_r = rset_open (info->rset_r, RSETF_READ);
156     rfd->more_l = rset_read (info->rset_l, rfd->rfd_l, rfd->buf_l);
157     rfd->more_r = rset_read (info->rset_r, rfd->rfd_r, rfd->buf_r);
158     rfd->tail = 0;
159     return rfd;
160 }
161
162 static void r_close (RSFD rfd)
163 {
164     struct rset_bool_info *info = ((struct rset_bool_rfd*)rfd)->info;
165     struct rset_bool_rfd **rfdp;
166     
167     for (rfdp = &info->rfd_list; *rfdp; rfdp = &(*rfdp)->next)
168         if (*rfdp == rfd)
169         {
170             xfree ((*rfdp)->buf_l);
171             xfree ((*rfdp)->buf_r);
172             rset_close (info->rset_l, (*rfdp)->rfd_l);
173             rset_close (info->rset_r, (*rfdp)->rfd_r);
174             *rfdp = (*rfdp)->next;
175             xfree (rfd);
176             return;
177         }
178     logf (LOG_FATAL, "r_close but no rfd match!");
179     assert (0);
180 }
181
182 static void r_delete (RSET ct)
183 {
184     struct rset_bool_info *info = (struct rset_bool_info *) ct->buf;
185
186     assert (info->rfd_list == NULL);
187     rset_delete (info->rset_l);
188     rset_delete (info->rset_r);
189     xfree (info);
190 }
191
192 static void r_rewind (RSFD rfd)
193 {
194     struct rset_bool_info *info = ((struct rset_bool_rfd*)rfd)->info;
195     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
196
197     logf (LOG_DEBUG, "rsbool_rewind");
198     rset_rewind (info->rset_l, p->rfd_l);
199     rset_rewind (info->rset_r, p->rfd_r);
200     p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
201     p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
202     p->hits=0;
203 }
204
205 static int r_forward (RSET ct, RSFD rfd, void *buf,
206                      int (*cmpfunc)(const void *p1, const void *p2),
207                      const void *untilbuf)
208 {
209     struct rset_bool_info *info = ((struct rset_bool_rfd*)rfd)->info;
210     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
211     int rc;
212
213 #if RSET_DEBUG
214     logf (LOG_DEBUG, "rsbool_forward (L) [%p] '%s' (ct=%p rfd=%p m=%d,%d)",
215                       rfd, ct->control->desc, ct, rfd, p->more_l, p->more_r);
216 #endif
217     if ( p->more_l && ((cmpfunc)(untilbuf,p->buf_l)==2) )
218         p->more_l = rset_forward(info->rset_l, p->rfd_l, p->buf_l,
219                         info->cmp, untilbuf);
220 #if RSET_DEBUG
221     logf (LOG_DEBUG, "rsbool_forward (R) [%p] '%s' (ct=%p rfd=%p m=%d,%d)",
222                       rfd, ct->control->desc, ct, rfd, p->more_l, p->more_r);
223 #endif
224     if ( p->more_r && ((cmpfunc)(untilbuf,p->buf_r)==2))
225         p->more_r = rset_forward(info->rset_r, p->rfd_r, p->buf_r,
226                         info->cmp, untilbuf);
227 #if RSET_DEBUG
228     logf (LOG_DEBUG, "rsbool_forward [%p] calling read, m=%d,%d t=%d", 
229                        rfd, p->more_l, p->more_r, p->tail);
230 #endif
231     
232     p->tail=0; 
233     rc = rset_read(ct,rfd,buf); 
234 #if RSET_DEBUG
235     logf (LOG_DEBUG, "rsbool_forward returning [%p] %d m=%d,%d", 
236                        rfd, rc, p->more_l, p->more_r);
237 #endif
238     return rc;
239 }
240
241
242 /*
243     1,1         1,3
244     1,9         2,1
245     1,11        3,1
246     2,9
247
248   1,1     1,1
249   1,3     1,3
250           1,9
251           1,11
252   2,1     2,1
253           2,9
254           3,1
255 */
256
257 static int r_read_and (RSFD rfd, void *buf)
258 {
259     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
260     struct rset_bool_info *info = p->info;
261
262     while (p->more_l || p->more_r)
263     {
264         int cmp;
265
266         if (p->more_l && p->more_r)
267             cmp = (*info->cmp)(p->buf_l, p->buf_r);
268         else if (p->more_l)
269             cmp = -2;
270         else
271             cmp = 2;
272 #if RSET_DEBUG
273         logf (LOG_DEBUG, "r_read_and [%p] looping: m=%d/%d c=%d t=%d",
274                         rfd, p->more_l, p->more_r, cmp, p->tail);
275         (*info->log_item)(LOG_DEBUG, p->buf_l, "left ");
276         (*info->log_item)(LOG_DEBUG, p->buf_r, "right ");
277 #endif
278         if (!cmp)
279         {
280             memcpy (buf, p->buf_l, info->key_size);
281             p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
282             p->tail = 1;
283         }
284         else if (cmp == 1)
285         {
286             memcpy (buf, p->buf_r, info->key_size);
287             p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
288             p->tail = 1;
289 #if RSET_DEBUG
290             logf (LOG_DEBUG, "r_read_and [%p] returning R m=%d/%d c=%d",
291                     rfd, p->more_l, p->more_r, cmp);
292             key_logdump(LOG_DEBUG,buf);
293             (*info->log_item)(LOG_DEBUG, buf, "");
294 #endif
295             p->hits++;
296             return 1;
297         }
298         else if (cmp == -1)
299         {
300             memcpy (buf, p->buf_l, info->key_size);
301             p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
302             p->tail = 1;
303 #if RSET_DEBUG
304             logf (LOG_DEBUG, "r_read_and [%p] returning L m=%d/%d c=%d",
305                     rfd, p->more_l, p->more_r, cmp);
306             (*info->log_item)(LOG_DEBUG, buf, "");
307 #endif
308             p->hits++;
309             return 1;
310         }
311         else if (cmp > 1)  /* cmp == 2 */
312         {
313 #define OLDCODE 0
314 #if OLDCODE
315             memcpy (buf, p->buf_r, info->key_size);
316             
317             p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
318             if (p->tail)
319             {
320                 if (!p->more_r || (*info->cmp)(p->buf_r, buf) > 1)
321                     p->tail = 0;
322 #if RSET_DEBUG
323                 logf (LOG_DEBUG, "r_read_and returning C m=%d/%d c=%d",
324                         p->more_l, p->more_r, cmp);
325                 (*info->log_item)(LOG_DEBUG, buf, "");
326 #endif
327                 p->hits++;
328                 return 1;
329             }
330 #else
331             
332             if (p->tail)
333             {
334                 memcpy (buf, p->buf_r, info->key_size);
335                 p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
336                 if (!p->more_r || (*info->cmp)(p->buf_r, buf) > 1)
337                     p->tail = 0;
338 #if RSET_DEBUG
339                 logf (LOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
340                         rfd, p->more_l, p->more_r, cmp);
341                 (*info->log_item)(LOG_DEBUG, buf, "");
342 #endif
343                 p->hits++;
344                 return 1;
345             }
346             else
347             {
348 #if RSET_DEBUG
349                 logf (LOG_DEBUG, "r_read_and [%p] about to forward R m=%d/%d c=%d",
350                         rfd, p->more_l, p->more_r, cmp);
351 #endif
352                 if (p->more_r && p->more_l)
353                     p->more_r = rset_forward( info->rset_r, p->rfd_r, 
354                                     p->buf_r, (info->cmp), p->buf_l);
355                 else 
356                     return 0; /* no point in reading further */
357             }
358 #endif
359         }
360         else  /* cmp == -2 */
361         {
362 #if OLDCODE
363              memcpy (buf, p->buf_l, info->key_size);
364              p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
365              if (p->tail)
366              {
367                  if (!p->more_l || (*info->cmp)(p->buf_l, buf) > 1)
368                      p->tail = 0;
369 #if RSET_DEBUG
370                  logf (LOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
371                         rfd, p->more_l, p->more_r, cmp);
372                  (*info->log_item)(LOG_DEBUG, buf, "");
373 #endif
374                  p->hits++;
375                  return 1;
376              }
377 #else
378             if (p->tail)
379             {
380                 memcpy (buf, p->buf_l, info->key_size);
381                 p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
382                 if (!p->more_l || (*info->cmp)(p->buf_l, buf) > 1)
383                     p->tail = 0;
384 #if RSET_DEBUG
385                 logf (LOG_DEBUG, "r_read_and [%p] returning L tail m=%d/%d c=%d",
386                         rfd, p->more_l, p->more_r, cmp);
387                 (*info->log_item)(LOG_DEBUG, buf, "");
388 #endif
389                 p->hits++;
390                 return 1;
391             }
392             else
393             {
394 #if RSET_DEBUG
395                 logf (LOG_DEBUG, "r_read_and [%p] about to forward L m=%d/%d c=%d",
396                         rfd, p->more_l, p->more_r, cmp);
397 #endif
398                 if (p->more_r && p->more_l)
399                     p->more_l = rset_forward( 
400                                     info->rset_l, p->rfd_l, 
401                                     p->buf_l, (info->cmp), p->buf_r);
402                 else 
403                     return 0; /* no point in reading further */
404             }
405 #endif
406         }
407     }
408 #if RSET_DEBUG
409     logf (LOG_DEBUG, "r_read_and [%p] reached its end",rfd);
410 #endif
411     return 0;
412 }
413
414 static int r_read_or (RSFD rfd, void *buf)
415 {
416     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
417     struct rset_bool_info *info = p->info;
418
419     while (p->more_l || p->more_r)
420     {
421         int cmp;
422
423         if (p->more_l && p->more_r)
424             cmp = (*info->cmp)(p->buf_l, p->buf_r);
425         else if (p->more_r)
426             cmp = 2;
427         else
428             cmp = -2;
429         if (!cmp)
430         {
431             memcpy (buf, p->buf_l, info->key_size);
432             p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
433             p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
434 #if RSET_DEBUG
435             logf (LOG_DEBUG, "r_read_or returning A m=%d/%d c=%d",
436                     p->more_l, p->more_r, cmp);
437             (*info->log_item)(LOG_DEBUG, buf, "");
438 #endif
439             p->hits++;
440             return 1;
441         }
442         else if (cmp > 0)
443         {
444             memcpy (buf, p->buf_r, info->key_size);
445             p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
446 #if RSET_DEBUG
447             logf (LOG_DEBUG, "r_read_or returning B m=%d/%d c=%d",
448                     p->more_l, p->more_r, cmp);
449             (*info->log_item)(LOG_DEBUG, buf, "");
450 #endif
451             p->hits++;
452             return 1;
453         }
454         else
455         {
456             memcpy (buf, p->buf_l, info->key_size);
457             p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
458 #if RSET_DEBUG
459             logf (LOG_DEBUG, "r_read_or returning C m=%d/%d c=%d",
460                     p->more_l, p->more_r, cmp);
461             (*info->log_item)(LOG_DEBUG, buf, "");
462 #endif
463             p->hits++;
464             return 1;
465         }
466     }
467     return 0;
468 }
469
470 static int r_read_not (RSFD rfd, void *buf)
471 {
472     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
473     struct rset_bool_info *info = p->info;
474
475     while (p->more_l || p->more_r)
476     {
477         int cmp;
478
479         if (p->more_l && p->more_r)
480             cmp = (*info->cmp)(p->buf_l, p->buf_r);
481         else if (p->more_r)
482             cmp = 2;
483         else
484             cmp = -2;
485         if (cmp < -1)
486         {
487             memcpy (buf, p->buf_l, info->key_size);
488             p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
489             p->hits++;
490             return 1;
491         }
492         else if (cmp > 1)
493         {
494                 p->more_r = rset_forward( 
495                     info->rset_r, p->rfd_r, 
496                     p->buf_r, (info->cmp), p->buf_l);
497         }
498         else
499         {
500             memcpy (buf, p->buf_l, info->key_size);
501             do
502             { 
503                 p->more_l = rset_read (info->rset_l, p->rfd_l, p->buf_l);
504                 if (!p->more_l)
505                     break;
506                 cmp = (*info->cmp)(p->buf_l, buf);
507             } while (cmp >= -1 && cmp <= 1);
508             do
509             {
510                 p->more_r = rset_read (info->rset_r, p->rfd_r, p->buf_r);
511                 if (!p->more_r)
512                     break;
513                 cmp = (*info->cmp)(p->buf_r, buf);
514             } while (cmp >= -1 && cmp <= 1);
515         }
516     }
517     return 0;
518 }
519
520
521 static int r_write (RSFD rfd, const void *buf)
522 {
523     logf (LOG_FATAL, "bool set type is read-only");
524     return -1;
525 }
526
527 static void r_pos (RSFD rfd, double *current, double *total)
528 {
529     struct rset_bool_rfd *p = (struct rset_bool_rfd *) rfd;
530     struct rset_bool_info *info = p->info;
531     double lcur,ltot;
532     double rcur,rtot;
533     double r;
534     ltot=-1; rtot=-1;
535     rset_pos(info->rset_l, p->rfd_l,  &lcur, &ltot);
536     rset_pos(info->rset_r, p->rfd_r,  &rcur, &rtot);
537     if ( (rtot<0) && (ltot<0)) { /*no position */
538         *current=rcur;  /* return same as you got */
539         *total=rtot;    /* probably -1 for not available */
540     }
541     if ( rtot<0) { rtot=0; rcur=0;} /* if only one useful, use it */
542     if ( ltot<0) { ltot=0; lcur=0;}
543     if ( rtot+ltot < 1 ) { /* empty rset */
544         *current=0;
545         *total=0;
546         return;
547     }
548     r=1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
549     *current=(double) (p->hits);
550     *total=*current/r ; 
551 #if RSET_DEBUG
552     yaz_log(LOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
553                     info->rset_l->control->desc, info->rset_r->control->desc,
554                     *current, *total, r);
555 #endif
556 }