Branch data Line data Source code
1 : : /* flint_alltermslist.cc: A termlist containing all terms in a flint database.
2 : : *
3 : : * Copyright (C) 2005,2007,2008,2009,2010 Olly Betts
4 : : *
5 : : * This program is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU General Public License as
7 : : * published by the Free Software Foundation; either version 2 of the
8 : : * License, or (at your option) any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : : * GNU General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License
16 : : * along with this program; if not, write to the Free Software
17 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18 : : * USA
19 : : */
20 : :
21 : : #include <config.h>
22 : : #include "flint_alltermslist.h"
23 : :
24 : : #include "debuglog.h"
25 : : #include "flint_postlist.h"
26 : : #include "flint_utils.h"
27 : : #include "stringutils.h"
28 : :
29 : : void
30 : 998 : FlintAllTermsList::read_termfreq_and_collfreq() const
31 : : {
32 : : LOGCALL_VOID(DB, "FlintAllTermsList::read_termfreq_and_collfreq", NO_ARGS);
33 : : Assert(!current_term.empty());
34 : : Assert(!at_end());
35 : :
36 : : // Unpack the termfreq and collfreq from the tag. Only do this if
37 : : // one or other is actually read.
38 : 998 : cursor->read_tag();
39 : 998 : const char *p = cursor->current_tag.data();
40 : 998 : const char *pend = p + cursor->current_tag.size();
41 : 998 : FlintPostList::read_number_of_entries(&p, pend, &termfreq, &collfreq);
42 : 998 : }
43 : :
44 : 231 : FlintAllTermsList::~FlintAllTermsList()
45 : : {
46 : : LOGCALL_DTOR(DB, "FlintAllTermsList");
47 [ + - ][ # # ]: 231 : delete cursor;
[ # # ]
48 [ + - ][ # # ]: 231 : }
[ # # ]
49 : :
50 : : string
51 : 16856 : FlintAllTermsList::get_termname() const
52 : : {
53 : : LOGCALL(DB, string, "FlintAllTermsList::get_termname", NO_ARGS);
54 : : Assert(!current_term.empty());
55 : : Assert(!at_end());
56 : 16856 : RETURN(current_term);
57 : : }
58 : :
59 : : Xapian::doccount
60 : 998 : FlintAllTermsList::get_termfreq() const
61 : : {
62 : : LOGCALL(DB, Xapian::doccount, "FlintAllTermsList::get_termfreq", NO_ARGS);
63 : : Assert(!current_term.empty());
64 : : Assert(!at_end());
65 [ + - ]: 998 : if (termfreq == 0) read_termfreq_and_collfreq();
66 : 998 : RETURN(termfreq);
67 : : }
68 : :
69 : : Xapian::termcount
70 : 0 : FlintAllTermsList::get_collection_freq() const
71 : : {
72 : : LOGCALL(DB, Xapian::termcount, "FlintAllTermsList::get_collection_freq", NO_ARGS);
73 : : Assert(!current_term.empty());
74 : : Assert(!at_end());
75 [ # # ]: 0 : if (termfreq == 0) read_termfreq_and_collfreq();
76 : 0 : RETURN(collfreq);
77 : : }
78 : :
79 : : TermList *
80 : 1405 : FlintAllTermsList::next()
81 : : {
82 : : LOGCALL(DB, TermList *, "FlintAllTermsList::next", NO_ARGS);
83 : : Assert(!at_end());
84 : : // Set termfreq to 0 to indicate no termfreq/collfreq have been read for
85 : : // the current term.
86 : 1405 : termfreq = 0;
87 : :
88 [ + + ]: 1405 : if (rare(!cursor)) {
89 : 231 : cursor = database->postlist_table.cursor_get();
90 : : Assert(cursor); // The postlist table isn't optional.
91 : :
92 [ + + ]: 231 : if (prefix.empty()) {
93 : 146 : (void)cursor->find_entry_ge(string("\x00\xff", 2));
94 : : } else {
95 : 85 : const string & key = F_pack_string_preserving_sort(prefix);
96 [ + + ]: 85 : if (cursor->find_entry_ge(key)) {
97 : : // The exact term we asked for is there, so just copy it rather
98 : : // than wasting effort unpacking it from the key.
99 : 5 : current_term = prefix;
100 : 82 : RETURN(NULL);
101 [ + + ]: 85 : }
102 : : }
103 : 223 : goto first_time;
104 : : }
105 : :
106 : 204 : while (true) {
107 : 1378 : cursor->next();
108 : : first_time:
109 [ + + ]: 1601 : if (cursor->after_end()) {
110 : 158 : current_term.resize(0);
111 : 158 : RETURN(NULL);
112 : : }
113 : :
114 : 1443 : const char *p = cursor->current_key.data();
115 : 1443 : const char *pend = p + cursor->current_key.size();
116 [ - + ]: 1443 : if (!F_unpack_string_preserving_sort(&p, pend, current_term)) {
117 : 0 : throw Xapian::DatabaseCorruptError("PostList table key has unexpected format");
118 : : }
119 : :
120 : : // If this key is for the first chunk of a postlist, we're done.
121 : : // Otherwise we need to skip past continuation chunks until we find the
122 : : // first chunk of the next postlist.
123 [ + + ]: 1443 : if (p == pend) break;
124 : : }
125 : :
126 [ + + ]: 1239 : if (!startswith(current_term, prefix)) {
127 : : // We've reached the end of the prefixed terms.
128 : 59 : cursor->to_end();
129 : 59 : current_term.resize(0);
130 : : }
131 : :
132 : 1402 : RETURN(NULL);
133 : : }
134 : :
135 : : TermList *
136 : 17 : FlintAllTermsList::skip_to(const string &term)
137 : : {
138 : : LOGCALL(DB, TermList *, "FlintAllTermsList::skip_to", term);
139 : : Assert(!at_end());
140 : : // Set termfreq to 0 to indicate no termfreq/collfreq have been read for
141 : : // the current term.
142 : 17 : termfreq = 0;
143 : :
144 [ - + ]: 17 : if (rare(!cursor)) {
145 : 0 : cursor = database->postlist_table.cursor_get();
146 : : Assert(cursor); // The postlist table isn't optional.
147 : : }
148 : :
149 [ + + ]: 17 : if (cursor->find_entry_ge(F_pack_string_preserving_sort(term))) {
150 : : // The exact term we asked for is there, so just copy it rather than
151 : : // wasting effort unpacking it from the key.
152 : 11 : current_term = term;
153 : : } else {
154 [ + - ]: 6 : if (cursor->after_end()) {
155 : 6 : current_term.resize(0);
156 : 6 : RETURN(NULL);
157 : : }
158 : :
159 : 0 : const char *p = cursor->current_key.data();
160 : 0 : const char *pend = p + cursor->current_key.size();
161 [ # # ]: 0 : if (!F_unpack_string_preserving_sort(&p, pend, current_term)) {
162 : 0 : throw Xapian::DatabaseCorruptError("PostList table key has unexpected format");
163 : : }
164 : : }
165 : :
166 [ - + ]: 11 : if (!startswith(current_term, prefix)) {
167 : : // We've reached the end of the prefixed terms.
168 : 0 : cursor->to_end();
169 : 0 : current_term.resize(0);
170 : : }
171 : :
172 : 17 : RETURN(NULL);
173 : : }
174 : :
175 : : bool
176 : 1430 : FlintAllTermsList::at_end() const
177 : : {
178 : : LOGCALL(DB, bool, "FlintAllTermsList::at_end", NO_ARGS);
179 [ + - ][ + + ]: 1430 : RETURN(cursor && cursor->after_end());
180 : : }
|