1 #ifndef XAPIAN_INCLUDED_HONEY_CURSOR_H
2 #define XAPIAN_INCLUDED_HONEY_CURSOR_H
4 #include "honey_table.h"
9 std::string current_key
, current_tag
;
10 mutable size_t val_size
= 0;
11 bool current_compressed
;
12 mutable CompressionStream comp_stream
;
13 bool is_at_end
= false;
14 bool is_after_end
= false;
15 mutable std::string last_key
;
18 explicit HoneyCursor(const HoneyTable
* table
)
19 : HoneyCursor(table
->fh
, table
->get_root())
24 HoneyCursor(const BufferedFile
& fh_
, off_t root_
)
26 comp_stream(Z_DEFAULT_STRATEGY
),
33 HoneyCursor(const HoneyCursor
& o
)
35 comp_stream(Z_DEFAULT_STRATEGY
),
43 last_key
= std::string();
44 is_at_end
= is_after_end
= false;
48 bool after_end() const { return is_after_end
; }
57 // Skip val data we've not looked at.
69 if (!last_key
.empty()) {
72 if (ch
== EOF
) throw Xapian::DatabaseError("EOF/error while reading key length", errno
);
76 if (!fh
.read(buf
, key_size
))
77 throw Xapian::DatabaseError("read of " + str(key_size
) + " bytes of key data failed", errno
);
78 current_key
.assign(last_key
, 0, reuse
);
79 current_key
.append(buf
, key_size
);
80 last_key
= current_key
;
84 description_append(esc
, current_key
);
85 std::cout
<< "K:" << esc
<< std::endl
;
90 // FIXME: rework to take advantage of buffering that's happening anyway?
92 for (int i
= 0; i
< 8; ++i
) {
103 const char* end
= p
+ r
;
104 if (!unpack_uint(&p
, end
, &val_size
)) {
105 throw Xapian::DatabaseError("val_size unpack_uint invalid");
107 if (p
!= end
) std::abort();
108 current_compressed
= val_size
& 1;
111 // FIXME: Always resize to 0? Not doing so avoids always having to
112 // clear all the data before reading it.
113 if (true && val_size
== 0)
114 current_tag
.resize(0);
120 bool read_tag(bool keep_compressed
= false) {
122 current_tag
.resize(val_size
);
123 if (!fh
.read(&(current_tag
[0]), val_size
))
124 throw Xapian::DatabaseError("read of " + str(val_size
) + " bytes of value data failed", errno
);
126 std::cerr
<< "read " << val_size
<< " bytes of value data ending @" << fh
.get_pos() << std::endl
;
131 description_append(esc
, current_tag
);
132 std::cout
<< "V:" << esc
<< std::endl
;
135 if (!keep_compressed
&& current_compressed
) {
136 // Need to decompress.
137 comp_stream
.decompress_start();
139 if (!comp_stream
.decompress_chunk(current_tag
.data(), current_tag
.size(), new_tag
)) {
140 // Decompression didn't complete.
143 swap(current_tag
, new_tag
);
144 current_compressed
= false;
146 std::cerr
<< "decompressed to " << current_tag
.size() << " bytes of value data" << std::endl
;
149 return current_compressed
;
152 bool find_exact(const std::string
& key
) {
153 // std::cerr << "EQ" << std::endl;
155 int cmp0
= current_key
.compare(key
);
156 if (cmp0
== 0) return true;
162 int cmp
= current_key
.compare(key
);
163 if (cmp
== 0) return true;
169 bool find_entry_ge(const std::string
& key
) {
170 // std::cerr << "GE" << std::endl;
172 int cmp0
= current_key
.compare(key
);
173 if (cmp0
== 0) return true;
179 int cmp
= current_key
.compare(key
);
180 if (cmp
== 0) return true;
186 bool find_entry(const std::string
& key
) {
189 description_append(desc
, key
);
190 std::cerr
<< "find_entry(" << desc
<< ") [LE]" << std::endl
;
192 int cmp0
= current_key
.compare(key
);
194 if (DEBUGGING
) std::cerr
<< " already on it" << std::endl
;
202 // FIXME: If "close" just seek forwards? Or consider seeking from current index pos?
203 //off_t pos = fh.get_pos();
205 std::string index_key
, prev_index_key
;
206 std::make_unsigned
<off_t
>::type ptr
= 0;
208 int reuse
= fh
.read();
209 if (reuse
== -1) break;
211 if (len
== -1) std::abort(); // FIXME
212 prev_index_key
= index_key
;
213 index_key
.resize(reuse
+ len
);
214 fh
.read(&index_key
[reuse
], len
);
218 description_append(desc
, index_key
);
219 std::cerr
<< "Index key: " << desc
<< std::endl
;
222 cmp0
= index_key
.compare(key
);
224 last_key
= ptr
? index_key
: std::string(); // for now (a lie, but the reuse part is correct).
230 if ((b
& 0x80) == 0) break;
233 if (!unpack_uint(&p
, e
, &ptr
) || p
!= e
) std::abort(); // FIXME
234 if (DEBUGGING
) std::cerr
<< " -> " << ptr
<< std::endl
;
236 if (DEBUGGING
) std::cerr
<< " hit straight from index" << std::endl
;
238 current_key
= index_key
;
241 // FIXME: rework to take advantage of buffering that's happening anyway?
243 for (int i
= 0; i
< 8; ++i
) {
249 if (ch2
< 128) break;
254 const char* end
= p
+ r
;
255 if (!unpack_uint(&p
, end
, &val_size
)) {
256 throw Xapian::DatabaseError("val_size unpack_uint invalid");
258 bool& compressed
= current_compressed
;
259 compressed
= val_size
& 1;
261 if (p
!= end
) std::abort();
265 if (DEBUGGING
) std::cerr
<< " cmp0 = " << cmp0
<< ", going to " << ptr
<< std::endl
;
268 // FIXME: crude for now
270 current_key
= prev_index_key
;
274 // FIXME: rework to take advantage of buffering that's happening anyway?
276 for (int i
= 0; i
< 8; ++i
) {
282 if (ch2
< 128) break;
287 const char* end
= p
+ r
;
288 if (!unpack_uint(&p
, end
, &val_size
)) {
289 throw Xapian::DatabaseError("val_size unpack_uint invalid");
291 bool& compressed
= current_compressed
;
292 auto& val
= current_tag
;
293 compressed
= val_size
& 1;
296 if (p
!= end
) std::abort();
297 val_size
-= (end
- p
);
299 size_t n
= std::min(val_size
, sizeof(buf
));
300 if (!fh
.read(buf
, n
))
301 throw Xapian::DatabaseError("read of " + str(n
) + "/" + str(val_size
) + " bytes of value data failed", errno
);
313 description_append(desc
, current_key
);
314 std::cerr
<< "Dropped to data layer on key: " << desc
<< std::endl
;
317 // FIXME: need to put us in the "read key not tag" state but persist that more?
318 // if (cmp0 == 0) this is an exact hit from the index...
329 compressed
= current_compressed
;
333 description_append(desc
, current_key
);
334 std::cerr
<< "@ " << pos
<< " key: " << desc
<< std::endl
;
339 int cmp
= current_key
.compare(key
);
341 if (DEBUGGING
) std::cerr
<< " found it" << std::endl
;
349 description_append(desc
, current_key
);
350 std::cerr
<< " NOT found - reached " << desc
<< std::endl
;
352 // No match so back up to previous entry.
353 is_at_end
= is_after_end
= false;
354 last_key
= current_key
= k
;
356 current_compressed
= compressed
;
360 description_append(desc
, current_key
);
361 std::cerr
<< " NOT found - leaving us on " << desc
<< std::endl
;
366 void find_entry_lt(const std::string
& key
) {
367 // std::cerr << "LT" << std::endl;
369 if (key
< current_key
) {
371 current_key
.resize(0);
382 compressed
= current_compressed
;
383 } while (next() && current_key
< key
);
385 // Back up to previous entry.
386 is_at_end
= is_after_end
= false;
387 last_key
= current_key
= k
;
389 current_compressed
= compressed
;
393 HoneyCursor
* clone() const {
394 return new HoneyCursor(*this);
397 bool del() { return false; }
400 class MutableHoneyCursor
: public HoneyCursor
{
402 MutableHoneyCursor(HoneyTable
* table_
)
403 : HoneyCursor(table_
->fh
, table_
->get_root()) { }
406 #endif // XAPIAN_INCLUDED_HONEY_CURSOR_H