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
DeleteEntry(const Slice & key,void * value)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
UnrefEntry(void * arg1,void * arg2)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
TableCache(const std::string & dbname,const Options & options,int entries)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
~TableCache()39 TableCache::~TableCache() { delete cache_; }
40
FindTable(uint64_t file_number,uint64_t file_size,Cache::Handle ** handle)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
NewIterator(const ReadOptions & options,uint64_t file_number,uint64_t file_size,Table ** tableptr)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
Get(const ReadOptions & options,uint64_t file_number,uint64_t file_size,const Slice & k,void * arg,void (* handle_result)(void *,const Slice &,const Slice &))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
Evict(uint64_t file_number)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