1 /* $Id: rset.c,v 1.53 2006-05-10 08:13:33 adam Exp $
2 Copyright (C) 1995-2005
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 Zebra; see the file LICENSE.zebra. If not, write to the
19 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
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;
69 \brief Closes a result set RFD handle
70 \param rfd the RFD handle.
72 void rset_close(RSFD rfd)
77 if (rs->hits_count == 0)
81 while(rfd->counted_items <= rs->hits_limit
82 && rset_default_read(rfd, buf, &termid))
85 rs->hits_count = rfd->counted_items;
86 yaz_log(log_level, "rset_close rset=%p hits_count=" ZINT_FORMAT
87 " hits_limit=" ZINT_FORMAT,
88 rs, rs->hits_count, rs->hits_limit);
90 if (rs->hits_count > rs->hits_limit)
94 rset_pos(rfd, &cur, &tot);
97 double ratio = cur/tot;
98 est = (zint)(0.5 + rs->hits_count / ratio);
99 yaz_log(log_level, "Estimating hits (%s) "
100 "%0.1f->" ZINT_FORMAT
101 "; %0.1f->" ZINT_FORMAT,
105 i = 0; /* round to significant digits */
106 while (est > rs->hits_round) {
112 rs->hits_count = est;
116 yaz_log(log_level, "rset_close p=%p count=" ZINT_FORMAT, rs,
119 (*rs->control->f_close)(rfd);
121 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
122 rfd, rs, rfd->priv, rs->free_list);
123 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
127 rfd->next = rs->free_list;
131 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
136 \brief Common constuctor for RSETs
137 \param sel The interface control handle
138 \param nmem The memory handle for it.
139 \param kcontrol Key control info (decode, encode, comparison etc)
140 \param scope scope for set
141 \param term Information about term for it (NULL for none).
142 \param no_children number of child rsets (0 for none)
143 \param children child rsets (NULL for none).
145 Creates an rfd. Either allocates a new one, in which case the priv
146 pointer is null, and will have to be filled in, or picks up one
147 from the freelist, in which case the priv is already allocated,
148 and presumably everything that hangs from it as well
150 RSET rset_create_base(const struct rset_control *sel,
151 NMEM nmem, struct rset_key_control *kcontrol,
152 int scope, TERMID term,
153 int no_children, RSET *children)
157 if (!log_level_initialized)
159 log_level = yaz_log_module_level("rset");
160 log_level_initialized = 1;
163 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
164 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
165 yaz_log(log_level, " ref_id=%s limit=" ZINT_FORMAT,
166 (term && term->ref_id ? term->ref_id : "null"),
172 rset->free_list = NULL;
173 rset->use_list = NULL;
174 rset->hits_count = 0;
175 rset->hits_limit = 0;
176 rset->hits_round = 1000;
177 rset->keycontrol = kcontrol;
178 (*kcontrol->inc)(kcontrol);
184 rset->hits_limit = term->hits_limit;
186 rset->no_children = no_children;
190 rset->children = (RSET*)
191 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
192 memcpy(rset->children, children, no_children*sizeof(RSET *));
198 \brief Destructor RSETs
199 \param rs Handle for result set.
201 Destroys a result set and all its children.
202 The f_delete method of control is called for the result set.
204 void rset_delete(RSET rs)
207 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
208 rs->control->desc, rs, rs->refcount);
213 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
215 for (i = 0; i<rs->no_children; i++)
216 rset_delete(rs->children[i]);
217 (*rs->control->f_delete)(rs);
218 (*rs->keycontrol->dec)(rs->keycontrol);
223 \brief Test for last use of RFD
224 \param rfd RFD handle.
226 Returns 1 if this RFD is the last reference to it; 0 otherwise.
228 int rfd_is_last(RSFD rfd)
230 if (rfd->rset->use_list == rfd && rfd->next == 0)
236 \brief Duplicate an RSET
237 \param rs Handle for result set.
239 Duplicates a result set by incrementing the reference count to it.
241 RSET rset_dup (RSET rs)
244 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
245 rs->control->desc, rs, rs->refcount);
246 (*rs->keycontrol->inc)(rs->keycontrol);
251 \brief Estimates hit count for result set.
252 \param rs Result Set.
254 rset_count uses rset_pos to get the total and returns that.
255 This is ok for rsisamb/c/s, and for some other rsets, but in case of
256 booleans etc it will give bad estimate, as nothing has been read
259 zint rset_count(RSET rs)
262 RSFD rfd = rset_open(rs, 0);
263 rset_pos(rfd, &cur, &tot);
269 \brief is a getterms function for those that don't have any
270 \param ct result set handle
271 \param terms array of terms (0..maxterms-1)
272 \param maxterms length of terms array
273 \param curterm current size of terms array
275 If there is a term associated with rset the term is appeneded; otherwise
276 the terms array is untouched but curterm is incremented anyway.
278 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
282 if (*curterm < maxterms)
283 terms[*curterm] = ct->term;
288 struct ord_list *ord_list_create(NMEM nmem)
293 struct ord_list *ord_list_append(NMEM nmem, struct ord_list *list,
296 struct ord_list *n = nmem_malloc(nmem, sizeof(*n));
302 struct ord_list *ord_list_dup(NMEM nmem, struct ord_list *list)
304 struct ord_list *n = ord_list_create(nmem);
305 for (; list; list = list->next)
306 n = ord_list_append(nmem, n, list->ord);
311 \brief Creates a TERMID entry.
312 \param name Term/Name buffer with given length
313 \param length of term
314 \param flags for term
315 \param type Term Type, Z_Term_general, Z_Term_characterString,..
316 \param nmem memory for term.
318 \param reg_type register type
319 \param hits_limit limit before counting stops and gets approximate
320 \param ref_id supplied ID for term that can be used to identify this
322 TERMID rset_term_create(const char *name, int length, const char *flags,
323 int type, NMEM nmem, struct ord_list *ol,
325 zint hits_limit, const char *ref_id)
329 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
330 name, length, flags, type, nmem);
331 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
334 else if (length == -1)
335 t->name = nmem_strdup(nmem, name);
337 t->name = nmem_strdupn(nmem, name, length);
341 t->ref_id = nmem_strdup(nmem, ref_id);
345 t->flags = nmem_strdup(nmem, flags);
346 t->hits_limit = hits_limit;
348 t->reg_type = reg_type;
351 t->ol = ord_list_dup(nmem, ol);
355 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
357 RSET rset = rfd->rset;
358 int rc = (*rset->control->f_read)(rfd, buf, term);
361 if (rfd->counted_items == 0 ||
362 (rset->keycontrol->cmp)(buf, rfd->counted_buf) > rset->scope)
364 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
365 rfd->counted_items++;
371 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
372 const void *untilbuf)
374 RSET rset = rfd->rset;
377 if (rset->control->f_forward &&
378 rfd->counted_items >= rset->hits_limit)
380 assert (rset->control->f_forward != rset_default_forward);
381 return rset->control->f_forward(rfd, buf, term, untilbuf);
384 while ((more = rset_read(rfd, buf, term)) > 0)
386 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) <= 1)
390 yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
396 void rset_visit(RSET rset, int level)
399 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
400 rset->hits_approx ? '~' : '=',
402 for (i = 0; i<rset->no_children; i++)
403 rset_visit(rset->children[i], level+1);
409 * indent-tabs-mode: nil
411 * vim: shiftwidth=4 tabstop=8 expandtab