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