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 12namespace leveldb { 13 14struct TableAndFile { 15 RandomAccessFile* file; 16 Table* table; 17}; 18 19static 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 26static 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 32TableCache::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 41TableCache::~TableCache() { 42 delete cache_; 43} 44 45Status 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 s = Table::Open(*options_, file, file_size, &table); 59 } 60 61 if (!s.ok()) { 62 assert(table == NULL); 63 delete file; 64 // We do not cache error results so that if the error is transient, 65 // or somebody repairs the file, we recover automatically. 66 } else { 67 TableAndFile* tf = new TableAndFile; 68 tf->file = file; 69 tf->table = table; 70 *handle = cache_->Insert(key, tf, 1, &DeleteEntry); 71 } 72 } 73 return s; 74} 75 76Iterator* TableCache::NewIterator(const ReadOptions& options, 77 uint64_t file_number, 78 uint64_t file_size, 79 Table** tableptr) { 80 if (tableptr != NULL) { 81 *tableptr = NULL; 82 } 83 84 Cache::Handle* handle = NULL; 85 Status s = FindTable(file_number, file_size, &handle); 86 if (!s.ok()) { 87 return NewErrorIterator(s); 88 } 89 90 Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table; 91 Iterator* result = table->NewIterator(options); 92 result->RegisterCleanup(&UnrefEntry, cache_, handle); 93 if (tableptr != NULL) { 94 *tableptr = table; 95 } 96 return result; 97} 98 99Status TableCache::Get(const ReadOptions& options, 100 uint64_t file_number, 101 uint64_t file_size, 102 const Slice& k, 103 void* arg, 104 void (*saver)(void*, const Slice&, const Slice&)) { 105 Cache::Handle* handle = NULL; 106 Status s = FindTable(file_number, file_size, &handle); 107 if (s.ok()) { 108 Table* t = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table; 109 s = t->InternalGet(options, k, arg, saver); 110 cache_->Release(handle); 111 } 112 return s; 113} 114 115void TableCache::Evict(uint64_t file_number) { 116 char buf[sizeof(file_number)]; 117 EncodeFixed64(buf, file_number); 118 cache_->Erase(Slice(buf, sizeof(buf))); 119} 120 121} // namespace leveldb 122