#include "table/block_based/data_block_footer.h"
#include "util/coding.h"
namespace ROCKSDB_NAMESPACE {
constexpr uint32_t kHashIndexBit = 1u << 31;
constexpr uint32_t kSeparatedKVBit = 1u << 28;
void DataBlockFooter::EncodeTo(std::string* dst) const {
assert(num_restarts <= kMaxNumRestarts);
if (separated_kv) {
PutFixed32(dst, values_section_offset);
}
uint32_t packed = num_restarts;
if (index_type == BlockBasedTableOptions::kDataBlockBinaryAndHash) {
packed |= kHashIndexBit;
} else {
assert(index_type == BlockBasedTableOptions::kDataBlockBinarySearch);
}
if (separated_kv) {
packed |= kSeparatedKVBit;
}
PutFixed32(dst, packed);
}
Status DataBlockFooter::DecodeFrom(Slice* input) {
if (input->size() < kMinEncodedLength) {
return Status::Corruption("Block too small for footer");
}
const char* footer_ptr = input->data() + input->size() - sizeof(uint32_t);
uint32_t packed = DecodeFixed32(footer_ptr);
if (packed & kHashIndexBit) {
index_type = BlockBasedTableOptions::kDataBlockBinaryAndHash;
packed &= ~kHashIndexBit;
} else {
index_type = BlockBasedTableOptions::kDataBlockBinarySearch;
}
if (packed & kSeparatedKVBit) {
separated_kv = true;
packed &= ~kSeparatedKVBit;
} else {
separated_kv = false;
}
if (packed > kMaxNumRestarts) {
return Status::Corruption(
"Unrecognized feature in block footer (reserved bits set)");
}
num_restarts = packed;
input->remove_suffix(sizeof(uint32_t));
if (separated_kv) {
if (input->size() < sizeof(uint32_t)) {
return Status::Corruption(
"Block too small for separated KV values section offset");
}
values_section_offset =
DecodeFixed32(input->data() + input->size() - sizeof(uint32_t));
input->remove_suffix(sizeof(uint32_t));
}
return Status::OK();
}
}