1 /* $Id: rset.c,v 1.58 2007-01-17 15:35:48 adam Exp $
2 Copyright (C) 1995-2007
5 This file is part of the Zebra server.
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
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
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <idzebra/util.h>
30 static int log_level = 0;
31 static int log_level_initialized = 0;
34 \brief Common constuctor for RFDs
35 \param rs Result set handle.
37 Creates an rfd. Either allocates a new one, in which case the priv
38 pointer is null, and will have to be filled in, or picks up one
39 from the freelist, in which case the priv is already allocated,
40 and presumably everything that hangs from it as well
42 RSFD rfd_create_base(RSET rs)
44 RSFD rnew = rs->free_list;
48 rs->free_list = rnew->next;
49 assert(rnew->rset==rs);
50 yaz_log(log_level, "rfd_create_base (fl): rfd=%p rs=%p fl=%p priv=%p",
51 rnew, rs, rs->free_list, rnew->priv);
55 rnew = nmem_malloc(rs->nmem, sizeof(*rnew));
56 rnew->counted_buf = nmem_malloc(rs->nmem, rs->keycontrol->key_size);
59 yaz_log(log_level, "rfd_create_base (new): rfd=%p rs=%p fl=%p priv=%p",
60 rnew, rs, rs->free_list, rnew->priv);
62 rnew->next = rs->use_list;
64 rnew->counted_items = 0;
68 static void rset_close_int(RSET rs, RSFD rfd)
71 (*rs->control->f_close)(rfd);
73 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
74 rfd, rs, rfd->priv, rs->free_list);
75 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
79 rfd->next = rs->free_list;
83 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
87 void rset_set_hits_limit(RSET rs, zint l)
93 \brief Closes a result set RFD handle
94 \param rfd the RFD handle.
96 void rset_close(RSFD rfd)
100 if (rs->hits_count == 0)
105 while(rfd->counted_items <= rs->hits_limit
106 && rset_default_read(rfd, buf, &termid))
109 rs->hits_count = rfd->counted_items;
110 yaz_log(log_level, "rset_close rset=%p hits_count=" ZINT_FORMAT
111 " hits_limit=" ZINT_FORMAT,
112 rs, rs->hits_count, rs->hits_limit);
114 if (rs->hits_count > rs->hits_limit)
118 rset_pos(rfd, &cur, &tot);
121 double ratio = cur/tot;
122 est = (zint)(0.5 + rs->hits_count / ratio);
123 yaz_log(log_level, "Estimating hits (%s) "
124 "%0.1f->" ZINT_FORMAT
125 "; %0.1f->" ZINT_FORMAT,
129 i = 0; /* round to significant digits */
130 while (est > rs->hits_round) {
136 rs->hits_count = est;
140 yaz_log(log_level, "rset_close p=%p count=" ZINT_FORMAT, rs,
143 rset_close_int(rs, rfd);
147 \brief Common constuctor for RSETs
148 \param sel The interface control handle
149 \param nmem The memory handle for it.
150 \param kcontrol Key control info (decode, encode, comparison etc)
151 \param scope scope for set
152 \param term Information about term for it (NULL for none).
153 \param no_children number of child rsets (0 for none)
154 \param children child rsets (NULL for none).
156 Creates an rfd. Either allocates a new one, in which case the priv
157 pointer is null, and will have to be filled in, or picks up one
158 from the freelist, in which case the priv is already allocated,
159 and presumably everything that hangs from it as well
161 RSET rset_create_base(const struct rset_control *sel,
162 NMEM nmem, struct rset_key_control *kcontrol,
163 int scope, TERMID term,
164 int no_children, RSET *children)
168 if (!log_level_initialized)
170 log_level = yaz_log_module_level("rset");
171 log_level_initialized = 1;
174 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
175 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
176 yaz_log(log_level, " ref_id=%s limit=" ZINT_FORMAT,
177 (term && term->ref_id ? term->ref_id : "null"),
183 rset->free_list = NULL;
184 rset->use_list = NULL;
185 rset->hits_count = 0;
186 rset->hits_limit = 0;
187 rset->hits_round = 1000;
188 rset->keycontrol = kcontrol;
190 (*kcontrol->inc)(kcontrol);
196 rset->hits_limit = term->hits_limit;
198 rset->no_children = no_children;
202 rset->children = (RSET*)
203 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
204 memcpy(rset->children, children, no_children*sizeof(RSET *));
210 \brief Destructor RSETs
211 \param rs Handle for result set.
213 Destroys a result set and all its children.
214 The f_delete method of control is called for the result set.
216 void rset_delete(RSET rs)
219 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
220 rs->control->desc, rs, rs->refcount);
225 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
227 for (i = 0; i<rs->no_children; i++)
228 rset_delete(rs->children[i]);
229 (*rs->control->f_delete)(rs);
230 (*rs->keycontrol->dec)(rs->keycontrol);
235 \brief Test for last use of RFD
236 \param rfd RFD handle.
238 Returns 1 if this RFD is the last reference to it; 0 otherwise.
240 int rfd_is_last(RSFD rfd)
242 if (rfd->rset->use_list == rfd && rfd->next == 0)
248 \brief Duplicate an RSET
249 \param rs Handle for result set.
251 Duplicates a result set by incrementing the reference count to it.
253 RSET rset_dup (RSET rs)
256 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
257 rs->control->desc, rs, rs->refcount);
262 \brief Estimates hit count for result set.
263 \param rs Result Set.
265 rset_count uses rset_pos to get the total and returns that.
266 This is ok for rsisamb/c/s, and for some other rsets, but in case of
267 booleans etc it will give bad estimate, as nothing has been read
270 zint rset_count(RSET rs)
273 RSFD rfd = rset_open(rs, 0);
274 rset_pos(rfd, &cur, &tot);
275 rset_close_int(rs, rfd);
280 \brief is a getterms function for those that don't have any
281 \param ct result set handle
282 \param terms array of terms (0..maxterms-1)
283 \param maxterms length of terms array
284 \param curterm current size of terms array
286 If there is a term associated with rset the term is appeneded; otherwise
287 the terms array is untouched but curterm is incremented anyway.
289 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
293 if (*curterm < maxterms)
294 terms[*curterm] = ct->term;
299 struct ord_list *ord_list_create(NMEM nmem)
304 struct ord_list *ord_list_append(NMEM nmem, struct ord_list *list,
307 struct ord_list *n = nmem_malloc(nmem, sizeof(*n));
313 struct ord_list *ord_list_dup(NMEM nmem, struct ord_list *list)
315 struct ord_list *n = ord_list_create(nmem);
316 for (; list; list = list->next)
317 n = ord_list_append(nmem, n, list->ord);
322 \brief Creates a TERMID entry.
323 \param name Term/Name buffer with given length
324 \param length of term
325 \param flags for term
326 \param type Term Type, Z_Term_general, Z_Term_characterString,..
327 \param nmem memory for term.
329 \param reg_type register type
330 \param hits_limit limit before counting stops and gets approximate
331 \param ref_id supplied ID for term that can be used to identify this
333 TERMID rset_term_create(const char *name, int length, const char *flags,
334 int type, NMEM nmem, struct ord_list *ol,
336 zint hits_limit, const char *ref_id)
340 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
341 name, length, flags, type, nmem);
342 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
345 else if (length == -1)
346 t->name = nmem_strdup(nmem, name);
348 t->name = nmem_strdupn(nmem, name, length);
352 t->ref_id = nmem_strdup(nmem, ref_id);
356 t->flags = nmem_strdup(nmem, flags);
357 t->hits_limit = hits_limit;
359 t->reg_type = reg_type;
362 t->ol = ord_list_dup(nmem, ol);
366 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
368 RSET rset = rfd->rset;
369 int rc = (*rset->control->f_read)(rfd, buf, term);
373 if (rfd->counted_items == 0)
374 got_scope = rset->scope+1;
376 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
379 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
380 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
382 if (got_scope > rset->scope)
384 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
385 rfd->counted_items++;
391 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
392 const void *untilbuf)
394 RSET rset = rfd->rset;
397 if (rset->control->f_forward &&
398 rfd->counted_items >= rset->hits_limit)
400 assert (rset->control->f_forward != rset_default_forward);
401 return rset->control->f_forward(rfd, buf, term, untilbuf);
404 while ((more = rset_read(rfd, buf, term)) > 0)
406 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) <= 1)
410 yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
416 void rset_visit(RSET rset, int level)
419 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
420 rset->hits_approx ? '~' : '=',
422 for (i = 0; i<rset->no_children; i++)
423 rset_visit(rset->children[i], level+1);
429 * indent-tabs-mode: nil
431 * vim: shiftwidth=4 tabstop=8 expandtab