table_cache.cc
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