leveldb注释7–key与value
来源:互联网 发布:windows loader 2.4 编辑:程序博客网 时间:2024/06/11 19:22
作为一个kv的系统,key的存储至关重要。在leveldb中,主要涉及到如下几个key,user_key、InternalKey与LookupKey(memtable_key)。
其关系构成如下图。user_key就是用户输入的key,而InternalKey在user_key的基础上封装了sequence_num+type。sequence_num是一个全局递增的序列号,每一次Put操作都会递增。这样,不同时间的写入操作会得到不一样的sequence_num。前面章节中提到的sstable单条record中的key,其内部其实就是一个InternalKey。sequence_num主要跟snapshot机制与version机制相关,对压缩会产生一定影响。这些我们在后续章节分析。根据type字段,可以获知本次写入操作是写还是删除(也就是说删除是一种特殊的写)。而LookupKey/memtable_key用于在memtable中,多了一个长度字段。代码主要在dbformat.cc/.h中。
static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) { assert(seq <= kMaxSequenceNumber); assert(t <= kValueTypeForSeek); return (seq << \8) | t;}
skiplist中的单个节点不仅存储了Key,也存储了value。格式如下图。尽管单个节点的开头部分是一个LookupKey,但其内部比较时,还是使用的InternalKey。也就是说,比较时,先使用InternalKey内部的user_key进行比较,再比较sequence_num。这样不管是memtable还是sstable文件,其内部都是按InternalKey有序的。
int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const { // Order by: // increasing user key (according to user-supplied comparator) // decreasing sequence number // decreasing type (though sequence# should be enough to disambiguate) int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey)); if (r == 0) { const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8); const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8); if (anum > bnum) { r = -1; } else if (anum < bnum) { r = +1; } } return r;}
在进行Get操作时,leveldb会使用用户传入的user_key与当前db最大的sequence_num进行合并,以得到LookupKey(实际还会受snapshot机制影响)。但在内部查找时还是使用的InternalKey。
Put操作会稍微复杂点。leveldb的3种写入操作最终都会封装成WriteBatch。这3种写入操作分别是Put(写入单条key
/value)、Delete(删除单条key)、Write(批量进行Put与Delete操作)。WriteBath的内部格式如下图。WriteBatch所表示的多条记录最终会按SkipList所要求的格式1条条地顺序插入到memtable中。
Status WriteBatchInternal::InsertInto(const WriteBatch* b, MemTable* memtable) { MemTableInserter inserter; // memtable 的初始sequence为WriteBatchInternal中的seq inserter.sequence_ = WriteBatchInternal::Sequence(b); inserter.mem_ = memtable; return b->Iterate(&inserter);}Status WriteBatch::Iterate(Handler* handler) const { Slice input(rep_); if (input.size() < kHeader) { return Status::Corruption("malformed WriteBatch (too small)"); } // kHeader=12 = seq(8字节) + count(4字节) input.remove_prefix(kHeader); Slice key, value; int found = 0; while (!input.empty()) { found++; char tag = input[0]; // type:1字节 input.remove_prefix(1); switch (tag) { case kTypeValue: if (GetLengthPrefixedSlice(&input, &key) && GetLengthPrefixedSlice(&input, &value)) { handler->Put(key, value); } else { return Status::Corruption("bad WriteBatch Put"); } break; case kTypeDeletion: if (GetLengthPrefixedSlice(&input, &key)) { handler->Delete(key); } else { return Status::Corruption("bad WriteBatch Delete"); } break; default: return Status::Corruption("unknown WriteBatch tag"); } } if (found != WriteBatchInternal::Count(this)) { return Status::Corruption("WriteBatch has wrong count"); } else { return Status::OK(); }}
关于读写压缩等对key/value的具体操作,我们在后续章节进行分析,这里只需要了解大概。
- leveldb注释7–key与value
- LevelDB:一个快速轻量级的key-value存储库(译)
- LevelDB:一个快速轻量级的key-value存储库(译)
- riser服务key/value服务介绍-基于leveldb
- LevelDB:一个快速轻量级的key-value存储库(译)
- 高性能Key/Value存储引擎levelDB, rocksDB, sessionDB
- LevelDB:一个快速轻量级的key-value存储库(译)
- LevelDB:一个快速轻量级的key-value存储库(译)
- 遍历对象key与value
- map 遍历key 与 value
- leveldb源码剖析--key-value形式的Block块中的数据存储格式
- 第7章 Key-Value Coding; Key-Value Observing
- HashMap同时遍历key与value
- Map的key,value与null简例
- Map遍历取得Key与Value
- js取object的key与value
- System.getProperties的key与value.
- Key 与 Value 并发的Cache 设计
- Git学习与训练
- 前端两个页面之间传递值的方法
- Js Switch语句
- JSON
- javascript学习之函数(8)—— 函数 参数传递
- leveldb注释7–key与value
- Docker初识之Centos6.2下安装Docker容器
- 大数据的大公司
- 数组名在作为形参传递时的注意事项
- 程序员修炼之道-从小工到专家读后感
- 2016年年终总结
- centOs下安装jdk
- Actor模型
- JS的闭包 (一)——为什么要用闭包