本文简要说明了block和footer中的代码实现,其中带有注释和部分讲解
blockbuilder
blockbuilder的结构
class BlockBuilder {
// 存放的就是按照输出的格式进行处理好的内存区域
std::string buffer_;
// 同一个restart区域就是属于group的区域, 内部的key只是会存放non-shared的部分
std::vector<uint32_t> restarts_;
// 所有的entries的数目
int counter_;
// 是否是finish了, Finish() called
bool finished_;
//最后一个key?
std::string last_key_;
};
Entry
: 保存具体的key, value数据,当然是no-shared
Restart
:保存每条restart 索引RestartNum
: restart的数目,能够找到restart的 起点
BlockBuilder::BlockBuilder(const Options* options)
: options_(options), restarts_(), counter_(0), finished_(false)
{
assert(options->block_restart_interval >= 1);
restarts_.push_back(0); // 第一个重启点的Offset是0
}
Slice BlockBuilder::Finish() {
// 结束了key value 的插入,restart代表着索引啥的,插入进去
for (int i = 0; i < restarts_.size(); i++) {
PutFixed32(&buffer_, restarts_[i]);
}
PutFixed32(&buffer_, restarts_.size()); // 这样就能够确认首个restart的位置
finished_ = true;
return Slice(buffer_);
}
size_t BlockBuilder::CurrentSizeEstimate() const {
return buffer_.size() + restarts_.size() * sizeof(uint32_t) + sizeof(uint32_t);
}
void BlockBuilder::Reset() {
buffer_.clear();
restarts_.clear();
restarts_.push_back(0);
counter_ = 0;
finished_ = false;
last_key_.clear();
}
// 将Key, Value按照SST的格式写进buffer中
void BlockBuilder::Add(const Slice& key, const Slice& value) {
Slice last_key_slice(last_key_);
assert(!finished_);
assert(counter_ <= options_->block_restart_interval);
// 下面是要保证传入的key是有序的,
assert(buffer_.empty() || options_->comparator->Compare(key, last_key_slice) > 0);
size_t shared = 0;
if (counter_ < options_->block_restart_interval) {
// 看一下相同的前缀的长度
const size_t minlen = std::min(last_key_slice.size(), key.size());
while (shared < minlen && last_key_slice[shared] == key[shared])
shared++;
} else {
// 那就是重启了一个group?
restarts_.push_back(buffer_.size());
counter_ = 0;
}
const size_t no_shared = key.size() - shared;
PutVarint32(&buffer_, shared);
PutVarint32(&buffer_, no_shared);
PutVarint32(&buffer_, value.size());
// 将具体的key value存放进去
buffer_.append(key.data() + shared, no_shared);
buffer_.append(value.data(), value.size());
last_key_.resize(shared);
last_key_.append(key.data() + shared, no_shared);
assert(Slice(last_key_) == key);
counter_++;
}
Footer
Footer
就是 block 中最后的部分【metaIndex, index】, 最后以 魔数为结尾。我们读取 block的时候就是从这里开始读取和解析的,其中编码和解码的处理还是很哇塞的🤩
void BlockHandle::EncodeTo(std::string *dst) const {
PutVarint64(dst, offset_); // 内部调用的是append
PutVarint64(dst, size_);
}
Status BlockHandle::DecodeFrom(Slice* input) {
if (GetVarint64(input, &offset_) && GetVarint64(input, &size_)) {
// get之后内部会更改一下input,移动一下齐起始的位置
return Status::OK();
} else {
return Status::Corruption("bad block handle");
}
}
// 将footer写进dst中
void Footer::EncodeTo(std::string* dst) const {
const int originsize = dst->size();
// 1.将index[s] 放进去
metaIndex_handle_.EncodeTo(dst);
index_handle_.EncodeTo(dst);
// 2.Padding
dst->resize(2 * BlockHandle::kMaxEncodedLength);
// 3.MagicNumber
PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber & 0xffffffffu));
PutFixed32(dst, static_cast<uint32_t>(kTableMagicNumber >> 32));
assert(originsize + kEncodedLen == dst->size());
(void)originsize; // 清除掉Warning
}
// 解析
Status Footer::DecodeFrom(Slice* input) {
// 1.我们首先解析魔数
const char* magic_ptr = input->data() + kEncodedLen - 8; // 魔数的起始位置
uint32_t Magic_Number_Low = DecodeFixed32(magic_ptr);
uint32_t Magic_Number_Hig = DecodeFixed32(magic_ptr + 4);
uint64_t Magic_Number = static_cast<uint64_t>(Magic_Number_Hig << 32) | static_cast<uint64_t>(Magic_Number_Low);
if (Magic_Number != kTableMagicNumber) {
return Status::Corruption("not an sstable(bad magic numer)");
}
// 2.解析metahandle & indexhandle
Status result = metaIndex_handle_.DecodeFrom(input);
if (result.ok()) {
result = index_handle_.DecodeFrom(input);
}
// 3.去除掉padding
if (result.ok()) {
const char* end = magic_ptr + 8;
*input = Slice(end, input->data() + input->size() - end);
}
return result;
}