阅读本博客可参考:
由上面这三篇博客可知,LevelDB的Cache分为两种,分别是table cache和block cache。block是table文件内组织数据的单位,也是从持久化存储中读取和写入的单位。
block cache是缓存的block数据。table cache缓存的是table的索引数据,因此通过table cache可以遍历DB所有.sst文件,类似于文件系统中对inode的缓存。
在LevelDB源码分析之十三:table中用到了block_cache,它实际上就是一个NewLRUCache对象,并没有像table_cache一样,专门用一个类TableCache来管理NewLRUCache对象。
下面来简单分析TableCache。
struct TableAndFile {
RandomAccessFile* file;
Table* table;
};
static void DeleteEntry(const Slice& key, void* value) {
TableAndFile* tf = reinterpret_cast<TableAndFile*>(value);
delete tf->table;
delete tf->file;
delete tf;
}
static void UnrefEntry(void* arg1, void* arg2) {
Cache* cache = reinterpret_cast<Cache*>(arg1);
Cache::Handle* h = reinterpret_cast<Cache::Handle*>(arg2);
cache->Release(h);
}
// 从构造函数中可以看出TableCache内部管理的是LRUCache对象
TableCache::TableCache(const std::string& dbname,
const Options* options,
int entries)
: env_(options->env),
dbname_(dbname),
options_(options),
cache_(NewLRUCache(entries)) {
}
TableCache::~TableCache() {
delete cache_;
}
// 参数file_number是文件编号,file_size是文件大小
// 参数*tableptr指向Table对象,当然必须先判断tableptr是不是NULL
// 返回某个.sst文件对应的Table对象的迭代器
Iterator* TableCache::NewIterator(const ReadOptions& options,
uint64_t file_number,
uint64_t file_size,
Table** tableptr) {
if (tableptr != NULL) {
*tableptr = NULL;
}
// 将file_number转换为key
char buf[sizeof(file_number)];
EncodeFixed64(buf, file_number);
Slice key(buf, sizeof(buf));
// 根据key查找指定的文件
Cache::Handle* handle = cache_->Lookup(key);
// 如果指定文件不存在,打开文件并添加至缓存
if (handle == NULL) {
// 返回新的.sst文件的路径
std::string fname = TableFileName(dbname_, file_number);
RandomAccessFile* file = NULL;
Table* table = NULL;
Status s = env_->NewRandomAccessFile(fname, &file);
if (s.ok()) {
// 将.sst文件映射到table,Table类用于解析.sst文件
s = Table::Open(*options_, file, file_size, &table);
}
if (!s.ok()) {
assert(table == NULL);
delete file;
// We do not cache error results so that if the error is transient,
// or somebody repairs the file, we recover automatically.
return NewErrorIterator(s);
}
TableAndFile* tf = new TableAndFile;
tf->file = file;
tf->table = table;
// 将tf插入到LRUCache中,占据一个大小的缓存,DeleteEntry是删除结点的回调函数
handle = cache_->Insert(key, tf, 1, &DeleteEntry);
}
// cache_->Value(handle)用于返回handle结点的value
Table* table = reinterpret_cast<TableAndFile*>(cache_->Value(handle))->table;
Iterator* result = table->NewIterator(options);
result->RegisterCleanup(&UnrefEntry, cache_, handle);
if (tableptr != NULL) {
*tableptr = table;
}
return result;
}
// Evict含义为”驱逐“,当Compaction时,过期的文件将会被移除,此时调用Evict从移除该文件缓存。
void TableCache::Evict(uint64_t file_number) {
char buf[sizeof(file_number)];
EncodeFixed64(buf, file_number);
// 从LRUCache中删除对应的key结点,不过此时该结点内容为TableAndFile
cache_->Erase(Slice(buf, sizeof(buf)));
}