RocksDB源码分析
slice
和levelDB类似,无太大变化
PinnableSlice
http://kernelmaker.github.io/Rocksdb_pinnableslice
主要作用是延长数据生命周期,减少数据拷贝。PinnableSlice中记录数据的指针,使用的时候通过指针进行解引用。不需要从最底层进行数据的copy,数据的生命周期使用Reset
和其析构函数确定,此时调用cleanup注册的cleanup函数对数据进行处理,
- 这种思想在其他地方存在,例如trafodion的queue_entry,或者是向量化中的延迟物化技术,本质上都是避免直接进行数据拷贝,只进行指针传递,只是RocksDB中处理更进一步,添加了委托清理等逻辑
Status
无变化,只是添加了些特殊状态
Arena
在levelDB的基础上,添加了大空间的支持,对于huge_blocks。使用mmap申请大空间,使用huge_blocks_保存,和普通的block类似,只是申请和释放方法不一样。
char* Arena::AllocateFromHugePage(size_t bytes) {
#ifdef MAP_HUGETLB
if (hugetlb_size_ == 0) {
return nullptr;
}
// Reserve space in `huge_blocks_` before calling `mmap`.
// Use `emplace_back()` instead of `reserve()` to let std::vector manage its
// own memory and do fewer reallocations.
//
// - If `emplace_back` throws, no memory leaks because we haven't called
// `mmap` yet.
// - If `mmap` throws, no memory leaks because the vector will be cleaned up
// via RAII.
huge_blocks_.emplace_back(nullptr /* addr */, 0 /* length */);
void* addr = mmap(nullptr, bytes, (PROT_READ | PROT_WRITE),
(MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB), -1, 0);
if (addr == MAP_FAILED) {
return nullptr;
}
huge_blocks_.back() = MmapInfo(addr, bytes);
blocks_memory_ += bytes;
if (tracker_ != nullptr) {
tracker_->Allocate(bytes);
}
return reinterpret_cast<char*>(addr);
#else
(void)bytes;
return nullptr;
#endif
}
SkipList
和levelDB类似,但是有几个优化点
- 保存prev进行快速insert,因为insert的数据很大程度上具有局部性,所以使用保存的prev可能避免重新查找
- 跳表是概率均衡,一般使用概率为0.25,他在估计表大小的是时候,没有直接遍历第0层计算,他从上到下,如多高度下降,测count*4,此时可以大致的统计出跳表小于key的数量
template <typename Key, class Comparator>
uint64_t SkipList<Key, Comparator>::EstimateCount(const Key& key) const {
uint64_t count = 0;
Node* x = head_;
int level = GetMaxHeight() - 1;
while (true) {
assert(x == head_ || compare_(x->key, key) < 0);
Node* next = x->Next(level);
if (next == nullptr || compare_(next->key, key) >= 0) {
if (level == 0) {
return count;
} else {
// Switch to next list
count *= kBranching_;
level--;
}
} else {
x = next;
count++;
}
}
}
MemTable
Read other posts