Using the key_control block for the first key-handling functions in all
[idzebra-moved-to-github.git] / rset / rsprox.c
1 /* $Id: rsprox.c,v 1.14 2004-09-01 15:01:32 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 void r_rewind (RSFD rfd);
39 static int r_forward(RSFD rfd, void *buf, const void *untilbuf);
40 static int r_read (RSFD rfd, void *buf);
41 static int r_write (RSFD rfd, const void *buf);
42 static void r_pos (RSFD rfd, double *current, double *total);
43
44 static const struct rset_control control = 
45 {
46     "prox",
47     r_delete,
48     r_open,
49     r_close,
50     r_rewind,
51     r_forward,
52     r_pos,
53     r_read,
54     r_write,
55 };
56
57 const struct rset_control *rset_kind_prox = &control;
58
59 struct rset_prox_info {
60     RSET *rset;   /* array of 'child' rsets */
61     int rset_no;  /* how many of them */
62     int ordered;
63     int exclusion;
64     int relation;
65     int distance;
66 };
67
68 struct rset_prox_rfd {
69     RSFD *rfd;
70     char **buf;  /* lookahead key buffers */
71     char *more;  /* more in each lookahead? */
72     zint hits;
73 };    
74
75
76 RSET rsprox_create( NMEM nmem, const struct key_control *kcontrol,
77             int rset_no, RSET *rset,
78             int ordered, int exclusion,
79             int relation, int distance)
80 {
81     RSET rnew=rset_create_base(&control, nmem, kcontrol);
82     struct rset_prox_info *info;
83     info = (struct rset_prox_info *) nmem_malloc(rnew->nmem,sizeof(*info));
84     info->rset = nmem_malloc(rnew->nmem,rset_no * sizeof(*info->rset));
85     memcpy(info->rset, rset,
86            rset_no * sizeof(*info->rset));
87     info->rset_no=rset_no;
88     info->ordered=ordered;
89     info->exclusion=exclusion;
90     info->relation=relation;
91     info->distance=distance;
92     rnew->priv=info;
93     return rnew;
94 }
95
96
97 static void r_delete (RSET ct)
98 {
99     struct rset_prox_info *info = (struct rset_prox_info *) ct->priv;
100     int i;
101
102     for (i = 0; i<info->rset_no; i++)
103         rset_delete (info->rset[i]);
104 }
105
106
107 static RSFD r_open (RSET ct, int flag)
108 {
109     struct rset_prox_info *info = (struct rset_prox_info *) ct->priv;
110     RSFD rfd;
111     struct rset_prox_rfd *p;
112     int i;
113
114     if (flag & RSETF_WRITE)
115     {
116         logf (LOG_FATAL, "prox set type is read-only");
117         return NULL;
118     }
119     rfd = rfd_create_base(ct);
120     if (rfd->priv)
121         p=(struct rset_prox_rfd *)(rfd->priv);
122     else {
123         p = (struct rset_prox_rfd *) nmem_malloc (ct->nmem,sizeof(*p));
124         rfd->priv=p;
125         p->more = nmem_malloc (ct->nmem,sizeof(*p->more) * info->rset_no);
126         p->buf = nmem_malloc(ct->nmem,sizeof(*p->buf) * info->rset_no);
127         for (i = 0; i < info->rset_no; i++)
128             p->buf[i] = nmem_malloc(ct->nmem,ct->keycontrol->key_size);
129         p->rfd = nmem_malloc(ct->nmem,sizeof(*p->rfd) * info->rset_no);
130     }
131     logf(LOG_DEBUG,"rsprox (%s) open [%p] n=%d", 
132             ct->control->desc, rfd, info->rset_no);
133
134     for (i = 0; i < info->rset_no; i++) {
135         p->rfd[i] = rset_open (info->rset[i], RSETF_READ);
136         p->more[i] = rset_read (p->rfd[i], p->buf[i]);
137     }
138     p->hits=0;
139     return rfd;
140 }
141
142 static void r_close (RSFD rfd)
143 {
144     struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
145     struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
146     
147     int i;
148     for (i = 0; i<info->rset_no; i++)
149         rset_close (p->rfd[i]);
150     rfd_delete_base(rfd);
151 }
152
153 static void r_rewind (RSFD rfd)
154 {
155     struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
156     struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
157     int i;
158
159     logf (LOG_DEBUG, "rsprox_rewind");
160
161     for (i = 0; i < info->rset_no; i++)
162     {
163         rset_rewind (p->rfd[i]);
164         p->more[i] = rset_read (p->rfd[i], p->buf[i]);
165     }
166     p->hits=0;
167 }
168
169 static int r_forward (RSFD rfd, void *buf, const void *untilbuf)
170 {
171     struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
172     struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
173     const struct key_control *kctrl=rfd->rset->keycontrol;
174     int cmp=0;
175     int i;
176
177     if (untilbuf)
178     {
179         /* it is enough to forward first one. Other will follow. */
180         if ( p->more[0] && ((kctrl->cmp)(untilbuf, p->buf[0]) >= 2) )
181             p->more[0] = rset_forward(p->rfd[0], p->buf[0], untilbuf);
182     }
183     if (info->ordered && info->relation == 3 && info->exclusion == 0
184         && info->distance == 1)
185     {
186         while (p->more[0]) 
187         {
188             for (i = 1; i < info->rset_no; i++)
189             {
190                 if (!p->more[i]) 
191                 {
192                     p->more[0] = 0; /* saves us a goto out of while loop. */
193                     break;
194                 }
195                 cmp = (*kctrl->cmp) (p->buf[i], p->buf[i-1]);
196                 if (cmp > 1)
197                 {
198                     p->more[i-1] = rset_forward (p->rfd[i-1],
199                                                  p->buf[i-1],
200                                                  p->buf[i]);
201                     break;
202                 }
203                 else if (cmp == 1)
204                 {
205                     if ((*kctrl->getseq)(p->buf[i-1]) +1 != 
206                         (*kctrl->getseq)(p->buf[i]))
207                     { /* FIXME - We need more flexible multilevel stuff */
208                         p->more[i-1] = rset_read ( p->rfd[i-1], p->buf[i-1]);
209                         break;
210                     }
211                 }
212                 else
213                 {
214                     p->more[i] = rset_forward (p->rfd[i], 
215                                   p->buf[i], p->buf[i-1]);
216                     break;
217                 }
218             }
219             if (i == info->rset_no)
220             {
221                 memcpy (buf, p->buf[0], kctrl->key_size);
222                 p->more[0] = rset_read (p->rfd[0], p->buf[0]);
223                 p->hits++;
224                 return 1;
225             }
226         }
227     }
228     else if (info->rset_no == 2)
229     {
230         while (p->more[0] && p->more[1]) 
231         {
232             int cmp = (*kctrl->cmp)(p->buf[0], p->buf[1]);
233             if (cmp < -1)
234                 p->more[0] = rset_forward (p->rfd[0],
235                                            p->buf[0], p->buf[0]);
236                 /* FIXME - this certainly looks wrong! */
237             else if (cmp > 1)
238                 p->more[1] = rset_forward (p->rfd[1],
239                                            p->buf[1], p->buf[1]);
240             else
241             {
242                 zint seqno[500]; /* FIXME - why 500 ?? */
243                 int n = 0;
244                 
245                 seqno[n++] = (*kctrl->getseq)(p->buf[0]);
246                 while ((p->more[0] = rset_read (p->rfd[0],
247                                                 p->buf[0])) >= -1 &&
248                        p->more[0] <= -1)
249                     if (n < 500)
250                         seqno[n++] = (*kctrl->getseq)(p->buf[0]);
251                 
252                 for (i = 0; i<n; i++)
253                 {
254                     int diff = (*kctrl->getseq)(p->buf[1]) - seqno[i];
255                     int excl = info->exclusion;
256                     if (!info->ordered && diff < 0)
257                         diff = -diff;
258                     switch (info->relation)
259                     {
260                     case 1:      /* < */
261                         if (diff < info->distance && diff >= 0)
262                             excl = !excl;
263                         break;
264                     case 2:      /* <= */
265                         if (diff <= info->distance && diff >= 0)
266                             excl = !excl;
267                         break;
268                     case 3:      /* == */
269                         if (diff == info->distance && diff >= 0)
270                             excl = !excl;
271                         break;
272                     case 4:      /* >= */
273                         if (diff >= info->distance && diff >= 0)
274                             excl = !excl;
275                         break;
276                     case 5:      /* > */
277                         if (diff > info->distance && diff >= 0)
278                             excl = !excl;
279                         break;
280                     case 6:      /* != */
281                         if (diff != info->distance && diff >= 0)
282                             excl = !excl;
283                         break;
284                     }
285                     if (excl)
286                     {
287                         memcpy (buf, p->buf[1], kctrl->key_size);
288                         
289                         p->more[1] = rset_read ( p->rfd[1], p->buf[1]);
290                         p->hits++;
291                         return 1;
292                     }
293                 }
294                 p->more[1] = rset_read (p->rfd[1], p->buf[1]);
295             }
296         }
297     }
298     return 0;
299 }
300
301
302 static int r_read (RSFD rfd, void *buf)
303 {
304     return r_forward(rfd, buf, 0);
305 }
306
307 static int r_write (RSFD rfd, const void *buf)
308 {
309     logf (LOG_FATAL, "prox set type is read-only");
310     return -1;
311 }
312
313 static void r_pos (RSFD rfd, double *current, double *total)
314 {
315     struct rset_prox_info *info = (struct rset_prox_info *)(rfd->rset->priv);
316     struct rset_prox_rfd *p=(struct rset_prox_rfd *)(rfd->priv);
317     int i;
318     double cur,tot=-1;
319     double scur=0,stot=0;
320     double r;
321
322     logf (LOG_DEBUG, "rsprox_pos");
323
324     for (i = 0; i < info->rset_no; i++)
325     {
326         rset_pos(p->rfd[i],  &cur, &tot);
327         if (tot>0) {
328             scur += cur;
329             stot += tot;
330         }
331     }
332     if (tot <0) {  /* nothing found */
333         *current=-1;
334         *total=-1;
335     } else if (tot <1) { /* most likely tot==0 */
336         *current=0;
337         *total=0;
338     } else {
339         r=scur/stot; 
340         *current=p->hits;
341         *total=*current/r ; 
342     }
343     logf(LOG_DEBUG,"prox_pos: [%d] %0.1f/%0.1f= %0.4f ",
344                     i,*current, *total, r);
345 }