Passing a TERMID to rsets when creating, and getting it back when reading.
[idzebra-moved-to-github.git] / rset / rsbool.c
1 /* $Id: rsbool.c,v 1.49 2004-10-15 10:07:34 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
31 #ifndef RSET_DEBUG
32 #define RSET_DEBUG 0
33 #endif
34
35 static RSFD r_open (RSET ct, int flag);
36 static void r_close (RSFD rfd);
37 static void r_delete (RSET ct);
38 static int r_forward(RSFD rfd, void *buf, TERMID *term, const void *untilbuf);
39 static void r_pos (RSFD rfd, double *current, double *total); 
40 static int r_read_and (RSFD rfd, void *buf, TERMID *term);
41 static int r_read_or (RSFD rfd, void *buf, TERMID *term);
42 static int r_read_not (RSFD rfd, void *buf, TERMID *term);
43 static int r_write (RSFD rfd, const void *buf);
44
45 static const struct rset_control control_and = 
46 {
47     "and",
48     r_delete,
49     r_open,
50     r_close,
51     r_forward, 
52     r_pos,    
53     r_read_and,
54     r_write,
55 };
56
57 static const struct rset_control control_or = 
58 {
59     "or",
60     r_delete,
61     r_open,
62     r_close,
63     r_forward, 
64     r_pos,
65     r_read_or,
66     r_write,
67 };
68
69 static const struct rset_control control_not = 
70 {
71     "not",
72     r_delete,
73     r_open,
74     r_close,
75     r_forward, 
76     r_pos,
77     r_read_not,
78     r_write,
79 };
80
81
82 const struct rset_control *rset_kind_and = &control_and;
83 const struct rset_control *rset_kind_or  = &control_or;
84 const struct rset_control *rset_kind_not = &control_not;
85
86 struct rset_bool_info {
87     RSET rset_l;
88     RSET rset_r;
89 };
90
91 struct rset_bool_rfd {
92     zint hits;
93     RSFD rfd_l;
94     RSFD rfd_r;
95     int  more_l;
96     int  more_r;
97     void *buf_l;
98     void *buf_r;
99     TERMID term_l;
100     TERMID term_r;
101     int tail;
102 };    
103
104 static RSET rsbool_create_base( const struct rset_control *ctrl,
105             NMEM nmem, const struct key_control *kcontrol,
106             int scope, 
107             RSET rset_l, RSET rset_r)
108 {
109     RSET rnew=rset_create_base(ctrl, nmem, kcontrol, scope,0);
110     struct rset_bool_info *info;
111     info = (struct rset_bool_info *) nmem_malloc(rnew->nmem,sizeof(*info));
112     info->rset_l = rset_l;
113     info->rset_r = rset_r;
114     rnew->priv=info;
115     return rnew;
116 }
117
118
119 RSET rsbool_create_and( NMEM nmem, const struct key_control *kcontrol,
120                         int scope, 
121                         RSET rset_l, RSET rset_r)
122 {
123     return rsbool_create_base(rset_kind_and, nmem, kcontrol,
124                               scope,
125                               rset_l, rset_r);
126 }
127
128 RSET rsbool_create_or( NMEM nmem, const struct key_control *kcontrol,
129                         int scope, 
130                        RSET rset_l, RSET rset_r)
131 {
132     return rsbool_create_base(rset_kind_or, nmem, kcontrol,
133                               scope,
134                               rset_l, rset_r);
135 }
136
137 RSET rsbool_create_not( NMEM nmem, const struct key_control *kcontrol,
138                         int scope, 
139                         RSET rset_l, RSET rset_r)
140 {
141     return rsbool_create_base(rset_kind_not, nmem, kcontrol,
142                               scope, 
143                               rset_l, rset_r);
144 }
145
146 static void r_delete (RSET ct)
147 {
148     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
149     rset_delete (info->rset_l);
150     rset_delete (info->rset_r);
151 }
152
153
154 static RSFD r_open (RSET ct, int flag)
155 {
156     struct rset_bool_info *info = (struct rset_bool_info *) ct->priv;
157     RSFD rfd;
158     struct rset_bool_rfd *p;
159    
160
161     if (flag & RSETF_WRITE)
162     {
163         logf (LOG_FATAL, "bool set type is read-only");
164         return NULL;
165     }
166     rfd = rfd_create_base(ct);
167     if (rfd->priv)
168         p=(struct rset_bool_rfd *)rfd->priv;
169     else {
170         p=nmem_malloc(ct->nmem,sizeof(*p));
171         rfd->priv=p;
172         p->buf_l = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
173         p->buf_r = nmem_malloc(ct->nmem, ct->keycontrol->key_size);
174     }
175
176     logf(LOG_DEBUG,"rsbool (%s) open [%p]", ct->control->desc, rfd);
177     p->hits=0;
178
179     p->rfd_l = rset_open (info->rset_l, RSETF_READ);
180     p->rfd_r = rset_open (info->rset_r, RSETF_READ);
181     p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
182     p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
183     p->tail = 0;
184     return rfd;
185 }
186
187 static void r_close (RSFD rfd)
188 {
189  /* struct rset_bool_info *info = (struct rset_bool_info*)(rfd->rset->priv); */
190     struct rset_bool_rfd *prfd=(struct rset_bool_rfd *)rfd->priv;
191
192     rset_close (prfd->rfd_l);
193     rset_close (prfd->rfd_r);
194     rfd_delete_base(rfd);
195 }
196
197
198
199 static int r_forward (RSFD rfd, void *buf, TERMID *term,
200                      const void *untilbuf)
201 {
202     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
203     const struct key_control *kctrl=rfd->rset->keycontrol;
204
205     if ( p->more_l && ((kctrl->cmp)(untilbuf,p->buf_l)>=rfd->rset->scope) )
206         p->more_l = rset_forward(p->rfd_l, p->buf_l, &p->term_l, untilbuf);
207     if ( p->more_r && ((kctrl->cmp)(untilbuf,p->buf_r)>=rfd->rset->scope))
208         p->more_r = rset_forward(p->rfd_r, p->buf_r, &p->term_r, untilbuf);
209     p->tail=0; 
210     return rset_read(rfd,buf,term); 
211 }
212
213
214 /*
215     1,1         1,3
216     1,9         2,1
217     1,11        3,1
218     2,9
219
220   1,1     1,1
221   1,3     1,3
222           1,9
223           1,11
224   2,1     2,1
225           2,9
226           3,1
227 */
228
229 static int r_read_and (RSFD rfd, void *buf, TERMID *term)
230 {
231     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
232     const struct key_control *kctrl=rfd->rset->keycontrol;
233
234     while (p->more_l || p->more_r)
235     {
236         int cmp;
237
238         if (p->more_l && p->more_r)
239             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
240         else if (p->more_l)
241             cmp = -rfd->rset->scope;
242         else
243             cmp = rfd->rset->scope;
244 #if RSET_DEBUG
245         logf (LOG_DEBUG, "r_read_and [%p] looping: m=%d/%d c=%d t=%d",
246                         rfd, p->more_l, p->more_r, cmp, p->tail);
247         (*kctrl->log_item)(LOG_DEBUG, p->buf_l, "left ");
248         (*kctrl->log_item)(LOG_DEBUG, p->buf_r, "right ");
249 #endif
250         if (!cmp)
251         {  /* cmp==0 */
252             memcpy (buf, p->buf_l, kctrl->key_size);
253             if (term)
254                 *term=p->term_l;
255             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
256             p->tail = 1;
257         }
258         else if ( (cmp>0) && (cmp<rfd->rset->scope))
259         {  /* typically cmp == 1 */
260             memcpy (buf, p->buf_r, kctrl->key_size);
261             if (term)
262                 *term=p->term_r;
263             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
264             p->tail = 1;
265 #if RSET_DEBUG
266             logf (LOG_DEBUG, "r_read_and [%p] returning R m=%d/%d c=%d",
267                     rfd, p->more_l, p->more_r, cmp);
268             key_logdump(LOG_DEBUG,buf);
269             (*kctrl->log_item)(LOG_DEBUG, buf, "");
270 #endif
271             p->hits++;
272             return 1;
273         }
274         else if ( (cmp<0) && (-cmp<rfd->rset->scope))
275         {  /* cmp == -1 */
276             memcpy (buf, p->buf_l, kctrl->key_size);
277             if (term)
278                 *term=p->term_l;
279             p->more_l = rset_read (p->rfd_l, p->buf_l,&p->term_l);
280             p->tail = 1;
281 #if RSET_DEBUG
282             logf (LOG_DEBUG, "r_read_and [%p] returning L m=%d/%d c=%d",
283                     rfd, p->more_l, p->more_r, cmp);
284             (*kctrl->log_item)(LOG_DEBUG, buf, "");
285 #endif
286             p->hits++;
287             return 1;
288         }
289         else if (cmp >= rfd->rset->scope )  
290         {  /* cmp == 2 */
291             if (p->tail)
292             {
293                 memcpy (buf, p->buf_r, kctrl->key_size);
294                 if (term)
295                     *term=p->term_r;
296                 p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
297                 if (!p->more_r || (*kctrl->cmp)(p->buf_r, buf) > 1)
298                     p->tail = 0;
299 #if RSET_DEBUG
300                 logf (LOG_DEBUG, "r_read_and [%p] returning R tail m=%d/%d c=%d",
301                         rfd, p->more_l, p->more_r, cmp);
302                 (*kctrl->log_item)(LOG_DEBUG, buf, "");
303 #endif
304                 p->hits++;
305                 return 1;
306             }
307             else
308             {
309 #if RSET_DEBUG
310                 logf (LOG_DEBUG, "r_read_and [%p] about to forward R "
311                                  "m=%d/%d c=%d",
312                         rfd, p->more_l, p->more_r, cmp);
313 #endif
314                 if (p->more_r && p->more_l)
315                     p->more_r = rset_forward( p->rfd_r, p->buf_r,
316                              &p->term_r, p->buf_l);
317                 else 
318                     return 0; /* no point in reading further */
319             }
320         }
321         else  
322         { /* cmp == -2 */
323             if (p->tail)
324             {
325                 memcpy (buf, p->buf_l, kctrl->key_size);
326                 if (term)
327                     *term=p->term_l;
328                 p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
329                 if (!p->more_l || (*kctrl->cmp)(p->buf_l, buf) > 1)
330                     p->tail = 0;
331 #if RSET_DEBUG
332                 logf (LOG_DEBUG, "r_read_and [%p] returning L tail m=%d/%d c=%d",
333                         rfd, p->more_l, p->more_r, cmp);
334                 (*kctrl->log_item)(LOG_DEBUG, buf, "");
335 #endif
336                 p->hits++;
337                 return 1;
338             }
339             else
340             {
341 #if RSET_DEBUG
342                 logf (LOG_DEBUG, "r_read_and [%p] about to forward L "
343                                  "m=%d/%d c=%d",
344                         rfd, p->more_l, p->more_r, cmp);
345 #endif
346                 if (p->more_r && p->more_l)
347                     p->more_l = rset_forward(p->rfd_l, p->buf_l, 
348                                  &p->term_l, p->buf_r);
349                 else 
350                     return 0; /* no point in reading further */
351             }
352         }
353     }
354 #if RSET_DEBUG
355     logf (LOG_DEBUG, "r_read_and [%p] reached its end",rfd);
356 #endif
357     return 0;
358 }
359
360 static int r_read_or (RSFD rfd, void *buf, TERMID *term)
361 {
362     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
363     const struct key_control *kctrl=rfd->rset->keycontrol;
364
365     while (p->more_l || p->more_r)
366     {
367         int cmp;
368
369         if (p->more_l && p->more_r)
370             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
371         else if (p->more_r)
372             cmp = rfd->rset->scope;
373         else
374             cmp = -rfd->rset->scope;
375         if (!cmp)
376         { /* cmp==0 */
377             memcpy (buf, p->buf_l, kctrl->key_size);
378             if (term)
379                 *term=p->term_l;
380             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
381             /* FIXME - is this right, should we not leave _r as it is */
382             /* and return that in the next read, so that ranking etc */
383             /* get to see both? */
384             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
385 #if RSET_DEBUG
386             logf (LOG_DEBUG, "r_read_or returning A m=%d/%d c=%d",
387                     p->more_l, p->more_r, cmp);
388             (*kctrl->log_item)(LOG_DEBUG, buf, "");
389 #endif
390             p->hits++;
391             return 1;
392         }
393         else if (cmp > 0)
394         {
395             memcpy (buf, p->buf_r, kctrl->key_size);
396             if (term)
397                 *term=p->term_r;
398             p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
399 #if RSET_DEBUG
400             logf (LOG_DEBUG, "r_read_or returning B m=%d/%d c=%d",
401                     p->more_l, p->more_r, cmp);
402             (*kctrl->log_item)(LOG_DEBUG, buf, "");
403 #endif
404             p->hits++;
405             return 1;
406         }
407         else
408         {
409             memcpy (buf, p->buf_l, kctrl->key_size);
410             if (term)
411                 *term=p->term_l;
412             p->more_l = rset_read ( p->rfd_l, p->buf_l, &p->term_l);
413 #if RSET_DEBUG
414             logf (LOG_DEBUG, "r_read_or returning C m=%d/%d c=%d",
415                     p->more_l, p->more_r, cmp);
416             (*kctrl->log_item)(LOG_DEBUG, buf, "");
417 #endif
418             p->hits++;
419             return 1;
420         }
421     }
422     return 0;
423 }
424
425 static int r_read_not (RSFD rfd, void *buf, TERMID *term)
426 {
427     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
428     const struct key_control *kctrl=rfd->rset->keycontrol;
429
430     while (p->more_l || p->more_r)
431     {
432         int cmp;
433
434         if (p->more_l && p->more_r)
435             cmp = (*kctrl->cmp)(p->buf_l, p->buf_r);
436         else if (p->more_r)
437             cmp = rfd->rset->scope;
438         else
439             cmp = -rfd->rset->scope;
440
441         if (cmp <= -rfd->rset->scope)
442         { /* cmp == -2 */
443             memcpy (buf, p->buf_l, kctrl->key_size);
444             if (term)
445                 *term=p->term_l;
446             p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
447             p->hits++;
448             return 1;
449         }
450         else if (cmp >= rfd->rset->scope)   /* cmp >1 */
451             p->more_r = rset_forward( p->rfd_r, p->buf_r, 
452                           &p->term_r, p->buf_l);
453         else
454         { /* cmp== -1, 0, or 1 */
455             memcpy (buf, p->buf_l, kctrl->key_size);
456             if (term)
457                 *term=p->term_l;
458             do
459             { 
460                 p->more_l = rset_read (p->rfd_l, p->buf_l, &p->term_l);
461                 if (!p->more_l)
462                     break;
463                 cmp = (*kctrl->cmp)(p->buf_l, buf);
464             } while (abs(cmp)<rfd->rset->scope);
465                 /*  (cmp >= -1 && cmp <= 1) */
466             do
467             {
468                 p->more_r = rset_read (p->rfd_r, p->buf_r, &p->term_r);
469                 if (!p->more_r)
470                     break;
471                 cmp = (*kctrl->cmp)(p->buf_r, buf);
472             } while (abs(cmp)<rfd->rset->scope);
473                /* (cmp >= -1 && cmp <= 1) */
474         }
475     }
476     return 0;
477 }
478
479
480 static int r_write (RSFD rfd, const void *buf)
481 {
482     logf (LOG_FATAL, "bool set type is read-only");
483     return -1;
484 }
485
486 static void r_pos (RSFD rfd, double *current, double *total)
487 {
488     struct rset_bool_rfd *p=(struct rset_bool_rfd *)rfd->priv;
489     double lcur,ltot;
490     double rcur,rtot;
491     double r;
492     ltot=-1; rtot=-1;
493     rset_pos(p->rfd_l,  &lcur, &ltot);
494     rset_pos(p->rfd_r,  &rcur, &rtot);
495     if ( (rtot<0) && (ltot<0)) { /*no position */
496         *current=rcur;  /* return same as you got */
497         *total=rtot;    /* probably -1 for not available */
498     }
499     if ( rtot<0) { rtot=0; rcur=0;} /* if only one useful, use it */
500     if ( ltot<0) { ltot=0; lcur=0;}
501     if ( rtot+ltot < 1 ) { /* empty rset */
502         *current=0;
503         *total=0;
504         return;
505     }
506     r=1.0*(lcur+rcur)/(ltot+rtot); /* weighed average of l and r */
507     *current=(double) (p->hits);
508     *total=*current/r ; 
509 #if RSET_DEBUG
510     yaz_log(LOG_DEBUG,"bool_pos: (%s/%s) %0.1f/%0.1f= %0.4f ",
511                     info->rset_l->control->desc, info->rset_r->control->desc,
512                     *current, *total, r);
513 #endif
514 }