table_cache.cc raw

   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 "db/table_cache.h"
   6  
   7  #include "db/filename.h"
   8  #include "leveldb/env.h"
   9  #include "leveldb/table.h"
  10  #include "util/coding.h"
  11  
  12  namespace leveldb {
  13  
  14  struct TableAndFile {
  15    RandomAccessFile* file;
  16    Table* table;
  17  };
  18  
  19  static void DeleteEntry(const Slice& key, void* value) {
  20    TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);
  21    delete tf->table;
  22    delete tf->file;
  23    delete tf;
  24  }
  25  
  26  static void UnrefEntry(void* arg1, void* arg2) {
  27    Cache* cache = reinterpret_cast<Cache*>(arg1);
  28    Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);
  29    cache->Release(h);
  30  }
  31  
  32  TableCache::TableCache(const std::string& dbname, const Options& options,
  33                         int entries)
  34      : env_(options.env),
  35        dbname_(dbname),
  36        options_(options),
  37        cache_(NewLRUCache(entries)) {}
  38  
  39  TableCache::~TableCache() { delete cache_; }
  40  
  41  Status TableCache::FindTable(uint64_t file_number, uint64_t file_size,
  42                               Cache::Handle** handle) {
  43    Status s;
  44    char buf[sizeof(file_number)];
  45    EncodeFixed64(buf, file_number);
  46    Slice key(buf, sizeof(buf));
  47    *handle = cache_->Lookup(key);
  48    if (*handle == nullptr) {
  49      std::string fname = TableFileName(dbname_, file_number);
  50      RandomAccessFile* file = nullptr;
  51      Table* table = nullptr;
  52      s = env_->NewRandomAccessFile(fname, &file);
  53      if (!s.ok()) {
  54        std::string old_fname = SSTTableFileName(dbname_, file_number);
  55        if (env_->NewRandomAccessFile(old_fname, &file).ok()) {
  56          s = Status::OK();
  57        }
  58      }
  59      if (s.ok()) {
  60        s = Table::Open(options_, file, file_size, &table);
  61      }
  62  
  63      if (!s.ok()) {
  64        assert(table == nullptr);
  65        delete file;
  66        // We do not cache error results so that if the error is transient,
  67        // or somebody repairs the file, we recover automatically.
  68      } else {
  69        TableAndFile* tf = new TableAndFile;
  70        tf->file = file;
  71        tf->table = table;
  72        *handle = cache_->Insert(key, tf, 1, &DeleteEntry);
  73      }
  74    }
  75    return s;
  76  }
  77  
  78  Iterator* TableCache::NewIterator(const ReadOptions& options,
  79                                    uint64_t file_number, uint64_t file_size,
  80                                    Table** tableptr) {
  81    if (tableptr != nullptr) {
  82      *tableptr = nullptr;
  83    }
  84  
  85    Cache::Handle* handle = nullptr;
  86    Status s = FindTable(file_number, file_size, &handle);
  87    if (!s.ok()) {
  88      return NewErrorIterator(s);
  89    }
  90  
  91    Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
  92    Iterator* result = table->NewIterator(options);
  93    result->RegisterCleanup(&UnrefEntry, cache_, handle);
  94    if (tableptr != nullptr) {
  95      *tableptr = table;
  96    }
  97    return result;
  98  }
  99  
 100  Status TableCache::Get(const ReadOptions& options, uint64_t file_number,
 101                         uint64_t file_size, const Slice& k, void* arg,
 102                         void (*handle_result)(void*, const Slice&,
 103                                               const Slice&)) {
 104    Cache::Handle* handle = nullptr;
 105    Status s = FindTable(file_number, file_size, &handle);
 106    if (s.ok()) {
 107      Table* t = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
 108      s = t->InternalGet(options, k, arg, handle_result);
 109      cache_->Release(handle);
 110    }
 111    return s;
 112  }
 113  
 114  void TableCache::Evict(uint64_t file_number) {
 115    char buf[sizeof(file_number)];
 116    EncodeFixed64(buf, file_number);
 117    cache_->Erase(Slice(buf, sizeof(buf)));
 118  }
 119  
 120  }  // namespace leveldb
 121