内存数据库
leveldb内存数据库基于跳表结构。
跳表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| template <typename Key, class Comparator> class SkipList { private: struct Node; }
template <typename Key, class Comparator> struct SkipList<Key, Comparator>::Node { explicit Node(const Key& k) : key(k) {} const Key key; Node* Next(int n) { assert(n >= 0); return next_[n].load(std::memory_order_acquire); } void SetNext(int n, Node* x) { assert(n >= 0); next_[n].store(x, std::memory_order_release); } Node* NoBarrier_Next(int n) { assert(n >= 0); return next_[n].load(std::memory_order_relaxed); } void NoBarrier_SetNext(int n, Node* x) { assert(n >= 0); next_[n].store(x, std::memory_order_relaxed); }
private: std::atomic<Node*> next_[1]; };
|
memory_order 说明
- memory_order_relaxed: 只确保操作是原子性的,不对内存顺序做任何保证。
- memory_order_release: 用于写操作,例如
std::atomic::store(T, memory_order_release)
,会在写操作之前插入一个 StoreStore屏障,确保屏障之前的所有操作不会重排到屏障之后。
- memory_order_acquire: 用于读操作,例如
std::atomic::load(memory_order_acquire)
,会在读操作之后插入一个 LoadLoad 屏障,确保屏障之后的所有操作不会重排到屏障之前。
- memory_order_acq_rel: 等效于
memory_order_acquire
和 memory_order_release
的结合,同时插入一个 StoreStore 屏障与 LoadLoad 屏障,用于读写操作,例如 std::atomic::fetch_add(T, memory_order_acq_rel)
。
示例
1 2 3 4 5 6 7
| node->data = 42; list.SetNext(0, node);
Node* node = list.Next(0); int value = node->data;
|
编译器优化:编译器可能会认为,node->data = 42
和 list.SetNext(0, node)
没有直接依赖关系。因此,它可能将 list.SetNext(0, node)
提前。编译器这种优化是合法的,因为在单线程语境下,它认为不会改变行为。
模板例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| template <typename T> class Example { public: struct NestedType {}; static int value; };
template <typename T> void Func() { typename Example<T>::NestedType* ptr; Example<T>::value = 42; }
~~~c++ template <typename Key, class Comparator> typename SkipList<Key, Comparator>::Node* SkipList<Key, Comparator>::NewNode( const Key& key, int height) { char* const node_memory = arena_->AllocateAligned( sizeof(Node) + sizeof(std::atomic<Node*>) * (height - 1)); return new (node_memory) Node(key); }
|
跳表的查找
- 根据跳表高度选取最高层的头节点;
- 若小于,取该层的下一个节点;
- 若等于,则直接返回;
- 若大于且层高不为0,降低层高继续查找。
跳表的插入
- 查找过程中,不断记录每层的前任节点;
- 为新节点随机生成层高,并根据前任节点信息,将节点插入到层的链表中;
1 2 3 4 5 6 7 8 9
| graph TD subgraph MemTable_System ["MemTable 系统"] MemTable --> SkipList MemTable --> Arena SkipList --> Entry Entry --> Arena SkipList --> KeyComparator end
|