bitcoinleveldb_table/table.rs
1crate::ix!();
2
3//-------------------------------------------[.cpp/bitcoin/src/leveldb/include/leveldb/table.h]
4
5/**
6 | A Table is a sorted map from strings to
7 | strings. Tables are immutable and persistent.
8 | A Table may be safely accessed from multiple
9 | threads without external synchronization.
10 */
11pub struct Table {
12 rep: *const TableRep,
13}
14
15impl Table {
16
17 pub fn new(rep: *mut TableRep) -> Self {
18
19 todo!();
20 /*
21 : rep(rep),
22 */
23 }
24
25 /**
26 | Attempt to open the table that is stored in
27 | bytes [0..file_size) of "file", and read the
28 | metadata entries necessary to allow
29 | retrieving data from the table.
30 |
31 | If successful, returns ok and sets "*table"
32 | to the newly opened table. The client should
33 | delete "*table" when no longer needed. If
34 | there was an error while initializing the
35 | table, sets "*table" to nullptr and returns
36 | a non-ok status. Does not take ownership of
37 | "*source", but the client must ensure that
38 | "source" remains live for the duration of the
39 | returned table's lifetime.
40 |
41 | *file must remain live while this Table is in
42 | use.
43 */
44 pub fn open(&mut self,
45 options: &Options,
46 file: Rc<RefCell<dyn RandomAccessFile>>,
47 size: u64,
48 table: *mut *mut Table) -> Status {
49
50 todo!();
51 /*
52 *table = nullptr;
53 if (size < Footer::kEncodedLength) {
54 return Status::Corruption("file is too short to be an sstable");
55 }
56
57 char footer_space[Footer::kEncodedLength];
58 Slice footer_input;
59 Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,
60 &footer_input, footer_space);
61 if (!s.ok()) return s;
62
63 Footer footer;
64 s = footer.DecodeFrom(&footer_input);
65 if (!s.ok()) return s;
66
67 // Read the index block
68 BlockContents index_block_contents;
69 if (s.ok()) {
70 ReadOptions opt;
71 if (options.paranoid_checks) {
72 opt.verify_checksums = true;
73 }
74 s = ReadBlock(file, opt, footer.index_handle(), &index_block_contents);
75 }
76
77 if (s.ok()) {
78 // We've successfully read the footer and the index block: we're
79 // ready to serve requests.
80 Block* index_block = new Block(index_block_contents);
81 Rep* rep = new Table::Rep;
82 rep->options = options;
83 rep->file = file;
84 rep->metaindex_handle = footer.metaindex_handle();
85 rep->index_block = index_block;
86 rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);
87 rep->filter_data = nullptr;
88 rep->filter = nullptr;
89 *table = new Table(rep);
90 (*table)->ReadMeta(footer);
91 }
92
93 return s;
94 */
95 }
96
97 pub fn read_meta(&mut self, footer: &Footer) {
98
99 todo!();
100 /*
101 if (rep_->options.filter_policy == nullptr) {
102 return; // Do not need any metadata
103 }
104
105 // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates
106 // it is an empty block.
107 ReadOptions opt;
108 if (rep_->options.paranoid_checks) {
109 opt.verify_checksums = true;
110 }
111 BlockContents contents;
112 if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {
113 // Do not propagate errors since meta info is not needed for operation
114 return;
115 }
116 Block* meta = new Block(contents);
117
118 Iterator* iter = meta->NewIterator(BytewiseComparator());
119 std::string key = "filter.";
120 key.append(rep_->options.filter_policy->Name());
121 iter->Seek(key);
122 if (iter->Valid() && iter->key() == Slice(key)) {
123 ReadFilter(iter->value());
124 }
125 delete iter;
126 delete meta;
127 */
128 }
129
130 pub fn read_filter(&mut self, filter_handle_value: &Slice) {
131
132 todo!();
133 /*
134 Slice v = filter_handle_value;
135 BlockHandle filter_handle;
136 if (!filter_handle.DecodeFrom(&v).ok()) {
137 return;
138 }
139
140 // We might want to unify with ReadBlock() if we start
141 // requiring checksum verification in Table::Open.
142 ReadOptions opt;
143 if (rep_->options.paranoid_checks) {
144 opt.verify_checksums = true;
145 }
146 BlockContents block;
147 if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {
148 return;
149 }
150 if (block.heap_allocated) {
151 rep_->filter_data = block.data.data(); // Will need to delete later
152 }
153 rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data);
154 */
155 }
156
157 /**
158 | Convert an index iterator value (i.e.,
159 | an encoded BlockHandle) into an iterator
160 | over the contents of the corresponding
161 | block.
162 |
163 */
164 pub fn block_reader(&mut self,
165 arg: *mut c_void,
166 options: &ReadOptions,
167 index_value: &Slice) -> *mut LevelDBIterator {
168
169 todo!();
170 /*
171 Table* table = reinterpret_cast<Table*>(arg);
172 Cache* block_cache = table->rep_->options.block_cache;
173 Block* block = nullptr;
174 Cache::Handle* cache_handle = nullptr;
175
176 BlockHandle handle;
177 Slice input = index_value;
178 Status s = handle.DecodeFrom(&input);
179 // We intentionally allow extra stuff in index_value so that we
180 // can add more features in the future.
181
182 if (s.ok()) {
183 BlockContents contents;
184 if (block_cache != nullptr) {
185 char cache_key_buffer[16];
186 EncodeFixed64(cache_key_buffer, table->rep_->cache_id);
187 EncodeFixed64(cache_key_buffer + 8, handle.offset());
188 Slice key(cache_key_buffer, sizeof(cache_key_buffer));
189 cache_handle = block_cache->Lookup(key);
190 if (cache_handle != nullptr) {
191 block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));
192 } else {
193 s = ReadBlock(table->rep_->file, options, handle, &contents);
194 if (s.ok()) {
195 block = new Block(contents);
196 if (contents.cachable && options.fill_cache) {
197 cache_handle = block_cache->Insert(key, block, block->size(),
198 &DeleteCachedBlock);
199 }
200 }
201 }
202 } else {
203 s = ReadBlock(table->rep_->file, options, handle, &contents);
204 if (s.ok()) {
205 block = new Block(contents);
206 }
207 }
208 }
209
210 Iterator* iter;
211 if (block != nullptr) {
212 iter = block->NewIterator(table->rep_->options.comparator);
213 if (cache_handle == nullptr) {
214 iter->RegisterCleanup(&DeleteBlock, block, nullptr);
215 } else {
216 iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);
217 }
218 } else {
219 iter = NewErrorIterator(s);
220 }
221 return iter;
222 */
223 }
224
225 /**
226 | Returns a new iterator over the table
227 | contents.
228 |
229 | The result of NewIterator() is initially
230 | invalid (caller must call one of the Seek
231 | methods on the iterator before using it).
232 */
233 pub fn new_iterator(&self, options: &ReadOptions) -> *mut LevelDBIterator {
234
235 todo!();
236 /*
237 return NewTwoLevelIterator(
238 rep_->index_block->NewIterator(rep_->options.comparator),
239 &Table::BlockReader, const_cast<Table*>(this), options);
240 */
241 }
242
243 /**
244 | Calls (*handle_result)(arg, ...) with the
245 | entry found after a call to Seek(key). May
246 | not make such a call if filter policy says
247 | that key is not present.
248 */
249 pub fn internal_get(&mut self,
250 options: &ReadOptions,
251 k: &Slice,
252 arg: *mut c_void,
253 handle_result: fn(
254 _0: *mut c_void,
255 _1: &Slice,
256 _2: &Slice
257 ) -> c_void) -> Status {
258
259 todo!();
260 /*
261 Status s;
262 Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator);
263 iiter->Seek(k);
264 if (iiter->Valid()) {
265 Slice handle_value = iiter->value();
266 FilterBlockReader* filter = rep_->filter;
267 BlockHandle handle;
268 if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() &&
269 !filter->KeyMayMatch(handle.offset(), k)) {
270 // Not found
271 } else {
272 Iterator* block_iter = BlockReader(this, options, iiter->value());
273 block_iter->Seek(k);
274 if (block_iter->Valid()) {
275 (*handle_result)(arg, block_iter->key(), block_iter->value());
276 }
277 s = block_iter->status();
278 delete block_iter;
279 }
280 }
281 if (s.ok()) {
282 s = iiter->status();
283 }
284 delete iiter;
285 return s;
286 */
287 }
288
289 /**
290 | Given a key, return an approximate byte
291 | offset in the file where the data for that
292 | key begins (or would begin if the key were
293 | present in the file). The returned value is
294 | in terms of file bytes, and so includes
295 | effects like compression of the underlying
296 | data.
297 |
298 | E.g., the approximate offset of the last key
299 | in the table will be close to the file
300 | length.
301 */
302 pub fn approximate_offset_of(&self, key_: &Slice) -> u64 {
303
304 todo!();
305 /*
306 Iterator* index_iter =
307 rep_->index_block->NewIterator(rep_->options.comparator);
308 index_iter->Seek(key);
309 uint64_t result;
310 if (index_iter->Valid()) {
311 BlockHandle handle;
312 Slice input = index_iter->value();
313 Status s = handle.DecodeFrom(&input);
314 if (s.ok()) {
315 result = handle.offset();
316 } else {
317 // Strange: we can't decode the block handle in the index block.
318 // We'll just return the offset of the metaindex block, which is
319 // close to the whole file size for this case.
320 result = rep_->metaindex_handle.offset();
321 }
322 } else {
323 // key is past the last key in the file. Approximate the offset
324 // by returning the offset of the metaindex block (which is
325 // right near the end of the file).
326 result = rep_->metaindex_handle.offset();
327 }
328 delete index_iter;
329 return result;
330 */
331 }
332}
333
334//-------------------------------------------[.cpp/bitcoin/src/leveldb/table/table.cc]
335
336pub struct TableRep {
337
338 options: Options,
339 status: Status,
340 file: Rc<RefCell<dyn RandomAccessFile>>,
341 cache_id: u64,
342 filter: *mut FilterBlockReader,
343 filter_data: *const u8,
344
345 /**
346 | Handle to metaindex_block: saved from
347 | footer
348 |
349 */
350 metaindex_handle: BlockHandle,
351
352 index_block: *mut Block,
353}
354
355impl Drop for TableRep {
356 fn drop(&mut self) {
357 todo!();
358 /*
359 delete filter;
360 delete[] filter_data;
361 delete index_block;
362 */
363 }
364}
365
366impl Drop for Table {
367 fn drop(&mut self) {
368 todo!();
369 /*
370 delete rep_;
371 */
372 }
373}
374
375pub fn delete_block(
376 arg: *mut c_void,
377 ignored: *mut c_void) {
378
379 todo!();
380 /*
381 delete reinterpret_cast<Block*>(arg);
382 */
383}
384
385pub fn delete_cached_block(
386 key_: &Slice,
387 value: *mut c_void) {
388
389 todo!();
390 /*
391 Block* block = reinterpret_cast<Block*>(value);
392 delete block;
393 */
394}
395
396pub fn release_block(
397 arg: *mut c_void,
398 h: *mut c_void) {
399
400 todo!();
401 /*
402 Cache* cache = reinterpret_cast<Cache*>(arg);
403 Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);
404 cache->Release(handle);
405 */
406}