LCOV - code coverage report
Current view: top level - src/leveldb/table - table.cc (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 95.5 % 156 149
Test Date: 2026-02-04 05:05:50 Functions: 100.0 % 12 12
Branches: 53.2 % 220 117

             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.h"
       6                 :             : 
       7                 :             : #include "leveldb/cache.h"
       8                 :             : #include "leveldb/comparator.h"
       9                 :             : #include "leveldb/env.h"
      10                 :             : #include "leveldb/filter_policy.h"
      11                 :             : #include "leveldb/options.h"
      12                 :             : #include "table/block.h"
      13                 :             : #include "table/filter_block.h"
      14                 :             : #include "table/format.h"
      15                 :             : #include "table/two_level_iterator.h"
      16                 :             : #include "util/coding.h"
      17                 :             : 
      18                 :             : namespace leveldb {
      19                 :             : 
      20         [ +  - ]:        4144 : struct Table::Rep {
      21                 :        4142 :   ~Rep() {
      22         [ +  - ]:        4142 :     delete filter;
      23         [ +  + ]:        4142 :     delete[] filter_data;
      24         [ +  - ]:        4142 :     delete index_block;
      25         [ -  + ]:        4142 :   }
      26                 :             : 
      27                 :             :   Options options;
      28                 :             :   Status status;
      29                 :             :   RandomAccessFile* file;
      30                 :             :   uint64_t cache_id;
      31                 :             :   FilterBlockReader* filter;
      32                 :             :   const char* filter_data;
      33                 :             : 
      34                 :             :   BlockHandle metaindex_handle;  // Handle to metaindex_block: saved from footer
      35                 :             :   Block* index_block;
      36                 :             : };
      37                 :             : 
      38                 :        4145 : Status Table::Open(const Options& options, RandomAccessFile* file,
      39                 :             :                    uint64_t size, Table** table) {
      40                 :        4145 :   *table = nullptr;
      41         [ -  + ]:        4145 :   if (size < Footer::kEncodedLength) {
      42                 :           0 :     return Status::Corruption("file is too short to be an sstable");
      43                 :             :   }
      44                 :             : 
      45                 :        4145 :   char footer_space[Footer::kEncodedLength];
      46                 :        4145 :   Slice footer_input;
      47                 :        4145 :   Status s = file->Read(size - Footer::kEncodedLength, Footer::kEncodedLength,
      48                 :        4145 :                         &footer_input, footer_space);
      49         [ -  + ]:        4145 :   if (!s.ok()) return s;
      50                 :             : 
      51         [ +  - ]:        4145 :   Footer footer;
      52   [ +  -  -  + ]:        4145 :   s = footer.DecodeFrom(&footer_input);
      53         [ +  + ]:        4145 :   if (!s.ok()) return s;
      54                 :             : 
      55                 :             :   // Read the index block
      56         [ +  - ]:        4144 :   BlockContents index_block_contents;
      57                 :        4144 :   if (s.ok()) {
      58                 :        4144 :     ReadOptions opt;
      59         [ +  - ]:        4144 :     if (options.paranoid_checks) {
      60                 :        4144 :       opt.verify_checksums = true;
      61                 :             :     }
      62   [ +  -  -  + ]:        4144 :     s = ReadBlock(file, opt, footer.index_handle(), &index_block_contents);
      63                 :             :   }
      64                 :             : 
      65         [ +  - ]:        4144 :   if (s.ok()) {
      66                 :             :     // We've successfully read the footer and the index block: we're
      67                 :             :     // ready to serve requests.
      68   [ +  -  +  - ]:        4144 :     Block* index_block = new Block(index_block_contents);
      69   [ +  -  +  - ]:        4144 :     Rep* rep = new Table::Rep;
      70                 :        4144 :     rep->options = options;
      71                 :        4144 :     rep->file = file;
      72                 :        4144 :     rep->metaindex_handle = footer.metaindex_handle();
      73                 :        4144 :     rep->index_block = index_block;
      74   [ +  -  +  - ]:        4144 :     rep->cache_id = (options.block_cache ? options.block_cache->NewId() : 0);
      75                 :        4144 :     rep->filter_data = nullptr;
      76                 :        4144 :     rep->filter = nullptr;
      77   [ +  -  +  - ]:        4144 :     *table = new Table(rep);
      78         [ +  - ]:        4144 :     (*table)->ReadMeta(footer);
      79                 :             :   }
      80                 :             : 
      81                 :        4144 :   return s;
      82                 :        4145 : }
      83                 :             : 
      84                 :        4144 : void Table::ReadMeta(const Footer& footer) {
      85         [ +  - ]:        4144 :   if (rep_->options.filter_policy == nullptr) {
      86                 :             :     return;  // Do not need any metadata
      87                 :             :   }
      88                 :             : 
      89                 :             :   // TODO(sanjay): Skip this if footer.metaindex_handle() size indicates
      90                 :             :   // it is an empty block.
      91                 :        4144 :   ReadOptions opt;
      92         [ +  - ]:        4144 :   if (rep_->options.paranoid_checks) {
      93                 :        4144 :     opt.verify_checksums = true;
      94                 :             :   }
      95                 :        4144 :   BlockContents contents;
      96   [ -  +  +  - ]:        4144 :   if (!ReadBlock(rep_->file, opt, footer.metaindex_handle(), &contents).ok()) {
      97                 :             :     // Do not propagate errors since meta info is not needed for operation
      98                 :             :     return;
      99                 :             :   }
     100         [ +  - ]:        4144 :   Block* meta = new Block(contents);
     101                 :             : 
     102                 :        4144 :   Iterator* iter = meta->NewIterator(BytewiseComparator());
     103                 :        4144 :   std::string key = "filter.";
     104   [ +  -  +  - ]:        4144 :   key.append(rep_->options.filter_policy->Name());
     105   [ -  +  +  - ]:        4144 :   iter->Seek(key);
     106   [ +  -  +  -  :        8288 :   if (iter->Valid() && iter->key() == Slice(key)) {
             +  -  +  - ]
     107   [ +  -  +  - ]:        4144 :     ReadFilter(iter->value());
     108                 :             :   }
     109         [ +  - ]:        4144 :   delete iter;
     110         [ +  - ]:        4144 :   delete meta;
     111                 :        4144 : }
     112                 :             : 
     113                 :        4144 : void Table::ReadFilter(const Slice& filter_handle_value) {
     114                 :        4144 :   Slice v = filter_handle_value;
     115                 :        4144 :   BlockHandle filter_handle;
     116   [ -  +  +  - ]:        4144 :   if (!filter_handle.DecodeFrom(&v).ok()) {
     117                 :             :     return;
     118                 :             :   }
     119                 :             : 
     120                 :             :   // We might want to unify with ReadBlock() if we start
     121                 :             :   // requiring checksum verification in Table::Open.
     122                 :        4144 :   ReadOptions opt;
     123         [ +  - ]:        4144 :   if (rep_->options.paranoid_checks) {
     124                 :        4144 :     opt.verify_checksums = true;
     125                 :             :   }
     126                 :        4144 :   BlockContents block;
     127   [ -  +  +  - ]:        4144 :   if (!ReadBlock(rep_->file, opt, filter_handle, &block).ok()) {
     128                 :             :     return;
     129                 :             :   }
     130         [ +  + ]:        4144 :   if (block.heap_allocated) {
     131                 :           1 :     rep_->filter_data = block.data.data();  // Will need to delete later
     132                 :             :   }
     133         [ +  - ]:        4144 :   rep_->filter = new FilterBlockReader(rep_->options.filter_policy, block.data);
     134                 :             : }
     135                 :             : 
     136         [ +  - ]:        4142 : Table::~Table() { delete rep_; }
     137                 :             : 
     138                 :       44209 : static void DeleteBlock(void* arg, void* ignored) {
     139         [ +  - ]:       44209 :   delete reinterpret_cast<Block*>(arg);
     140                 :       44209 : }
     141                 :             : 
     142                 :         255 : static void DeleteCachedBlock(const Slice& key, void* value) {
     143                 :         255 :   Block* block = reinterpret_cast<Block*>(value);
     144         [ +  - ]:         255 :   delete block;
     145                 :         255 : }
     146                 :             : 
     147                 :       63694 : static void ReleaseBlock(void* arg, void* h) {
     148                 :       63694 :   Cache* cache = reinterpret_cast<Cache*>(arg);
     149                 :       63694 :   Cache::Handle* handle = reinterpret_cast<Cache::Handle*>(h);
     150                 :       63694 :   cache->Release(handle);
     151                 :       63694 : }
     152                 :             : 
     153                 :             : // Convert an index iterator value (i.e., an encoded BlockHandle)
     154                 :             : // into an iterator over the contents of the corresponding block.
     155                 :      107905 : Iterator* Table::BlockReader(void* arg, const ReadOptions& options,
     156                 :             :                              const Slice& index_value) {
     157                 :      107905 :   Table* table = reinterpret_cast<Table*>(arg);
     158                 :      107905 :   Cache* block_cache = table->rep_->options.block_cache;
     159                 :      107905 :   Block* block = nullptr;
     160                 :      107905 :   Cache::Handle* cache_handle = nullptr;
     161                 :             : 
     162                 :      107905 :   BlockHandle handle;
     163                 :      107905 :   Slice input = index_value;
     164                 :      107905 :   Status s = handle.DecodeFrom(&input);
     165                 :             :   // We intentionally allow extra stuff in index_value so that we
     166                 :             :   // can add more features in the future.
     167                 :             : 
     168         [ +  - ]:      107905 :   if (s.ok()) {
     169         [ +  - ]:      107905 :     BlockContents contents;
     170         [ +  - ]:      107905 :     if (block_cache != nullptr) {
     171                 :      107905 :       char cache_key_buffer[16];
     172                 :      107905 :       EncodeFixed64(cache_key_buffer, table->rep_->cache_id);
     173                 :      107905 :       EncodeFixed64(cache_key_buffer + 8, handle.offset());
     174         [ +  - ]:      107905 :       Slice key(cache_key_buffer, sizeof(cache_key_buffer));
     175         [ +  - ]:      107905 :       cache_handle = block_cache->Lookup(key);
     176         [ +  + ]:      107905 :       if (cache_handle != nullptr) {
     177         [ +  - ]:       63439 :         block = reinterpret_cast<Block*>(block_cache->Value(cache_handle));
     178                 :             :       } else {
     179   [ +  -  -  + ]:       44466 :         s = ReadBlock(table->rep_->file, options, handle, &contents);
     180         [ +  + ]:       44466 :         if (s.ok()) {
     181   [ +  -  +  - ]:       44464 :           block = new Block(contents);
     182   [ +  +  +  - ]:       44464 :           if (contents.cachable && options.fill_cache) {
     183         [ +  - ]:         255 :             cache_handle = block_cache->Insert(key, block, block->size(),
     184                 :             :                                                &DeleteCachedBlock);
     185                 :             :           }
     186                 :             :         }
     187                 :             :       }
     188                 :             :     } else {
     189   [ #  #  #  # ]:           0 :       s = ReadBlock(table->rep_->file, options, handle, &contents);
     190         [ #  # ]:           0 :       if (s.ok()) {
     191   [ #  #  #  # ]:           0 :         block = new Block(contents);
     192                 :             :       }
     193                 :             :     }
     194                 :             :   }
     195                 :             : 
     196                 :      107648 :   Iterator* iter;
     197         [ +  - ]:      107648 :   if (block != nullptr) {
     198         [ +  - ]:      107903 :     iter = block->NewIterator(table->rep_->options.comparator);
     199         [ +  + ]:      107903 :     if (cache_handle == nullptr) {
     200         [ +  - ]:       44209 :       iter->RegisterCleanup(&DeleteBlock, block, nullptr);
     201                 :             :     } else {
     202         [ +  - ]:       63694 :       iter->RegisterCleanup(&ReleaseBlock, block_cache, cache_handle);
     203                 :             :     }
     204                 :             :   } else {
     205         [ +  - ]:           2 :     iter = NewErrorIterator(s);
     206                 :             :   }
     207         [ +  + ]:      107905 :   return iter;
     208                 :      107905 : }
     209                 :             : 
     210                 :        6992 : Iterator* Table::NewIterator(const ReadOptions& options) const {
     211                 :        6992 :   return NewTwoLevelIterator(
     212                 :        6992 :       rep_->index_block->NewIterator(rep_->options.comparator),
     213                 :        6992 :       &Table::BlockReader, const_cast<Table*>(this), options);
     214                 :             : }
     215                 :             : 
     216                 :     2216827 : Status Table::InternalGet(const ReadOptions& options, const Slice& k, void* arg,
     217                 :             :                           void (*handle_result)(void*, const Slice&,
     218                 :             :                                                 const Slice&)) {
     219         [ +  - ]:     2216827 :   Status s;
     220         [ +  - ]:     2216827 :   Iterator* iiter = rep_->index_block->NewIterator(rep_->options.comparator);
     221         [ +  - ]:     2216827 :   iiter->Seek(k);
     222   [ +  -  +  - ]:     2216827 :   if (iiter->Valid()) {
     223         [ +  - ]:     2216827 :     Slice handle_value = iiter->value();
     224                 :     2216827 :     FilterBlockReader* filter = rep_->filter;
     225         [ +  - ]:     2216827 :     BlockHandle handle;
     226   [ +  -  +  -  :     6650481 :     if (filter != nullptr && handle.DecodeFrom(&handle_value).ok() &&
          +  -  +  +  +  
                      + ]
     227         [ +  - ]:     2216827 :         !filter->KeyMayMatch(handle.offset(), k)) {
     228                 :             :       // Not found
     229                 :             :     } else {
     230   [ +  -  +  - ]:       94706 :       Iterator* block_iter = BlockReader(this, options, iiter->value());
     231         [ +  - ]:       94706 :       block_iter->Seek(k);
     232   [ +  -  +  + ]:       94706 :       if (block_iter->Valid()) {
     233   [ +  -  +  -  :       94687 :         (*handle_result)(arg, block_iter->key(), block_iter->value());
                   +  - ]
     234                 :             :       }
     235   [ +  -  -  + ]:       94706 :       s = block_iter->status();
     236         [ +  - ]:       94706 :       delete block_iter;
     237                 :             :     }
     238                 :             :   }
     239         [ +  + ]:     2216827 :   if (s.ok()) {
     240   [ +  -  -  + ]:     2216826 :     s = iiter->status();
     241                 :             :   }
     242         [ +  - ]:     2216827 :   delete iiter;
     243                 :     2216827 :   return s;
     244                 :           0 : }
     245                 :             : 
     246                 :         164 : uint64_t Table::ApproximateOffsetOf(const Slice& key) const {
     247                 :         164 :   Iterator* index_iter =
     248                 :         164 :       rep_->index_block->NewIterator(rep_->options.comparator);
     249                 :         164 :   index_iter->Seek(key);
     250                 :         164 :   uint64_t result;
     251         [ +  - ]:         164 :   if (index_iter->Valid()) {
     252                 :         164 :     BlockHandle handle;
     253                 :         164 :     Slice input = index_iter->value();
     254                 :         164 :     Status s = handle.DecodeFrom(&input);
     255         [ +  - ]:         164 :     if (s.ok()) {
     256                 :         164 :       result = handle.offset();
     257                 :             :     } else {
     258                 :             :       // Strange: we can't decode the block handle in the index block.
     259                 :             :       // We'll just return the offset of the metaindex block, which is
     260                 :             :       // close to the whole file size for this case.
     261                 :           0 :       result = rep_->metaindex_handle.offset();
     262                 :             :     }
     263                 :         164 :   } else {
     264                 :             :     // key is past the last key in the file.  Approximate the offset
     265                 :             :     // by returning the offset of the metaindex block (which is
     266                 :             :     // right near the end of the file).
     267                 :           0 :     result = rep_->metaindex_handle.offset();
     268                 :             :   }
     269         [ +  - ]:         164 :   delete index_iter;
     270                 :         164 :   return result;
     271                 :             : }
     272                 :             : 
     273                 :             : }  // namespace leveldb
        

Generated by: LCOV version 2.0-1