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