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}