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