1 /* $Id: rset.c,v 1.47 2005-06-02 11:59:54 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;
87 if (rs->hits_count >= rs->hits_limit)
91 rset_pos(rfd, &cur, &tot);
94 double ratio = cur/tot;
95 est = (zint)(0.5 + rs->hits_count / ratio);
96 yaz_log(log_level, "Estimating hits (%s) "
98 "; %0.1f->" ZINT_FORMAT,
102 i = 0; /* round to significant digits */
103 while (est > rs->hits_round) {
109 rs->hits_count = est;
113 yaz_log(log_level, "rset_close p=%p count=" ZINT_FORMAT, rs,
116 (*rs->control->f_close)(rfd);
118 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
119 rfd, rs, rfd->priv, rs->free_list);
120 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
124 rfd->next = rs->free_list;
128 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
133 \brief Common constuctor for RSETs
134 \param sel The interface control handle
135 \param nmem The memory handle for it.
136 \param kcontrol Key control info (decode, encode, comparison etc)
137 \param scope scope for set
138 \param term Information about term for it (NULL for none).
139 \param no_children number of child rsets (0 for none)
140 \param children child rsets (NULL for none).
142 Creates an rfd. Either allocates a new one, in which case the priv
143 pointer is null, and will have to be filled in, or picks up one
144 from the freelist, in which case the priv is already allocated,
145 and presumably everything that hangs from it as well
147 RSET rset_create_base(const struct rset_control *sel,
148 NMEM nmem, struct rset_key_control *kcontrol,
149 int scope, TERMID term,
150 int no_children, RSET *children)
154 if (!log_level_initialized)
156 log_level = yaz_log_module_level("rset");
157 log_level_initialized = 1;
160 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
161 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
166 rset->free_list = NULL;
167 rset->use_list = NULL;
168 rset->hits_count = 0;
169 rset->hits_limit = 1000;
170 rset->hits_round = 1000;
171 rset->keycontrol = kcontrol;
172 (*kcontrol->inc)(kcontrol);
178 rset->no_children = no_children;
182 rset->children = (RSET*)
183 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
184 memcpy(rset->children, children, no_children*sizeof(RSET *));
190 \brief Destructor RSETs
191 \param rs Handle for result set.
193 Destroys a result set and all its children.
194 The f_delete method of control is called for the result set.
196 void rset_delete(RSET rs)
199 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
200 rs->control->desc, rs, rs->refcount);
205 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
207 for (i = 0; i<rs->no_children; i++)
208 rset_delete(rs->children[i]);
209 (*rs->control->f_delete)(rs);
210 (*rs->keycontrol->dec)(rs->keycontrol);
215 \brief Test for last use of RFD
216 \param rfd RFD handle.
218 Returns 1 if this RFD is the last reference to it; 0 otherwise.
220 int rfd_is_last(RSFD rfd)
222 if (rfd->rset->use_list == rfd && rfd->next == 0)
228 \brief Duplicate an RSET
229 \param rs Handle for result set.
231 Duplicates a result set by incrementing the reference count to it.
233 RSET rset_dup (RSET rs)
236 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
237 rs->control->desc, rs, rs->refcount);
238 (*rs->keycontrol->inc)(rs->keycontrol);
243 \brief Estimates hit count for result set.
244 \param rs Result Set.
246 rset_count uses rset_pos to get the total and returns that.
247 This is ok for rsisamb/c/s, and for some other rsets, but in case of
248 booleans etc it will give bad estimate, as nothing has been read
251 zint rset_count(RSET rs)
254 RSFD rfd = rset_open(rs, 0);
255 rset_pos(rfd, &cur, &tot);
261 \brief is a getterms function for those that don't have any
262 \param ct result set handle
263 \param terms array of terms (0..maxterms-1)
264 \param maxterms length of terms array
265 \param curterm current size of terms array
267 If there is a term associated with rset the term is appeneded; otherwise
268 the terms array is untouched but curterm is incremented anyway.
270 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
274 if (*curterm < maxterms)
275 terms[*curterm] = ct->term;
281 \brief Creates a TERMID entry.
282 \param name Term/Name buffer with given length
283 \param length of term
284 \param flags for term
285 \param type Term Type, Z_Term_general, Z_Term_characterString,..
286 \param nmem memory for term.
288 TERMID rset_term_create(const char *name, int length, const char *flags,
293 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
294 name, length, flags, type, nmem);
295 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
298 else if (length == -1)
299 t->name = nmem_strdup(nmem, name);
302 t->name = (char*) nmem_malloc(nmem, length+1);
303 memcpy (t->name, name, length);
304 t->name[length] = '\0';
309 t->flags = nmem_strdup(nmem, flags);
316 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
318 RSET rset = rfd->rset;
319 int rc = (*rset->control->f_read)(rfd, buf, term);
322 if (rfd->counted_items == 0 ||
323 (rset->keycontrol->cmp)(buf, rfd->counted_buf) >= rset->scope)
325 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
326 rfd->counted_items++;
332 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
333 const void *untilbuf)
335 RSET rset = rfd->rset;
338 if (rset->control->f_forward &&
339 rfd->counted_items >= rset->hits_limit)
341 assert (rset->control->f_forward != rset_default_forward);
342 return rset->control->f_forward(rfd, buf, term, untilbuf);
345 while ((more = rset_read(rfd, buf, term)) > 0)
347 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) <= 1)
351 yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
357 void rset_visit(RSET rset, int level)
360 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
361 rset->hits_approx ? '~' : '=',
363 for (i = 0; i<rset->no_children; i++)
364 rset_visit(rset->children[i], level+1);