1 /* This file is part of the Zebra server.
2 Copyright (C) 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
25 #include <idzebra/util.h>
30 static int log_level = 0;
31 static int log_level_initialized = 0;
35 \brief Common constuctor for RFDs
36 \param rs Result set handle.
38 Creates an rfd. Either allocates a new one, in which case the priv
39 pointer is null, and will have to be filled in, or picks up one
40 from the freelist, in which case the priv is already allocated,
41 and presumably everything that hangs from it as well
43 RSFD rfd_create_base(RSET rs)
45 RSFD rnew = rs->free_list;
49 rs->free_list = rnew->next;
50 assert(rnew->rset==rs);
51 yaz_log(log_level, "rfd_create_base (fl): rfd=%p rs=%p fl=%p priv=%p",
52 rnew, rs, rs->free_list, rnew->priv);
56 rnew = nmem_malloc(rs->nmem, sizeof(*rnew));
57 rnew->counted_buf = nmem_malloc(rs->nmem, rs->keycontrol->key_size);
60 yaz_log(log_level, "rfd_create_base (new): rfd=%p rs=%p fl=%p priv=%p",
61 rnew, rs, rs->free_list, rnew->priv);
63 rnew->next = rs->use_list;
65 rnew->counted_items = 0;
69 static void rset_close_int(RSET rs, RSFD rfd)
72 (*rs->control->f_close)(rfd);
74 yaz_log(log_level, "rfd_delete_base: rfd=%p rs=%p priv=%p fl=%p",
75 rfd, rs, rfd->priv, rs->free_list);
76 for (pfd = &rs->use_list; *pfd; pfd = &(*pfd)->next)
80 rfd->next = rs->free_list;
84 yaz_log(YLOG_WARN, "rset_close handle not found. type=%s",
88 void rset_set_hits_limit(RSET rs, zint l)
90 yaz_log(log_level, "rset_set_hits_limit %p l=" ZINT_FORMAT, rs, l);
95 \brief Closes a result set RFD handle
96 \param rfd the RFD handle.
98 void rset_close(RSFD rfd)
102 if (rs->hits_count == 0)
107 while (rfd->counted_items <= rs->hits_limit
108 && rset_default_read(rfd, buf, &termid))
111 rs->hits_count = rfd->counted_items;
112 yaz_log(log_level, "rset_close rset=%p hits_count=" ZINT_FORMAT
113 " hits_limit=" ZINT_FORMAT,
114 rs, rs->hits_count, rs->hits_limit);
116 if (rs->hits_count > rs->hits_limit && rs->hits_limit > 0)
120 rset_pos(rfd, &cur, &tot);
123 double ratio = cur/tot;
124 est = (zint)(0.5 + rs->hits_count / ratio);
125 yaz_log(log_level, "Estimating hits (%s) "
126 "%0.1f->" ZINT_FORMAT
127 "; %0.1f->" ZINT_FORMAT,
131 i = 0; /* round to significant digits */
132 while (est > rs->hits_round) {
138 rs->hits_count = est;
142 yaz_log(log_level, "rset_close(%s) p=%p count=" ZINT_FORMAT,
143 rs->control->desc, rs,
146 rset_close_int(rs, rfd);
150 \brief Common constuctor for RSETs
151 \param sel The interface control handle
152 \param nmem The memory handle for it.
153 \param kcontrol Key control info (decode, encode, comparison etc)
154 \param scope scope for set
155 \param term Information about term for it (NULL for none).
156 \param no_children number of child rsets (0 for none)
157 \param children child rsets (NULL for none).
159 Creates an rfd. Either allocates a new one, in which case the priv
160 pointer is null, and will have to be filled in, or picks up one
161 from the freelist, in which case the priv is already allocated,
162 and presumably everything that hangs from it as well
164 RSET rset_create_base(const struct rset_control *sel,
165 NMEM nmem, struct rset_key_control *kcontrol,
166 int scope, TERMID term,
167 int no_children, RSET *children)
171 if (!log_level_initialized)
173 log_level = yaz_log_module_level("rset");
174 log_level_initialized = 1;
177 rset = (RSET) nmem_malloc(nmem, sizeof(*rset));
178 yaz_log(log_level, "rs_create(%s) rs=%p (nm=%p)", sel->desc, rset, nmem);
179 yaz_log(log_level, " ref_id=%s",
180 (term && term->ref_id ? term->ref_id : "null"));
185 rset->free_list = NULL;
186 rset->use_list = NULL;
187 rset->hits_count = 0;
188 rset->hits_limit = 0;
189 rset->hits_round = 1000;
190 rset->keycontrol = kcontrol;
192 (*kcontrol->inc)(kcontrol);
198 rset->hits_limit = term->hits_limit;
200 rset->no_children = no_children;
204 rset->children = (RSET*)
205 nmem_malloc(rset->nmem, no_children*sizeof(RSET *));
206 memcpy(rset->children, children, no_children*sizeof(RSET *));
212 \brief Destructor RSETs
213 \param rs Handle for result set.
215 Destroys a result set and all its children.
216 The f_delete method of control is called for the result set.
218 void rset_delete(RSET rs)
221 yaz_log(log_level, "rs_delete(%s), rs=%p, refcount=%d",
222 rs->control->desc, rs, rs->refcount);
227 yaz_log(YLOG_WARN, "rs_delete(%s) still has RFDs in use",
229 for (i = 0; i<rs->no_children; i++)
230 rset_delete(rs->children[i]);
231 (*rs->control->f_delete)(rs);
232 (*rs->keycontrol->dec)(rs->keycontrol);
237 \brief Test for last use of RFD
238 \param rfd RFD handle.
240 Returns 1 if this RFD is the last reference to it; 0 otherwise.
242 int rfd_is_last(RSFD rfd)
244 if (rfd->rset->use_list == rfd && rfd->next == 0)
250 \brief Duplicate an RSET
251 \param rs Handle for result set.
253 Duplicates a result set by incrementing the reference count to it.
255 RSET rset_dup (RSET rs)
258 yaz_log(log_level, "rs_dup(%s), rs=%p, refcount=%d",
259 rs->control->desc, rs, rs->refcount);
264 \brief Estimates hit count for result set.
265 \param rs Result Set.
267 rset_count uses rset_pos to get the total and returns that.
268 This is ok for rsisamb/c/s, and for some other rsets, but in case of
269 booleans etc it will give bad estimate, as nothing has been read
272 zint rset_count(RSET rs)
275 RSFD rfd = rset_open(rs, 0);
276 rset_pos(rfd, &cur, &tot);
277 rset_close_int(rs, rfd);
282 \brief is a getterms function for those that don't have any
283 \param ct result set handle
284 \param terms array of terms (0..maxterms-1)
285 \param maxterms length of terms array
286 \param curterm current size of terms array
288 If there is a term associated with rset the term is appeneded; otherwise
289 the terms array is untouched but curterm is incremented anyway.
291 void rset_get_one_term(RSET ct, TERMID *terms, int maxterms, int *curterm)
295 if (*curterm < maxterms)
296 terms[*curterm] = ct->term;
301 struct ord_list *ord_list_create(NMEM nmem)
306 struct ord_list *ord_list_append(NMEM nmem, struct ord_list *list,
309 struct ord_list *n = nmem_malloc(nmem, sizeof(*n));
315 struct ord_list *ord_list_dup(NMEM nmem, struct ord_list *list)
317 struct ord_list *n = ord_list_create(nmem);
318 for (; list; list = list->next)
319 n = ord_list_append(nmem, n, list->ord);
323 void ord_list_print(struct ord_list *list)
325 for (; list; list = list->next)
326 yaz_log(YLOG_LOG, "ord_list %d", list->ord);
329 \brief Creates a TERMID entry.
330 \param name Term/Name buffer with given length
331 \param length of term
332 \param flags for term
333 \param type Term Type, Z_Term_general, Z_Term_characterString,..
334 \param nmem memory for term.
336 \param reg_type register type
337 \param hits_limit limit before counting stops and gets approximate
338 \param ref_id supplied ID for term that can be used to identify this
340 TERMID rset_term_create(const char *name, int length, const char *flags,
341 int type, NMEM nmem, struct ord_list *ol,
343 zint hits_limit, const char *ref_id)
346 TERMID t = (TERMID) nmem_malloc(nmem, sizeof(*t));
351 t->name = nmem_strdup(nmem, name);
353 t->name = nmem_strdupn(nmem, name, length);
357 t->ref_id = nmem_strdup(nmem, ref_id);
361 t->flags = nmem_strdup(nmem, flags);
362 t->hits_limit = hits_limit;
364 t->reg_type = reg_type;
367 t->ol = ord_list_dup(nmem, ol);
371 int rset_default_read(RSFD rfd, void *buf, TERMID *term)
373 RSET rset = rfd->rset;
374 int rc = (*rset->control->f_read)(rfd, buf, term);
378 if (rfd->counted_items == 0)
379 got_scope = rset->scope+1;
381 got_scope = rset->keycontrol->cmp(buf, rfd->counted_buf);
384 key_logdump_txt(YLOG_LOG, buf, "rset_default_read");
385 yaz_log(YLOG_LOG, "rset_scope=%d got_scope=%d", rset->scope, got_scope);
387 if (got_scope > rset->scope)
389 memcpy(rfd->counted_buf, buf, rset->keycontrol->key_size);
390 rfd->counted_items++;
396 int rset_default_forward(RSFD rfd, void *buf, TERMID *term,
397 const void *untilbuf)
399 RSET rset = rfd->rset;
402 if (rset->control->f_forward &&
403 rfd->counted_items >= rset->hits_limit)
405 assert (rset->control->f_forward != rset_default_forward);
406 return rset->control->f_forward(rfd, buf, term, untilbuf);
409 while ((more = rset_read(rfd, buf, term)) > 0)
411 if ((rfd->rset->keycontrol->cmp)(untilbuf, buf) < rset->scope)
415 yaz_log(log_level, "rset_default_forward exiting rfd=%p scope=%d m=%d c=%d",
416 rfd, rset->scope, more, rset->scope);
421 void rset_visit(RSET rset, int level)
424 yaz_log(YLOG_LOG, "%*s%c " ZINT_FORMAT, level, "",
425 rset->hits_approx ? '~' : '=',
427 for (i = 0; i<rset->no_children; i++)
428 rset_visit(rset->children[i], level+1);
431 int rset_no_write(RSFD rfd, const void *buf)
433 yaz_log(YLOG_FATAL, "%s set type is read-only", rfd->rset->control->desc);
440 * c-file-style: "Stroustrup"
441 * indent-tabs-mode: nil
443 * vim: shiftwidth=4 tabstop=8 expandtab