Branch data Line data Source code
1 : : /* flint_termlist.cc: Termlists in a flint database
2 : : *
3 : : * Copyright 1999,2000,2001 BrightStation PLC
4 : : * Copyright 2002 Ananova Ltd
5 : : * Copyright 2002,2003,2004,2006,2007,2008,2010 Olly Betts
6 : : *
7 : : * This program is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU General Public License as
9 : : * published by the Free Software Foundation; either version 2 of the
10 : : * License, or (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, write to the Free Software
19 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 : : * USA
21 : : */
22 : :
23 : : #include <config.h>
24 : : #include "flint_termlist.h"
25 : :
26 : : #include "xapian/error.h"
27 : :
28 : : #include "expandweight.h"
29 : : #include "flint_positionlist.h"
30 : : #include "flint_utils.h"
31 : : #include "debuglog.h"
32 : : #include "omassert.h"
33 : : #include "str.h"
34 : :
35 : : using namespace std;
36 : :
37 : 53695 : FlintTermList::FlintTermList(Xapian::Internal::RefCntPtr<const FlintDatabase> db_,
38 : : Xapian::docid did_)
39 : 53695 : : db(db_), did(did_), current_wdf(0), current_termfreq(0)
40 : : {
41 : : LOGCALL_CTOR(DB, "FlintTermList", db_ | did_);
42 : :
43 [ + + ][ # # ]: 53698 : if (!db->termlist_table.get_exact_entry(flint_docid_to_key(did), data))
44 : 3023 : throw Xapian::DocNotFoundError("No termlist for document " + str(did));
45 : :
46 : 50669 : pos = data.data();
47 : 50669 : end = pos + data.size();
48 : :
49 [ + + # # ]: 50669 : if (pos == end) {
50 : 9057 : doclen = 0;
51 : 9057 : termlist_size = 0;
52 : 9057 : return;
53 : : }
54 : :
55 : : // Read doclen
56 [ - + ][ # # ]: 41612 : if (!F_unpack_uint(&pos, end, &doclen)) {
57 : : const char *msg;
58 [ # # ][ # # ]: 0 : if (pos == 0) {
59 : 0 : msg = "Too little data for doclen in termlist";
60 : : } else {
61 : 0 : msg = "Overflowed value for doclen in termlist";
62 : : }
63 : 0 : throw Xapian::DatabaseCorruptError(msg);
64 : : }
65 : :
66 : : // Read termlist_size
67 [ - + ][ # # ]: 41612 : if (!F_unpack_uint(&pos, end, &termlist_size)) {
68 : : const char *msg;
69 [ # # ][ # # ]: 0 : if (pos == 0) {
70 : 0 : msg = "Too little data for list size in termlist";
71 : : } else {
72 : 0 : msg = "Overflowed value for list size in termlist";
73 : : }
74 : 0 : throw Xapian::DatabaseCorruptError(msg);
75 : : }
76 : :
77 : : // See comment in FlintTermListTable::set_termlist() in
78 : : // flint_termlisttable.cc for an explanation of this!
79 [ + - ][ + + ]: 41612 : if (pos != end && *pos == '0') ++pos;
[ # # ][ # # ]
80 : 62773 : }
81 : :
82 : : flint_doclen_t
83 : 19082 : FlintTermList::get_doclength() const
84 : : {
85 : : LOGCALL(DB, flint_doclen_t, "FlintTermList::get_doclength", NO_ARGS);
86 : 19082 : RETURN(doclen);
87 : : }
88 : :
89 : : Xapian::termcount
90 : 46 : FlintTermList::get_approx_size() const
91 : : {
92 : : LOGCALL(DB, Xapian::termcount, "FlintTermList::get_approx_size", NO_ARGS);
93 : 46 : RETURN(termlist_size);
94 : : }
95 : :
96 : : void
97 : 1441 : FlintTermList::accumulate_stats(Xapian::Internal::ExpandStats & stats) const
98 : : {
99 : : LOGCALL_VOID(DB, "FlintTermList::accumulate_stats", stats);
100 : : Assert(!at_end());
101 : 1441 : stats.accumulate(current_wdf, doclen, get_termfreq(), db->get_doccount());
102 : 1441 : }
103 : :
104 : : string
105 : 108248 : FlintTermList::get_termname() const
106 : : {
107 : : LOGCALL(DB, string, "FlintTermList::get_termname", NO_ARGS);
108 : 108248 : RETURN(current_term);
109 : : }
110 : :
111 : : Xapian::termcount
112 : 82092 : FlintTermList::get_wdf() const
113 : : {
114 : : LOGCALL(DB, Xapian::termcount, "FlintTermList::get_wdf", NO_ARGS);
115 : 82092 : RETURN(current_wdf);
116 : : }
117 : :
118 : : Xapian::doccount
119 : 26955 : FlintTermList::get_termfreq() const
120 : : {
121 : : LOGCALL(DB, Xapian::doccount, "FlintTermList::get_termfreq", NO_ARGS);
122 [ + + ]: 26955 : if (current_termfreq == 0)
123 : 26953 : current_termfreq = db->get_termfreq(current_term);
124 : 26955 : RETURN(current_termfreq);
125 : : }
126 : :
127 : : TermList *
128 : 113133 : FlintTermList::next()
129 : : {
130 : : LOGCALL(DB, TermList *, "FlintTermList::next", NO_ARGS);
131 : : Assert(!at_end());
132 [ + + ]: 113133 : if (pos == end) {
133 : 50644 : pos = NULL;
134 : 50644 : RETURN(NULL);
135 : : }
136 : :
137 : : // Reset to 0 to indicate that the termfreq needs to be read.
138 : 62489 : current_termfreq = 0;
139 : :
140 : 62489 : bool wdf_in_reuse = false;
141 [ + + ]: 62489 : if (!current_term.empty()) {
142 : : // Find out how much of the previous term to reuse.
143 : 20877 : size_t len = static_cast<unsigned char>(*pos++);
144 [ + + ]: 20877 : if (len > current_term.size()) {
145 : : // The wdf is also stored in the "reuse" byte.
146 : 20865 : wdf_in_reuse = true;
147 : 20865 : size_t divisor = current_term.size() + 1;
148 : 20865 : current_wdf = len / divisor - 1;
149 : 20865 : len %= divisor;
150 : : }
151 : 20877 : current_term.resize(len);
152 : : }
153 : :
154 : : // Append the new tail to form the next term.
155 : 62489 : size_t append_len = static_cast<unsigned char>(*pos++);
156 : 62489 : current_term.append(pos, append_len);
157 : 62489 : pos += append_len;
158 : :
159 : : // Read the wdf if it wasn't packed into the reuse byte.
160 [ + + - + ]: 62489 : if (!wdf_in_reuse && !F_unpack_uint(&pos, end, ¤t_wdf)) {
[ - + ]
161 : : const char *msg;
162 [ # # ]: 0 : if (pos == 0) {
163 : 0 : msg = "Too little data for wdf in termlist";
164 : : } else {
165 : 0 : msg = "Overflowed value for wdf in termlist";
166 : : }
167 : 0 : throw Xapian::DatabaseCorruptError(msg);
168 : : }
169 : :
170 : 113133 : RETURN(NULL);
171 : : }
172 : :
173 : : TermList *
174 : 56 : FlintTermList::skip_to(const string & term)
175 : : {
176 : : LOGCALL(API, TermList *, "FlintTermList::skip_to", term);
177 [ + + ][ + + ]: 598 : while (pos != NULL && current_term < term) {
[ + + ]
178 : 542 : (void)FlintTermList::next();
179 : : }
180 : 56 : RETURN(NULL);
181 : : }
182 : :
183 : : bool
184 : 113397 : FlintTermList::at_end() const
185 : : {
186 : : LOGCALL(DB, bool, "FlintTermList::at_end", NO_ARGS);
187 : 113397 : RETURN(pos == NULL);
188 : : }
189 : :
190 : : Xapian::termcount
191 : 11239 : FlintTermList::positionlist_count() const
192 : : {
193 : : LOGCALL(DB, Xapian::termcount, "FlintTermList::positionlist_count", NO_ARGS);
194 : 11239 : RETURN(db->position_table.positionlist_count(did, current_term));
195 : : }
196 : :
197 : : Xapian::PositionIterator
198 : 33842 : FlintTermList::positionlist_begin() const
199 : : {
200 : : LOGCALL(DB, Xapian::PositionIterator, "FlintTermList::positionlist_begin", NO_ARGS);
201 : : return Xapian::PositionIterator(
202 : 33842 : new FlintPositionList(&db->position_table, did, current_term));
203 : : }
|