1 /* This file is part of the Zebra server.
2 Copyright (C) 1995-2008 Index Data
4 Zebra is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
9 Zebra is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <idzebra/util.h>
27 static int log_level = 0;
28 static int log_level_initialized = 0;
31 \brief Common constuctor for RFDs
32 \param rs Result set handle.
34 Creates an rfd. Either allocates a new one, in which case the priv
35 pointer is null, and will have to be filled in, or picks up one
36 from the freelist, in which case the priv is already allocated,
37 and presumably everything that hangs from it as well
39 RSFD rfd_create_base(RSET rs)
41 RSFD rnew = rs->free_list;
45 rs->free_list = rnew->next;
46 assert(rnew->rset==rs);
47 yaz_log(log_level, "rfd_create_base (fl): rfd=%p rs=%p fl=%p priv=%p",
48 rnew, rs, rs->free_list, rnew->priv);
52 rnew = nmem_malloc(rs->nmem, sizeof(*rnew));
53 rnew->counted_buf = nmem_malloc(rs->nmem, rs->keycontrol->key_size);
56 yaz_log(log_level, "rfd_create_base (new): rfd=%p rs=%p fl=%p priv=%p",
57 rnew, rs, rs->free_list, rnew->priv);
59 rnew->next = rs->use_list;
61 rnew->counted_items = 0;
65 static void rset_close_int(RSET rs, RSFD rfd)
68 (*rs->control->f_close)(rfd);
70 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
71 rfd, rs, rfd->priv, rs->free_list);
72 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
76 rfd->next = rs->free_list;
80 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
84 void rset_set_hits_limit(RSET rs, zint l)
90 \brief Closes a result set RFD handle
91 \param rfd the RFD handle.
93 void rset_close(RSFD rfd)
97 if (rs->hits_count == 0)
102 while(rfd->counted_items <= rs->hits_limit
103 && rset_default_read(rfd, buf, &termid))
106 rs->hits_count = rfd->counted_items;
107 yaz_log(log_level, "rset_close rset=%p hits_count=" ZINT_FORMAT
108 " hits_limit=" ZINT_FORMAT,
109 rs, rs->hits_count, rs->hits_limit);
111 if (rs->hits_count > rs->hits_limit)
115 rset_pos(rfd, &cur, &tot);
118 double ratio = cur/tot;
119 est = (zint)(0.5 + rs->hits_count / ratio);
120 yaz_log(log_level, "Estimating hits (%s) "
121 "%0.1f->" ZINT_FORMAT
122 "; %0.1f->" ZINT_FORMAT,
126 i = 0; /* round to significant digits */
127 while (est > rs->hits_round) {
133 rs->hits_count = est;
137 yaz_log(log_level, "rset_close p=%p count=" ZINT_FORMAT, rs,
140 rset_close_int(rs, rfd);
144 \brief Common constuctor for RSETs
145 \param sel The interface control handle
146 \param nmem The memory handle for it.
147 \param kcontrol Key control info (decode, encode, comparison etc)
148 \param scope scope for set
149 \param term Information about term for it (NULL for none).
150 \param no_children number of child rsets (0 for none)
151 \param children child rsets (NULL for none).
153 Creates an rfd. Either allocates a new one, in which case the priv
154 pointer is null, and will have to be filled in, or picks up one
155 from the freelist, in which case the priv is already allocated,
156 and presumably everything that hangs from it as well
158 RSET rset_create_base(const struct rset_control *sel,
159 NMEM nmem, struct rset_key_control *kcontrol,
160 int scope, TERMID term,
161 int no_children, RSET *children)
165 if (!log_level_initialized)
167 log_level = yaz_log_module_level("rset");
168 log_level_initialized = 1;
171 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
172 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
173 yaz_log(log_level, " ref_id=%s limit=" ZINT_FORMAT,
174 (term && term->ref_id ? term->ref_id : "null"),
180 rset->free_list = NULL;
181 rset->use_list = NULL;
182 rset->hits_count = 0;
183 rset->hits_limit = 0;
184 rset->hits_round = 1000;
185 rset->keycontrol = kcontrol;
187 (*kcontrol->inc)(kcontrol);
193 rset->hits_limit = term->hits_limit;
195 rset->no_children = no_children;
199 rset->children = (RSET*)
200 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
201 memcpy(rset->children, children, no_children*sizeof(RSET *));
207 \brief Destructor RSETs
208 \param rs Handle for result set.
210 Destroys a result set and all its children.
211 The f_delete method of control is called for the result set.
213 void rset_delete(RSET rs)
216 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
217 rs->control->desc, rs, rs->refcount);
222 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
224 for (i = 0; i<rs->no_children; i++)
225 rset_delete(rs->children[i]);
226 (*rs->control->f_delete)(rs);
227 (*rs->keycontrol->dec)(rs->keycontrol);
232 \brief Test for last use of RFD
233 \param rfd RFD handle.
235 Returns 1 if this RFD is the last reference to it; 0 otherwise.
237 int rfd_is_last(RSFD rfd)
239 if (rfd->rset->use_list == rfd && rfd->next == 0)
245 \brief Duplicate an RSET
246 \param rs Handle for result set.
248 Duplicates a result set by incrementing the reference count to it.
250 RSET rset_dup (RSET rs)
253 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
254 rs->control->desc, rs, rs->refcount);
259 \brief Estimates hit count for result set.
260 \param rs Result Set.
262 rset_count uses rset_pos to get the total and returns that.
263 This is ok for rsisamb/c/s, and for some other rsets, but in case of
264 booleans etc it will give bad estimate, as nothing has been read
267 zint rset_count(RSET rs)
270 RSFD rfd = rset_open(rs, 0);
271 rset_pos(rfd, &cur, &tot);
272 rset_close_int(rs, rfd);
277 \brief is a getterms function for those that don't have any
278 \param ct result set handle
279 \param terms array of terms (0..maxterms-1)
280 \param maxterms length of terms array
281 \param curterm current size of terms array
283 If there is a term associated with rset the term is appeneded; otherwise
284 the terms array is untouched but curterm is incremented anyway.
286 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
290 if (*curterm < maxterms)
291 terms[*curterm] = ct->term;
296 struct ord_list *ord_list_create(NMEM nmem)
301 struct ord_list *ord_list_append(NMEM nmem, struct ord_list *list,
304 struct ord_list *n = nmem_malloc(nmem, sizeof(*n));
310 struct ord_list *ord_list_dup(NMEM nmem, struct ord_list *list)
312 struct ord_list *n = ord_list_create(nmem);
313 for (; list; list = list->next)
314 n = ord_list_append(nmem, n, list->ord);
319 \brief Creates a TERMID entry.
320 \param name Term/Name buffer with given length
321 \param length of term
322 \param flags for term
323 \param type Term Type, Z_Term_general, Z_Term_characterString,..
324 \param nmem memory for term.
326 \param reg_type register type
327 \param hits_limit limit before counting stops and gets approximate
328 \param ref_id supplied ID for term that can be used to identify this
330 TERMID rset_term_create(const char *name, int length, const char *flags,
331 int type, NMEM nmem, struct ord_list *ol,
333 zint hits_limit, const char *ref_id)
337 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
338 name, length, flags, type, nmem);
339 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
342 else if (length == -1)
343 t->name = nmem_strdup(nmem, name);
345 t->name = nmem_strdupn(nmem, name, length);
349 t->ref_id = nmem_strdup(nmem, ref_id);
353 t->flags = nmem_strdup(nmem, flags);
354 t->hits_limit = hits_limit;
356 t->reg_type = reg_type;
359 t->ol = ord_list_dup(nmem, ol);
363 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
365 RSET rset = rfd->rset;
366 int rc = (*rset->control->f_read)(rfd, buf, term);
370 if (rfd->counted_items == 0)
371 got_scope = rset->scope+1;
373 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
376 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
377 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
379 if (got_scope > rset->scope)
381 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
382 rfd->counted_items++;
388 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
389 const void *untilbuf)
391 RSET rset = rfd->rset;
394 if (rset->control->f_forward &&
395 rfd->counted_items >= rset->hits_limit)
397 assert (rset->control->f_forward != rset_default_forward);
398 return rset->control->f_forward(rfd, buf, term, untilbuf);
401 while ((more = rset_read(rfd, buf, term)) > 0)
403 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) <= 1)
407 yaz_log (log_level, "rset_default_forward exiting m=%d c=%d",
413 void rset_visit(RSET rset, int level)
416 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
417 rset->hits_approx ? '~' : '=',
419 for (i = 0; i<rset->no_children; i++)
420 rset_visit(rset->children[i], level+1);
426 * indent-tabs-mode: nil
428 * vim: shiftwidth=4 tabstop=8 expandtab