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 Iterator* TableCache::NewIterator(const ReadOptions& options, 46 uint64_t file_number, 47 uint64_t file_size, 48 Table** tableptr) { 49 if (tableptr != NULL) { 50 *tableptr = NULL; 51 } 52 53 char buf[sizeof(file_number)]; 54 EncodeFixed64(buf, file_number); 55 Slice key(buf, sizeof(buf)); 56 Cache::Handle* handle = cache_->Lookup(key); 57 if (handle == NULL) { 58 std::string fname = TableFileName(dbname_, file_number); 59 RandomAccessFile* file = NULL; 60 Table* table = NULL; 61 Status s = env_->NewRandomAccessFile(fname, &file); 62 if (s.ok()) { 63 s = Table::Open(*options_, file, file_size, &table); 64 } 65 66 if (!s.ok()) { 67 assert(table == NULL); 68 delete file; 69 // We do not cache error results so that if the error is transient, 70 // or somebody repairs the file, we recover automatically. 71 return NewErrorIterator(s); 72 } 73 74 TableAndFile* tf = new TableAndFile; 75 tf->file = file; 76 tf->table = table; 77 handle = cache_->Insert(key, tf, 1, &DeleteEntry); 78 } 79 80 Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table; 81 Iterator* result = table->NewIterator(options); 82 result->RegisterCleanup(&UnrefEntry, cache_, handle); 83 if (tableptr != NULL) { 84 *tableptr = table; 85 } 86 return result; 87 } 88 89 void TableCache::Evict(uint64_t file_number) { 90 char buf[sizeof(file_number)]; 91 EncodeFixed64(buf, file_number); 92 cache_->Erase(Slice(buf, sizeof(buf))); 93 } 94 95 } 96