1 /* $Id: rset.c,v 1.56 2006-08-16 13:14:45 adam Exp $
2 Copyright (C) 1995-2006
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;
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;
179 (*kcontrol->inc)(kcontrol);
185 rset->hits_limit = term->hits_limit;
187 rset->no_children = no_children;
191 rset->children = (RSET*)
192 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
193 memcpy(rset->children, children, no_children*sizeof(RSET *));
199 \brief Destructor RSETs
200 \param rs Handle for result set.
202 Destroys a result set and all its children.
203 The f_delete method of control is called for the result set.
205 void rset_delete(RSET rs)
208 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
209 rs->control->desc, rs, rs->refcount);
214 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
216 for (i = 0; i<rs->no_children; i++)
217 rset_delete(rs->children[i]);
218 (*rs->control->f_delete)(rs);
219 (*rs->keycontrol->dec)(rs->keycontrol);
224 \brief Test for last use of RFD
225 \param rfd RFD handle.
227 Returns 1 if this RFD is the last reference to it; 0 otherwise.
229 int rfd_is_last(RSFD rfd)
231 if (rfd->rset->use_list == rfd && rfd->next == 0)
237 \brief Duplicate an RSET
238 \param rs Handle for result set.
240 Duplicates a result set by incrementing the reference count to it.
242 RSET rset_dup (RSET rs)
245 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
246 rs->control->desc, rs, rs->refcount);
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);
362 if (rfd->counted_items == 0)
363 got_scope = rset->scope+1;
365 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
368 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
369 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
371 if (got_scope > rset->scope)
373 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
374 rfd->counted_items++;
380 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
381 const void *untilbuf)
383 RSET rset = rfd->rset;
386 if (rset->control->f_forward &&
387 rfd->counted_items >= rset->hits_limit)
389 assert (rset->control->f_forward != rset_default_forward);
390 return rset->control->f_forward(rfd, buf, term, untilbuf);
393 while ((more = rset_read(rfd, buf, term)) > 0)
395 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) <= 1)
399 yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
405 void rset_visit(RSET rset, int level)
408 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
409 rset->hits_approx ? '~' : '=',
411 for (i = 0; i<rset->no_children; i++)
412 rset_visit(rset->children[i], level+1);
418 * indent-tabs-mode: nil
420 * vim: shiftwidth=4 tabstop=8 expandtab