bitcoinleveldb_table/builder_alt.rs
1crate::ix!();
2
3//-------------------------------------------[.cpp/bitcoin/src/leveldb/include/leveldb/table_builder.h]
4
5/**
6 | TableBuilder provides the interface used to
7 | build a Table (an immutable and sorted map from
8 | keys to values).
9 |
10 | Multiple threads can invoke const methods on
11 | a TableBuilder without external
12 | synchronization, but if any of the threads may
13 | call a non-const method, all threads accessing
14 | the same TableBuilder must use external
15 | synchronization.
16 */
17pub struct TableBuilder {
18 rep: *mut TableBuilderRep,
19}
20
21impl Drop for TableBuilder {
22
23 /**
24 | REQUIRES: Either Finish() or Abandon()
25 | has been called.
26 |
27 */
28 fn drop(&mut self) {
29 todo!();
30 /*
31 assert(rep_->closed); // Catch errors where caller forgot to call Finish()
32 delete rep_->filter_block;
33 delete rep_;
34 */
35 }
36}
37
38impl TableBuilder {
39
40 /**
41 | Create a builder that will store the contents
42 | of the table it is building in *file. Does
43 | not close the file. It is up to the caller
44 | to close the file after calling Finish().
45 */
46 pub fn new(
47 options: &Options,
48 file: *mut dyn WritableFile) -> Self {
49
50 todo!();
51 /*
52
53
54 : rep_(new Rep(options, file))
55
56 if (rep_->filter_block != nullptr) {
57 rep_->filter_block->StartBlock(0);
58 }
59 */
60 }
61
62 /**
63 | Change the options used by this builder.
64 | Note: only some of the option fields can be
65 | changed after construction. If a field is
66 | not allowed to change dynamically and its
67 | value in the structure passed to the
68 | constructor is different from its value in
69 | the structure passed to this method, this
70 | method will return an error without changing
71 | any fields.
72 */
73 pub fn change_options(&mut self, options: &Options) -> crate::Status {
74
75 todo!();
76 /*
77 // Note: if more fields are added to Options, update
78 // this function to catch changes that should not be allowed to
79 // change in the middle of building a Table.
80 if (options.comparator != rep_->options.comparator) {
81 return Status::InvalidArgument("changing comparator while building table");
82 }
83
84 // Note that any live BlockBuilders point to rep_->options and therefore
85 // will automatically pick up the updated options.
86 rep_->options = options;
87 rep_->index_block_options = options;
88 rep_->index_block_options.block_restart_interval = 1;
89 return Status::OK();
90 */
91 }
92
93 /**
94 | Add key,value to the table being constructed.
95 |
96 | REQUIRES: key is after any previously added
97 | key according to comparator.
98 |
99 | REQUIRES: Finish(), Abandon() have not been
100 | called
101 */
102 pub fn add(&mut self,
103 key_: &Slice,
104 value: &Slice) {
105
106 todo!();
107 /*
108 Rep* r = rep_;
109 assert(!r->closed);
110 if (!ok()) return;
111 if (r->num_entries > 0) {
112 assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0);
113 }
114
115 if (r->pending_index_entry) {
116 assert(r->data_block.empty());
117 r->options.comparator->FindShortestSeparator(&r->last_key, key);
118 std::string handle_encoding;
119 r->pending_handle.EncodeTo(&handle_encoding);
120 r->index_block.Add(r->last_key, Slice(handle_encoding));
121 r->pending_index_entry = false;
122 }
123
124 if (r->filter_block != nullptr) {
125 r->filter_block->AddKey(key);
126 }
127
128 r->last_key.assign(key.data(), key.size());
129 r->num_entries++;
130 r->data_block.Add(key, value);
131
132 const size_t estimated_block_size = r->data_block.CurrentSizeEstimate();
133 if (estimated_block_size >= r->options.block_size) {
134 Flush();
135 }
136 */
137 }
138
139 /**
140 | Advanced operation: flush any buffered
141 | key/value pairs to file.
142 |
143 | Can be used to ensure that two adjacent
144 | entries never live in the same data block.
145 | Most clients should not need to use this
146 | method.
147 |
148 | REQUIRES: Finish(), Abandon() have not been
149 | called
150 */
151 pub fn flush(&mut self) {
152
153 todo!();
154 /*
155 Rep* r = rep_;
156 assert(!r->closed);
157 if (!ok()) return;
158 if (r->data_block.empty()) return;
159 assert(!r->pending_index_entry);
160 WriteBlock(&r->data_block, &r->pending_handle);
161 if (ok()) {
162 r->pending_index_entry = true;
163 r->status = r->file->Flush();
164 }
165 if (r->filter_block != nullptr) {
166 r->filter_block->StartBlock(r->offset);
167 }
168 */
169 }
170
171 pub fn write_block(&mut self,
172 block: *mut BlockBuilder,
173 handle: *mut BlockHandle) {
174
175 todo!();
176 /*
177 // File format contains a sequence of blocks where each block has:
178 // block_data: uint8[n]
179 // type: uint8
180 // crc: uint32
181 assert(ok());
182 Rep* r = rep_;
183 Slice raw = block->Finish();
184
185 Slice block_contents;
186 CompressionType type = r->options.compression;
187 // TODO(postrelease): Support more compression options: zlib?
188 switch (type) {
189 case kNoCompression:
190 block_contents = raw;
191 break;
192
193 case kSnappyCompression: {
194 std::string* compressed = &r->compressed_output;
195 if (Snappy_Compress(raw.data(), raw.size(), compressed) &&
196 compressed->size() < raw.size() - (raw.size() / 8u)) {
197 block_contents = *compressed;
198 } else {
199 // Snappy not supported, or compressed less than 12.5%, so just
200 // store uncompressed form
201 block_contents = raw;
202 type = kNoCompression;
203 }
204 break;
205 }
206 }
207 WriteRawBlock(block_contents, type, handle);
208 r->compressed_output.clear();
209 block->Reset();
210 */
211 }
212
213 pub fn write_raw_block(&mut self,
214 block_contents: &Slice,
215 ty: CompressionType,
216 handle: *mut BlockHandle) {
217
218 todo!();
219 /*
220 Rep* r = rep_;
221 handle->set_offset(r->offset);
222 handle->set_size(block_contents.size());
223 r->status = r->file->Append(block_contents);
224 if (r->status.ok()) {
225 char trailer[kBlockTrailerSize];
226 trailer[0] = type;
227 uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size());
228 crc = crc32c::Extend(crc, trailer, 1); // Extend crc to cover block type
229 EncodeFixed32(trailer + 1, crc32c::Mask(crc));
230 r->status = r->file->Append(Slice(trailer, kBlockTrailerSize));
231 if (r->status.ok()) {
232 r->offset += block_contents.size() + kBlockTrailerSize;
233 }
234 }
235 */
236 }
237
238 /**
239 | Return non-ok iff some error has been
240 | detected.
241 |
242 */
243 pub fn status(&self) -> Status {
244
245 todo!();
246 /*
247 return rep_->status;
248 */
249 }
250
251 /**
252 | Finish building the table. Stops using the
253 | file passed to the constructor after this
254 | function returns.
255 |
256 | REQUIRES: Finish(), Abandon() have not been
257 | called
258 */
259 pub fn finish(&mut self) -> Status {
260
261 todo!();
262 /*
263 Rep* r = rep_;
264 Flush();
265 assert(!r->closed);
266 r->closed = true;
267
268 BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle;
269
270 // Write filter block
271 if (ok() && r->filter_block != nullptr) {
272 WriteRawBlock(r->filter_block->Finish(), kNoCompression,
273 &filter_block_handle);
274 }
275
276 // Write metaindex block
277 if (ok()) {
278 BlockBuilder meta_index_block(&r->options);
279 if (r->filter_block != nullptr) {
280 // Add mapping from "filter.Name" to location of filter data
281 std::string key = "filter.";
282 key.append(r->options.filter_policy->Name());
283 std::string handle_encoding;
284 filter_block_handle.EncodeTo(&handle_encoding);
285 meta_index_block.Add(key, handle_encoding);
286 }
287
288 // TODO(postrelease): Add stats and other meta blocks
289 WriteBlock(&meta_index_block, &metaindex_block_handle);
290 }
291
292 // Write index block
293 if (ok()) {
294 if (r->pending_index_entry) {
295 r->options.comparator->FindShortSuccessor(&r->last_key);
296 std::string handle_encoding;
297 r->pending_handle.EncodeTo(&handle_encoding);
298 r->index_block.Add(r->last_key, Slice(handle_encoding));
299 r->pending_index_entry = false;
300 }
301 WriteBlock(&r->index_block, &index_block_handle);
302 }
303
304 // Write footer
305 if (ok()) {
306 Footer footer;
307 footer.set_metaindex_handle(metaindex_block_handle);
308 footer.set_index_handle(index_block_handle);
309 std::string footer_encoding;
310 footer.EncodeTo(&footer_encoding);
311 r->status = r->file->Append(footer_encoding);
312 if (r->status.ok()) {
313 r->offset += footer_encoding.size();
314 }
315 }
316 return r->status;
317 */
318 }
319
320 /**
321 | Indicate that the contents of this builder
322 | should be abandoned. Stops using the file
323 | passed to the constructor after this function
324 | returns.
325 |
326 | If the caller is not going to call Finish(),
327 | it must call Abandon() before destroying this
328 | builder.
329 |
330 | REQUIRES: Finish(), Abandon() have not been
331 | called
332 */
333 pub fn abandon(&mut self) {
334
335 todo!();
336 /*
337 Rep* r = rep_;
338 assert(!r->closed);
339 r->closed = true;
340 */
341 }
342
343 /**
344 | Number of calls to Add() so far.
345 |
346 */
347 pub fn num_entries(&self) -> u64 {
348
349 todo!();
350 /*
351 return rep_->num_entries;
352 */
353 }
354
355 /**
356 | Size of the file generated so far. If
357 | invoked after a successful Finish()
358 | call, returns the size of the final generated
359 | file.
360 |
361 */
362 pub fn file_size(&self) -> u64 {
363
364 todo!();
365 /*
366 return rep_->offset;
367 */
368 }
369
370 pub fn ok(&self) -> bool {
371
372 todo!();
373 /*
374 return status().ok();
375 */
376 }
377}
378
379//-------------------------------------------[.cpp/bitcoin/src/leveldb/table/table_builder.cc]
380
381pub struct TableBuilderRep {
382 options: Options,
383 index_block_options: Options,
384 file: *mut dyn WritableFile,
385 offset: u64,
386 status: Status,
387 data_block: BlockBuilder,
388 index_block: BlockBuilder,
389 last_key_: String,
390 num_entries: i64,
391
392 /**
393 | Either Finish() or Abandon() has been
394 | called.
395 |
396 */
397 closed: bool,
398
399 filter_block: *mut FilterBlockBuilder,
400
401 /**
402 | We do not emit the index entry for a block
403 | until we have seen the first key for the next
404 | data block. This allows us to use shorter
405 | keys in the index block. For example,
406 | consider a block boundary between the keys
407 | "the quick brown fox" and "the who". We can
408 | use "the r" as the key for the index block
409 | entry since it is >= all entries in the first
410 | block and < all entries in subsequent blocks.
411 |
412 | Invariant: r->pending_index_entry is true
413 | only if data_block is empty.
414 */
415 pending_index_entry: bool,
416
417 /**
418 | Handle to add to index block
419 |
420 */
421 pending_handle: BlockHandle,
422
423 compressed_output: String,
424}
425
426impl TableBuilderRep {
427
428 pub fn new(
429 opt: &Options,
430 f: *mut dyn WritableFile) -> Self {
431
432 todo!();
433 /*
434
435
436 : options(opt),
437 index_block_options(opt),
438 file(f),
439 offset(0),
440 data_block(&options),
441 index_block(&index_block_options),
442 num_entries(0),
443 closed(false),
444 filter_block(opt.filter_policy == nullptr
445 ? nullptr
446 : new FilterBlockBuilder(opt.filter_policy)),
447 pending_index_entry(false)
448 index_block_options.block_restart_interval = 1;
449 */
450 }
451}