4 #include "honey_table.h"
6 #include "honey_cursor.h"
12 size_t HoneyTable::total_index_size
= 0;
15 HoneyTable::create_and_open(int flags_
, const RootInfo
& root_info
)
18 compress_min
= root_info
.get_compress_min();
20 num_entries
= root_info
.get_num_entries();
21 root
= root_info
.get_root();
24 if (!fh
.open(path
, read_only
))
25 throw Xapian::DatabaseOpeningError("Failed to open HoneyTable", errno
);
29 HoneyTable::open(int flags_
, const RootInfo
& root_info
, honey_revision_number_t
)
32 compress_min
= root_info
.get_compress_min();
33 num_entries
= root_info
.get_num_entries();
34 root
= root_info
.get_root();
35 if (!fh
.open(path
, read_only
)) {
37 throw Xapian::DatabaseOpeningError("Failed to open HoneyTable", errno
);
42 HoneyTable::add(const std::string
& key
,
47 if (!compressed
&& compress_min
> 0 && val_size
> compress_min
) {
48 size_t compressed_size
= val_size
;
49 CompressionStream comp_stream
; // FIXME: reuse
50 const char* p
= comp_stream
.compress(val
, &compressed_size
);
52 add(key
, p
, compressed_size
, true);
58 throw Xapian::InvalidOperationError("add() on read-only HoneyTable");
59 if (key
.size() == 0 || key
.size() > 255)
60 throw Xapian::InvalidArgumentError("Invalid key size: " + str(key
.size()));
62 throw Xapian::InvalidOperationError("New key <= previous key");
63 if (!last_key
.empty()) {
64 size_t len
= std::min(last_key
.size(), key
.size());
66 for (i
= 0; i
< len
; ++i
) {
67 if (last_key
[i
] != key
[i
]) break;
69 fh
.write(static_cast<unsigned char>(i
));
70 fh
.write(static_cast<unsigned char>(key
.size() - i
));
71 fh
.write(key
.data() + i
, key
.size() - i
);
73 fh
.write(static_cast<unsigned char>(key
.size()));
74 fh
.write(key
.data(), key
.size());
77 index
.maybe_add_entry(key
, fh
.get_pos());
79 // Encode "compressed?" flag in bottom bit.
80 // FIXME: Don't do this if a table is uncompressed? That saves a byte
81 // for each item where the extra bit pushes the length up by a byte.
82 size_t val_size_enc
= (val_size
<< 1) | compressed
;
84 pack_uint(val_len
, val_size_enc
);
85 // FIXME: pass together so we can potentially writev() both?
86 fh
.write(val_len
.data(), val_len
.size());
87 fh
.write(val
, val_size
);
92 HoneyTable::commit(honey_revision_number_t
, RootInfo
* root_info
)
95 throw Xapian::InvalidOperationError("root not set");
97 root_info
->set_level(1); // FIXME: number of index levels
98 root_info
->set_num_entries(num_entries
);
99 root_info
->set_root_is_fake(false);
100 // Not really meaningful.
101 root_info
->set_sequential(true);
102 root_info
->set_root(root
);
103 // Not really meaningful.
104 root_info
->set_blocksize(2048);
105 // Not really meaningful.
106 //root_info->set_free_list(std::string());
114 HoneyTable::read_item(std::string
& key
, std::string
& val
, bool& compressed
) const
121 if (ch
== EOF
) return false;
124 if (!last_key
.empty()) {
127 if (ch
== EOF
) throw Xapian::DatabaseError("EOF/error while reading key length", errno
);
129 size_t key_size
= ch
;
131 if (!fh
.read(buf
, key_size
))
132 throw Xapian::DatabaseError("read of " + str(key_size
) + " bytes of key data failed", errno
);
133 key
.assign(last_key
, 0, reuse
);
134 key
.append(buf
, key_size
);
139 description_append(esc
, key
);
140 std::cout
<< "K:" << esc
<< std::endl
;
145 // FIXME: rework to take advantage of buffering that's happening anyway?
147 for (int i
= 0; i
< 8; ++i
) {
153 if (ch2
< 128) break;
158 const char* end
= p
+ r
;
160 if (!unpack_uint(&p
, end
, &val_size
)) {
161 throw Xapian::DatabaseError("val_size unpack_uint invalid");
163 compressed
= val_size
& 1;
166 if (p
!= end
) std::abort();
167 val_size
-= (end
- p
);
169 size_t n
= min(val_size
, sizeof(buf
));
170 if (!fh
.read(buf
, n
))
171 throw Xapian::DatabaseError("read of " + str(n
) + "/" + str(val_size
) + " bytes of value data failed", errno
);
178 description_append(esc
, val
);
179 std::cout
<< "V:" << esc
<< std::endl
;
186 HoneyTable::get_exact_entry(const std::string
& key
, std::string
& tag
) const
188 if (!read_only
) std::abort();
189 if (!fh
.is_open()) return false;
191 last_key
= std::string();
196 if (!read_item(k
, v
, compressed
)) return false;
197 cmp
= k
.compare(key
);
199 if (cmp
> 0) return false;
201 CompressionStream comp_stream
;
202 comp_stream
.decompress_start();
203 if (!comp_stream
.decompress_chunk(v
.data(), v
.size(), tag
)) {
204 // Decompression didn't complete.
214 HoneyTable::key_exists(const std::string
& key
) const
216 if (!read_only
) std::abort();
217 if (!fh
.is_open()) return false;
219 last_key
= std::string();
224 // FIXME: avoid reading tag data?
225 if (!read_item(k
, v
, compressed
)) return false;
226 cmp
= k
.compare(key
);
232 HoneyTable::cursor_get() const
234 return new HoneyCursor(fh
, root
);