memtable常驻于内存,需要按照key进行排序,通常意义上的话,可以使用二叉查找树来实现,跟进一步可以使用红黑树保证树的平衡,但是leveldb中使用了另外的一种数据结构:跳表Skip List。
memtable声明在db/memtable.h中,定义如下:
- class MemTable
- {
- public:
-
-
- explicit MemTable(const InternalKeyComparator& comparator);
-
-
- void Ref()
- {
- ++refs_;
- }
-
-
- void Unref()
- {
- --refs_;
- assert(refs_ >= 0);
- if (refs_ <= 0)
- {
- delete this;
- }
- }
-
-
-
-
-
-
-
- size_t ApproximateMemoryUsage();
-
-
-
-
-
-
-
-
- Iterator* NewIterator();
-
-
-
-
-
-
-
- void Add(SequenceNumber seq, ValueType type,
- const Slice& key,
- const Slice& value);
-
-
-
-
-
-
- bool Get(const LookupKey& key, std::string* value, Status* s);
-
- private:
-
- ~MemTable();
-
- struct KeyComparator
- {
- const InternalKeyComparator comparator;
- explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { }
- int operator()(const char* a, const char* b) const;
- };
-
- friend class MemTableIterator;
- friend class MemTableBackwardIterator;
-
-
- typedef SkipList<const char*, KeyComparator> Table;
-
-
- KeyComparator comparator_;
-
- int refs_;
-
-
- Arena arena_;
-
- Table table_;
-
-
- MemTable(const MemTable&);
- void operator=(const MemTable&);
- };
这里面有几个注意点,首先Arena对象实现了一套leveldb的内存管理策略,将在下面的文章中进行分析,这里仅仅将其想象成一个内存分配器即可;另外就是Table类型(实际上就是SkipList类型)也将在下面的文章中进行分析。下面主要关注memtable初始化、插入key、查询key,由于LSM模型中memtable中没有数据的“实际”删除,这里并没有实现删除方法。
初始化函数定义如下:
- MemTable::MemTable(const InternalKeyComparator& cmp)
- : comparator_(cmp),
- refs_(0),
- table_(comparator_, &arena_)
- {
- }
就是简单的完成refs_和table_的初始化。插入的函数定义如下:
- void MemTable:Add(SequenceNumber s, ValueType type,
- const Slice& key,
- const Slice& value)
- {
-
-
-
-
-
-
-
-
- size_t key_size = key.size();
- size_t val_size = value.size();
- size_t internal_key_size = key_size + 8;
- const size_t encoded_len =
- VarintLength(internal_key_size) + internal_key_size +
- VarintLength(val_size) + val_size;
- char* buf = arena_.Allocate(encoded_len);
- char* p = EncodeVarint32(buf, internal_key_size);
- memcpy(p, key.data(), key_size);
- p += key_size;
- EncodeFixed64(p, (s << 8) | type);
- p += 8;
- p = EncodeVarint32(p, val_size);
- memcpy(p, value.data(), val_size);
- assert((p + val_size) - buf == encoded_len);
-
-
- table_.Insert(buf);
- }
思路上相对比较简单,首先对用户传递进来的kv进行格式化,之后调用table_的Insert方法插入到数据库中,需要注意:1. 新出现了Slice类型,基本上和std::string类型向类似,代码比较简单,这里略过;2. 用户传递进来的kv最终被封装到了一个char数组中,格式为key_size, key_bytes, (sequence_number << 8)|type,value_size, value_bytes(其中并没有,这里仅仅是为了区分)。
查询的操作代码如下:
- bool MemTable::Get(const LookupKey& key, std::string* value, Status* s)
- {
- Slice memkey = key.memtable_key();
- Table::Iterator iter(&table_);
-
- iter.Seek(memkey.data());
- if (iter.Valid())
- {
-
-
-
-
-
-
-
-
-
- const char* entry = iter.key();
- uint32_t key_length;
- const char* key_ptr = GetVarint32Ptr(entry, entry+5, &key_length);
- if (comparator_.comparator.user_comparator()->Compare(
- Slice(key_ptr, key_length - 8),
- key.user_key()) == 0)
- {
-
- const uint64_t tag = DecodeFixed64(key_ptr + key_length - 8);
- switch (static_cast<ValueType>(tag & 0xff))
- {
- case kTypeValue:
- {
- Slice v = GetLengthPrefixedSlice(key_ptr + key_length);
- value->assign(v.data(), v.size());
- return true;
- }
- case kTypeDeletion:
- *s = Status::NotFound(Slice());
- return true;
- }
- }
- }
- return false;
- }
Get函数内首先通过Table查找key,如果找到该key,解析key的内容,如果是kTypeValue类型的,返回给客户端查找到的value,如果是kTypeDeletion类型的(参考leveldb源代码分析:理论基础),返回给客户端表明没有找到。这里需要注意的是Get的参数中使用了LookupKey,该类型实际上就是在用户输入的key/value和leveldb内部使用key的起到桥梁的作用,定义如下:
- class LookupKey{
- public:
-
-
- LookupKey(const Slice& user_key, SequenceNumber sequence);
-
- ~LookupKey();
-
-
- Slice memtable_key() const { return Slice(start_, end_ - start_); }
-
-
- Slice internal_key() const { return Slice(kstart_, end_ - kstart_); }
-
-
- Slice user_key() const { return Slice(kstart_, end_ - kstart_ - 8); }
-
- private:
-
-
-
-
-
-
-
- const char* start_;
- const char* kstart_;
- const char* end_;
- char space_[200];
-
-
- LookupKey(const LookupKey&);
- void operator=(const LookupKey&);
- };
至此基本上memtable的初始化、读取、插入的操作分析完了,未解决问题如下:
1. SkipList数据结构
2. Arena内存分配策略
leveldb memtable,布布扣,bubuko.com
leveldb memtable
原文:http://www.cnblogs.com/shenzhaohai1989/p/3904166.html