1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2009 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 && rs->hits_limit > 0)
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(%s) p=%p count=" ZINT_FORMAT,
138 rs->control->desc, rs,
141 rset_close_int(rs, rfd);
145 \brief Common constuctor for RSETs
146 \param sel The interface control handle
147 \param nmem The memory handle for it.
148 \param kcontrol Key control info (decode, encode, comparison etc)
149 \param scope scope for set
150 \param term Information about term for it (NULL for none).
151 \param no_children number of child rsets (0 for none)
152 \param children child rsets (NULL for none).
154 Creates an rfd. Either allocates a new one, in which case the priv
155 pointer is null, and will have to be filled in, or picks up one
156 from the freelist, in which case the priv is already allocated,
157 and presumably everything that hangs from it as well
159 RSET rset_create_base(const struct rset_control *sel,
160 NMEM nmem, struct rset_key_control *kcontrol,
161 int scope, TERMID term,
162 int no_children, RSET *children)
166 if (!log_level_initialized)
168 log_level = yaz_log_module_level("rset");
169 log_level_initialized = 1;
172 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
173 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
174 yaz_log(log_level, " ref_id=%s",
175 (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);
318 void ord_list_print(struct ord_list *list)
320 for (; list; list = list->next)
321 yaz_log(YLOG_LOG, "ord_list %d", list->ord);
324 \brief Creates a TERMID entry.
325 \param name Term/Name buffer with given length
326 \param length of term
327 \param flags for term
328 \param type Term Type, Z_Term_general, Z_Term_characterString,..
329 \param nmem memory for term.
331 \param reg_type register type
332 \param hits_limit limit before counting stops and gets approximate
333 \param ref_id supplied ID for term that can be used to identify this
335 TERMID rset_term_create(const char *name, int length, const char *flags,
336 int type, NMEM nmem, struct ord_list *ol,
338 zint hits_limit, const char *ref_id)
342 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
343 name, length, flags, type, nmem);
344 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
347 else if (length == -1)
348 t->name = nmem_strdup(nmem, name);
350 t->name = nmem_strdupn(nmem, name, length);
354 t->ref_id = nmem_strdup(nmem, ref_id);
358 t->flags = nmem_strdup(nmem, flags);
359 t->hits_limit = hits_limit;
361 t->reg_type = reg_type;
364 t->ol = ord_list_dup(nmem, ol);
368 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
370 RSET rset = rfd->rset;
371 int rc = (*rset->control->f_read)(rfd, buf, term);
375 if (rfd->counted_items == 0)
376 got_scope = rset->scope+1;
378 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
381 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
382 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
384 if (got_scope > rset->scope)
386 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
387 rfd->counted_items++;
393 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
394 const void *untilbuf)
396 RSET rset = rfd->rset;
399 if (rset->control->f_forward &&
400 rfd->counted_items >= rset->hits_limit)
402 assert (rset->control->f_forward != rset_default_forward);
403 return rset->control->f_forward(rfd, buf, term, untilbuf);
406 while ((more = rset_read(rfd, buf, term)) > 0)
408 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) < rset->scope)
412 yaz_log(log_level, "rset_default_forward exiting rfd=%p scope=%d m=%d c=%d",
413 rfd, rset->scope, more, rset->scope);
418 void rset_visit(RSET rset, int level)
421 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
422 rset->hits_approx ? '~' : '=',
424 for (i = 0; i<rset->no_children; i++)
425 rset_visit(rset->children[i], level+1);
431 * c-file-style: "Stroustrup"
432 * indent-tabs-mode: nil
434 * vim: shiftwidth=4 tabstop=8 expandtab