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