1 /* This file is part of the Zebra server.
2 Copyright (C) 1994-2010 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;
32 \brief Common constuctor for RFDs
33 \param rs Result set handle.
35 Creates an rfd. Either allocates a new one, in which case the priv
36 pointer is null, and will have to be filled in, or picks up one
37 from the freelist, in which case the priv is already allocated,
38 and presumably everything that hangs from it as well
40 RSFD rfd_create_base(RSET rs)
42 RSFD rnew = rs->free_list;
46 rs->free_list = rnew->next;
47 assert(rnew->rset==rs);
48 yaz_log(log_level, "rfd_create_base (fl): rfd=%p rs=%p fl=%p priv=%p",
49 rnew, rs, rs->free_list, rnew->priv);
53 rnew = nmem_malloc(rs->nmem, sizeof(*rnew));
54 rnew->counted_buf = nmem_malloc(rs->nmem, rs->keycontrol->key_size);
57 yaz_log(log_level, "rfd_create_base (new): rfd=%p rs=%p fl=%p priv=%p",
58 rnew, rs, rs->free_list, rnew->priv);
60 rnew->next = rs->use_list;
62 rnew->counted_items = 0;
66 static void rset_close_int(RSET rs, RSFD rfd)
69 (*rs->control->f_close)(rfd);
71 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
72 rfd, rs, rfd->priv, rs->free_list);
73 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
77 rfd->next = rs->free_list;
81 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
85 void rset_set_hits_limit(RSET rs, zint l)
87 yaz_log(log_level, "rset_set_hits_limit %p l=" ZINT_FORMAT, rs, l);
92 \brief Closes a result set RFD handle
93 \param rfd the RFD handle.
95 void rset_close(RSFD rfd)
99 if (rs->hits_count == 0)
104 while (rfd->counted_items <= rs->hits_limit
105 && rset_default_read(rfd, buf, &termid))
108 rs->hits_count = rfd->counted_items;
109 yaz_log(log_level, "rset_close rset=%p hits_count=" ZINT_FORMAT
110 " hits_limit=" ZINT_FORMAT,
111 rs, rs->hits_count, rs->hits_limit);
113 if (rs->hits_count > rs->hits_limit && rs->hits_limit > 0)
117 rset_pos(rfd, &cur, &tot);
120 double ratio = cur/tot;
121 est = (zint)(0.5 + rs->hits_count / ratio);
122 yaz_log(log_level, "Estimating hits (%s) "
123 "%0.1f->" ZINT_FORMAT
124 "; %0.1f->" ZINT_FORMAT,
128 i = 0; /* round to significant digits */
129 while (est > rs->hits_round) {
135 rs->hits_count = est;
139 yaz_log(log_level, "rset_close(%s) p=%p count=" ZINT_FORMAT,
140 rs->control->desc, rs,
143 rset_close_int(rs, rfd);
147 \brief Common constuctor for RSETs
148 \param sel The interface control handle
149 \param nmem The memory handle for it.
150 \param kcontrol Key control info (decode, encode, comparison etc)
151 \param scope scope for set
152 \param term Information about term for it (NULL for none).
153 \param no_children number of child rsets (0 for none)
154 \param children child rsets (NULL for none).
156 Creates an rfd. Either allocates a new one, in which case the priv
157 pointer is null, and will have to be filled in, or picks up one
158 from the freelist, in which case the priv is already allocated,
159 and presumably everything that hangs from it as well
161 RSET rset_create_base(const struct rset_control *sel,
162 NMEM nmem, struct rset_key_control *kcontrol,
163 int scope, TERMID term,
164 int no_children, RSET *children)
168 if (!log_level_initialized)
170 log_level = yaz_log_module_level("rset");
171 log_level_initialized = 1;
174 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
175 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
176 yaz_log(log_level, " ref_id=%s",
177 (term && term->ref_id ? term->ref_id : "null"));
182 rset->free_list = NULL;
183 rset->use_list = NULL;
184 rset->hits_count = 0;
185 rset->hits_limit = 0;
186 rset->hits_round = 1000;
187 rset->keycontrol = kcontrol;
189 (*kcontrol->inc)(kcontrol);
195 rset->hits_limit = term->hits_limit;
197 rset->no_children = no_children;
201 rset->children = (RSET*)
202 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
203 memcpy(rset->children, children, no_children*sizeof(RSET *));
209 \brief Destructor RSETs
210 \param rs Handle for result set.
212 Destroys a result set and all its children.
213 The f_delete method of control is called for the result set.
215 void rset_delete(RSET rs)
218 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
219 rs->control->desc, rs, rs->refcount);
224 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
226 for (i = 0; i<rs->no_children; i++)
227 rset_delete(rs->children[i]);
228 (*rs->control->f_delete)(rs);
229 (*rs->keycontrol->dec)(rs->keycontrol);
234 \brief Test for last use of RFD
235 \param rfd RFD handle.
237 Returns 1 if this RFD is the last reference to it; 0 otherwise.
239 int rfd_is_last(RSFD rfd)
241 if (rfd->rset->use_list == rfd && rfd->next == 0)
247 \brief Duplicate an RSET
248 \param rs Handle for result set.
250 Duplicates a result set by incrementing the reference count to it.
252 RSET rset_dup (RSET rs)
255 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
256 rs->control->desc, rs, rs->refcount);
261 \brief Estimates hit count for result set.
262 \param rs Result Set.
264 rset_count uses rset_pos to get the total and returns that.
265 This is ok for rsisamb/c/s, and for some other rsets, but in case of
266 booleans etc it will give bad estimate, as nothing has been read
269 zint rset_count(RSET rs)
272 RSFD rfd = rset_open(rs, 0);
273 rset_pos(rfd, &cur, &tot);
274 rset_close_int(rs, rfd);
279 \brief is a getterms function for those that don't have any
280 \param ct result set handle
281 \param terms array of terms (0..maxterms-1)
282 \param maxterms length of terms array
283 \param curterm current size of terms array
285 If there is a term associated with rset the term is appeneded; otherwise
286 the terms array is untouched but curterm is incremented anyway.
288 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
292 if (*curterm < maxterms)
293 terms[*curterm] = ct->term;
298 struct ord_list *ord_list_create(NMEM nmem)
303 struct ord_list *ord_list_append(NMEM nmem, struct ord_list *list,
306 struct ord_list *n = nmem_malloc(nmem, sizeof(*n));
312 struct ord_list *ord_list_dup(NMEM nmem, struct ord_list *list)
314 struct ord_list *n = ord_list_create(nmem);
315 for (; list; list = list->next)
316 n = ord_list_append(nmem, n, list->ord);
320 void ord_list_print(struct ord_list *list)
322 for (; list; list = list->next)
323 yaz_log(YLOG_LOG, "ord_list %d", list->ord);
326 \brief Creates a TERMID entry.
327 \param name Term/Name buffer with given length
328 \param length of term
329 \param flags for term
330 \param type Term Type, Z_Term_general, Z_Term_characterString,..
331 \param nmem memory for term.
333 \param reg_type register type
334 \param hits_limit limit before counting stops and gets approximate
335 \param ref_id supplied ID for term that can be used to identify this
337 TERMID rset_term_create(const char *name, int length, const char *flags,
338 int type, NMEM nmem, struct ord_list *ol,
340 zint hits_limit, const char *ref_id)
344 yaz_log (log_level, "term_create '%s' %d f=%s type=%d nmem=%p",
345 name, length, flags, type, nmem);
346 t= (TERMID) nmem_malloc(nmem, sizeof(*t));
349 else if (length == -1)
350 t->name = nmem_strdup(nmem, name);
352 t->name = nmem_strdupn(nmem, name, length);
356 t->ref_id = nmem_strdup(nmem, ref_id);
360 t->flags = nmem_strdup(nmem, flags);
361 t->hits_limit = hits_limit;
363 t->reg_type = reg_type;
366 t->ol = ord_list_dup(nmem, ol);
370 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
372 RSET rset = rfd->rset;
373 int rc = (*rset->control->f_read)(rfd, buf, term);
377 if (rfd->counted_items == 0)
378 got_scope = rset->scope+1;
380 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
383 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
384 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
386 if (got_scope > rset->scope)
388 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
389 rfd->counted_items++;
395 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
396 const void *untilbuf)
398 RSET rset = rfd->rset;
401 if (rset->control->f_forward &&
402 rfd->counted_items >= rset->hits_limit)
404 assert (rset->control->f_forward != rset_default_forward);
405 return rset->control->f_forward(rfd, buf, term, untilbuf);
408 while ((more = rset_read(rfd, buf, term)) > 0)
410 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) < rset->scope)
414 yaz_log(log_level, "rset_default_forward exiting rfd=%p scope=%d m=%d c=%d",
415 rfd, rset->scope, more, rset->scope);
420 void rset_visit(RSET rset, int level)
423 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
424 rset->hits_approx ? '~' : '=',
426 for (i = 0; i<rset->no_children; i++)
427 rset_visit(rset->children[i], level+1);
433 * c-file-style: "Stroustrup"
434 * indent-tabs-mode: nil
436 * vim: shiftwidth=4 tabstop=8 expandtab