LCOV - code coverage report
Current view: top level - src/leveldb/table - table_builder.cc (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 128 158 81.0 %
Date: 2022-04-21 14:51:19 Functions: 11 13 84.6 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 27 52 51.9 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
#       2                 :            : // Use of this source code is governed by a BSD-style license that can be
#       3                 :            : // found in the LICENSE file. See the AUTHORS file for names of contributors.
#       4                 :            : 
#       5                 :            : #include "leveldb/table_builder.h"
#       6                 :            : 
#       7                 :            : #include <assert.h>
#       8                 :            : 
#       9                 :            : #include "leveldb/comparator.h"
#      10                 :            : #include "leveldb/env.h"
#      11                 :            : #include "leveldb/filter_policy.h"
#      12                 :            : #include "leveldb/options.h"
#      13                 :            : #include "table/block_builder.h"
#      14                 :            : #include "table/filter_block.h"
#      15                 :            : #include "table/format.h"
#      16                 :            : #include "util/coding.h"
#      17                 :            : #include "util/crc32c.h"
#      18                 :            : 
#      19                 :            : namespace leveldb {
#      20                 :            : 
#      21                 :            : struct TableBuilder::Rep {
#      22                 :            :   Rep(const Options& opt, WritableFile* f)
#      23                 :            :       : options(opt),
#      24                 :            :         index_block_options(opt),
#      25                 :            :         file(f),
#      26                 :            :         offset(0),
#      27                 :            :         data_block(&options),
#      28                 :            :         index_block(&index_block_options),
#      29                 :            :         num_entries(0),
#      30                 :            :         closed(false),
#      31                 :            :         filter_block(opt.filter_policy == nullptr
#      32                 :            :                          ? nullptr
#      33                 :            :                          : new FilterBlockBuilder(opt.filter_policy)),
#      34                 :       1077 :         pending_index_entry(false) {
#      35                 :       1077 :     index_block_options.block_restart_interval = 1;
#      36                 :       1077 :   }
#      37                 :            : 
#      38                 :            :   Options options;
#      39                 :            :   Options index_block_options;
#      40                 :            :   WritableFile* file;
#      41                 :            :   uint64_t offset;
#      42                 :            :   Status status;
#      43                 :            :   BlockBuilder data_block;
#      44                 :            :   BlockBuilder index_block;
#      45                 :            :   std::string last_key;
#      46                 :            :   int64_t num_entries;
#      47                 :            :   bool closed;  // Either Finish() or Abandon() has been called.
#      48                 :            :   FilterBlockBuilder* filter_block;
#      49                 :            : 
#      50                 :            :   // We do not emit the index entry for a block until we have seen the
#      51                 :            :   // first key for the next data block.  This allows us to use shorter
#      52                 :            :   // keys in the index block.  For example, consider a block boundary
#      53                 :            :   // between the keys "the quick brown fox" and "the who".  We can use
#      54                 :            :   // "the r" as the key for the index block entry since it is >= all
#      55                 :            :   // entries in the first block and < all entries in subsequent
#      56                 :            :   // blocks.
#      57                 :            :   //
#      58                 :            :   // Invariant: r->pending_index_entry is true only if data_block is empty.
#      59                 :            :   bool pending_index_entry;
#      60                 :            :   BlockHandle pending_handle;  // Handle to add to index block
#      61                 :            : 
#      62                 :            :   std::string compressed_output;
#      63                 :            : };
#      64                 :            : 
#      65                 :            : TableBuilder::TableBuilder(const Options& options, WritableFile* file)
#      66                 :       1077 :     : rep_(new Rep(options, file)) {
#      67         [ +  - ]:       1077 :   if (rep_->filter_block != nullptr) {
#      68                 :       1077 :     rep_->filter_block->StartBlock(0);
#      69                 :       1077 :   }
#      70                 :       1077 : }
#      71                 :            : 
#      72                 :       1077 : TableBuilder::~TableBuilder() {
#      73                 :       1077 :   assert(rep_->closed);  // Catch errors where caller forgot to call Finish()
#      74                 :          0 :   delete rep_->filter_block;
#      75                 :       1077 :   delete rep_;
#      76                 :       1077 : }
#      77                 :            : 
#      78                 :          0 : Status TableBuilder::ChangeOptions(const Options& options) {
#      79                 :            :   // Note: if more fields are added to Options, update
#      80                 :            :   // this function to catch changes that should not be allowed to
#      81                 :            :   // change in the middle of building a Table.
#      82         [ #  # ]:          0 :   if (options.comparator != rep_->options.comparator) {
#      83                 :          0 :     return Status::InvalidArgument("changing comparator while building table");
#      84                 :          0 :   }
#      85                 :            : 
#      86                 :            :   // Note that any live BlockBuilders point to rep_->options and therefore
#      87                 :            :   // will automatically pick up the updated options.
#      88                 :          0 :   rep_->options = options;
#      89                 :          0 :   rep_->index_block_options = options;
#      90                 :          0 :   rep_->index_block_options.block_restart_interval = 1;
#      91                 :          0 :   return Status::OK();
#      92                 :          0 : }
#      93                 :            : 
#      94                 :     196617 : void TableBuilder::Add(const Slice& key, const Slice& value) {
#      95                 :     196617 :   Rep* r = rep_;
#      96                 :     196617 :   assert(!r->closed);
#      97         [ -  + ]:     196617 :   if (!ok()) return;
#      98         [ +  + ]:     196617 :   if (r->num_entries > 0) {
#      99                 :     195540 :     assert(r->options.comparator->Compare(key, Slice(r->last_key)) > 0);
#     100                 :     195540 :   }
#     101                 :            : 
#     102         [ +  + ]:     196617 :   if (r->pending_index_entry) {
#     103                 :       3571 :     assert(r->data_block.empty());
#     104                 :          0 :     r->options.comparator->FindShortestSeparator(&r->last_key, key);
#     105                 :       3571 :     std::string handle_encoding;
#     106                 :       3571 :     r->pending_handle.EncodeTo(&handle_encoding);
#     107                 :       3571 :     r->index_block.Add(r->last_key, Slice(handle_encoding));
#     108                 :       3571 :     r->pending_index_entry = false;
#     109                 :       3571 :   }
#     110                 :            : 
#     111         [ +  - ]:     196617 :   if (r->filter_block != nullptr) {
#     112                 :     196617 :     r->filter_block->AddKey(key);
#     113                 :     196617 :   }
#     114                 :            : 
#     115                 :     196617 :   r->last_key.assign(key.data(), key.size());
#     116                 :     196617 :   r->num_entries++;
#     117                 :     196617 :   r->data_block.Add(key, value);
#     118                 :            : 
#     119                 :     196617 :   const size_t estimated_block_size = r->data_block.CurrentSizeEstimate();
#     120         [ +  + ]:     196617 :   if (estimated_block_size >= r->options.block_size) {
#     121                 :       3573 :     Flush();
#     122                 :       3573 :   }
#     123                 :     196617 : }
#     124                 :            : 
#     125                 :       4650 : void TableBuilder::Flush() {
#     126                 :       4650 :   Rep* r = rep_;
#     127                 :       4650 :   assert(!r->closed);
#     128         [ -  + ]:       4650 :   if (!ok()) return;
#     129         [ +  + ]:       4650 :   if (r->data_block.empty()) return;
#     130                 :       4648 :   assert(!r->pending_index_entry);
#     131                 :          0 :   WriteBlock(&r->data_block, &r->pending_handle);
#     132         [ +  - ]:       4648 :   if (ok()) {
#     133                 :       4648 :     r->pending_index_entry = true;
#     134                 :       4648 :     r->status = r->file->Flush();
#     135                 :       4648 :   }
#     136         [ +  - ]:       4648 :   if (r->filter_block != nullptr) {
#     137                 :       4648 :     r->filter_block->StartBlock(r->offset);
#     138                 :       4648 :   }
#     139                 :       4648 : }
#     140                 :            : 
#     141                 :       6802 : void TableBuilder::WriteBlock(BlockBuilder* block, BlockHandle* handle) {
#     142                 :            :   // File format contains a sequence of blocks where each block has:
#     143                 :            :   //    block_data: uint8[n]
#     144                 :            :   //    type: uint8
#     145                 :            :   //    crc: uint32
#     146                 :       6802 :   assert(ok());
#     147                 :          0 :   Rep* r = rep_;
#     148                 :       6802 :   Slice raw = block->Finish();
#     149                 :            : 
#     150                 :       6802 :   Slice block_contents;
#     151                 :       6802 :   CompressionType type = r->options.compression;
#     152                 :            :   // TODO(postrelease): Support more compression options: zlib?
#     153         [ -  + ]:       6802 :   switch (type) {
#     154         [ +  - ]:       6802 :     case kNoCompression:
#     155                 :       6802 :       block_contents = raw;
#     156                 :       6802 :       break;
#     157                 :            : 
#     158         [ -  + ]:          0 :     case kSnappyCompression: {
#     159                 :          0 :       std::string* compressed = &r->compressed_output;
#     160         [ #  # ]:          0 :       if (port::Snappy_Compress(raw.data(), raw.size(), compressed) &&
#     161         [ #  # ]:          0 :           compressed->size() < raw.size() - (raw.size() / 8u)) {
#     162                 :          0 :         block_contents = *compressed;
#     163                 :          0 :       } else {
#     164                 :            :         // Snappy not supported, or compressed less than 12.5%, so just
#     165                 :            :         // store uncompressed form
#     166                 :          0 :         block_contents = raw;
#     167                 :          0 :         type = kNoCompression;
#     168                 :          0 :       }
#     169                 :          0 :       break;
#     170                 :          0 :     }
#     171                 :       6802 :   }
#     172                 :       6802 :   WriteRawBlock(block_contents, type, handle);
#     173                 :       6802 :   r->compressed_output.clear();
#     174                 :       6802 :   block->Reset();
#     175                 :       6802 : }
#     176                 :            : 
#     177                 :            : void TableBuilder::WriteRawBlock(const Slice& block_contents,
#     178                 :       7879 :                                  CompressionType type, BlockHandle* handle) {
#     179                 :       7879 :   Rep* r = rep_;
#     180                 :       7879 :   handle->set_offset(r->offset);
#     181                 :       7879 :   handle->set_size(block_contents.size());
#     182                 :       7879 :   r->status = r->file->Append(block_contents);
#     183         [ +  - ]:       7879 :   if (r->status.ok()) {
#     184                 :       7879 :     char trailer[kBlockTrailerSize];
#     185                 :       7879 :     trailer[0] = type;
#     186                 :       7879 :     uint32_t crc = crc32c::Value(block_contents.data(), block_contents.size());
#     187                 :       7879 :     crc = crc32c::Extend(crc, trailer, 1);  // Extend crc to cover block type
#     188                 :       7879 :     EncodeFixed32(trailer + 1, crc32c::Mask(crc));
#     189                 :       7879 :     r->status = r->file->Append(Slice(trailer, kBlockTrailerSize));
#     190         [ +  - ]:       7879 :     if (r->status.ok()) {
#     191                 :       7879 :       r->offset += block_contents.size() + kBlockTrailerSize;
#     192                 :       7879 :     }
#     193                 :       7879 :   }
#     194                 :       7879 : }
#     195                 :            : 
#     196                 :     217025 : Status TableBuilder::status() const { return rep_->status; }
#     197                 :            : 
#     198                 :       1077 : Status TableBuilder::Finish() {
#     199                 :       1077 :   Rep* r = rep_;
#     200                 :       1077 :   Flush();
#     201                 :       1077 :   assert(!r->closed);
#     202                 :          0 :   r->closed = true;
#     203                 :            : 
#     204                 :       1077 :   BlockHandle filter_block_handle, metaindex_block_handle, index_block_handle;
#     205                 :            : 
#     206                 :            :   // Write filter block
#     207 [ +  - ][ +  - ]:       1077 :   if (ok() && r->filter_block != nullptr) {
#     208                 :       1077 :     WriteRawBlock(r->filter_block->Finish(), kNoCompression,
#     209                 :       1077 :                   &filter_block_handle);
#     210                 :       1077 :   }
#     211                 :            : 
#     212                 :            :   // Write metaindex block
#     213         [ +  - ]:       1077 :   if (ok()) {
#     214                 :       1077 :     BlockBuilder meta_index_block(&r->options);
#     215         [ +  - ]:       1077 :     if (r->filter_block != nullptr) {
#     216                 :            :       // Add mapping from "filter.Name" to location of filter data
#     217                 :       1077 :       std::string key = "filter.";
#     218                 :       1077 :       key.append(r->options.filter_policy->Name());
#     219                 :       1077 :       std::string handle_encoding;
#     220                 :       1077 :       filter_block_handle.EncodeTo(&handle_encoding);
#     221                 :       1077 :       meta_index_block.Add(key, handle_encoding);
#     222                 :       1077 :     }
#     223                 :            : 
#     224                 :            :     // TODO(postrelease): Add stats and other meta blocks
#     225                 :       1077 :     WriteBlock(&meta_index_block, &metaindex_block_handle);
#     226                 :       1077 :   }
#     227                 :            : 
#     228                 :            :   // Write index block
#     229         [ +  - ]:       1077 :   if (ok()) {
#     230         [ +  - ]:       1077 :     if (r->pending_index_entry) {
#     231                 :       1077 :       r->options.comparator->FindShortSuccessor(&r->last_key);
#     232                 :       1077 :       std::string handle_encoding;
#     233                 :       1077 :       r->pending_handle.EncodeTo(&handle_encoding);
#     234                 :       1077 :       r->index_block.Add(r->last_key, Slice(handle_encoding));
#     235                 :       1077 :       r->pending_index_entry = false;
#     236                 :       1077 :     }
#     237                 :       1077 :     WriteBlock(&r->index_block, &index_block_handle);
#     238                 :       1077 :   }
#     239                 :            : 
#     240                 :            :   // Write footer
#     241         [ +  - ]:       1077 :   if (ok()) {
#     242                 :       1077 :     Footer footer;
#     243                 :       1077 :     footer.set_metaindex_handle(metaindex_block_handle);
#     244                 :       1077 :     footer.set_index_handle(index_block_handle);
#     245                 :       1077 :     std::string footer_encoding;
#     246                 :       1077 :     footer.EncodeTo(&footer_encoding);
#     247                 :       1077 :     r->status = r->file->Append(footer_encoding);
#     248         [ +  - ]:       1077 :     if (r->status.ok()) {
#     249                 :       1077 :       r->offset += footer_encoding.size();
#     250                 :       1077 :     }
#     251                 :       1077 :   }
#     252                 :       1077 :   return r->status;
#     253                 :       1077 : }
#     254                 :            : 
#     255                 :          0 : void TableBuilder::Abandon() {
#     256                 :          0 :   Rep* r = rep_;
#     257                 :          0 :   assert(!r->closed);
#     258                 :          0 :   r->closed = true;
#     259                 :          0 : }
#     260                 :            : 
#     261                 :      32287 : uint64_t TableBuilder::NumEntries() const { return rep_->num_entries; }
#     262                 :            : 
#     263                 :      33256 : uint64_t TableBuilder::FileSize() const { return rep_->offset; }
#     264                 :            : 
#     265                 :            : }  // namespace leveldb

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a