leveldb 学习记录(四) skiplist补与变长数字
在leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明
这里在介绍 下skiplist的代码
里面有几个模块
template<typename Key, class Comparator>
class SkipList {......}
class Arena;(内存池模块 暂时不介绍)
struct Node;(节点 存储key 和指向其他Node的指针)
//Node 构造函数 KEY赋值 // Implementation details follow template<typename Key, class Comparator> struct SkipList<Key,Comparator>::Node { explicit Node(const Key& k) : key(k) { } Key const key; // Accessors/mutators for links. Wrapped in methods so we can // add the appropriate barriers as necessary. // 访问修改器使用 包装在方法中 可以使用内存屏障 // Node指向的另一层? Node* Next(int n) { assert(n >= 0); // Use an 'acquire load' so that we observe a fully initialized // version of the returned Node. return reinterpret_cast<Node*>(next_[n].Acquire_Load()); } //设置下层Node指向 void SetNext(int n, Node* x) { assert(n >= 0); // Use a 'release store' so that anybody who reads through this // pointer observes a fully initialized version of the inserted node. next_[n].Release_Store(x); } // No-barrier variants that can be safely used in a few locations. // 读取本Node在N层的NODE指向 非内存屏蔽操作 Node* NoBarrier_Next(int n) { assert(n >= 0); return reinterpret_cast<Node*>(next_[n].NoBarrier_Load()); } //设置Node 在N层的Node指向 非内存屏蔽操作 void NoBarrier_SetNext(int n, Node* x) { assert(n >= 0); next_[n].NoBarrier_Store(x); } private: // Array of length equal to the node height. next_[0] is lowest level link. // 原子指针数组 指向其他Node 创建时候动态确认数组长度 port::AtomicPointer next_[1]; };
结构示意图如下
其他操作可参见系列文章一
最后附上我注释的代码
1 #include <assert.h> 2 #include <stdlib.h> 3 #include "port/port.h" 4 #include "util/arena.h" 5 #include "util/random.h" 6 7 namespace leveldb { 8 9 class Arena; 10 11 template<typename Key, class Comparator> 12 class SkipList { 13 private: 14 struct Node; 15 16 public: 17 // Create a new SkipList object that will use "cmp" for comparing keys, 18 // and will allocate memory using "*arena". Objects allocated in the arena 19 // must remain allocated for the lifetime of the skiplist object. 20 explicit SkipList(Comparator cmp, Arena* arena); 21 22 // Insert key into the list. 23 // REQUIRES: nothing that compares equal to key is currently in the list. 24 void Insert(const Key& key); 25 26 // Returns true iff an entry that compares equal to key is in the list. 27 bool Contains(const Key& key) const; 28 29 // Iteration over the contents of a skip list 30 class Iterator { 31 public: 32 // Initialize an iterator over the specified list. 33 // The returned iterator is not valid. 34 explicit Iterator(const SkipList* list); 35 36 // Returns true iff the iterator is positioned at a valid node. 37 bool Valid() const; 38 39 // Returns the key at the current position. 40 // REQUIRES: Valid() 41 const Key& key() const; 42 43 // Advances to the next position. 44 // REQUIRES: Valid() 45 void Next(); 46 47 // Advances to the previous position. 48 // REQUIRES: Valid() 49 void Prev(); 50 51 // Advance to the first entry with a key >= target 52 void Seek(const Key& target); 53 54 // Position at the first entry in list. 55 // Final state of iterator is Valid() iff list is not empty. 56 void SeekToFirst(); 57 58 // Position at the last entry in list. 59 // Final state of iterator is Valid() iff list is not empty. 60 void SeekToLast(); 61 62 private: 63 const SkipList* list_; 64 Node* node_; 65 // Intentionally copyable 66 }; 67 68 private: 69 enum { kMaxHeight = 12 }; 70 71 // Immutable after construction 72 Comparator const compare_; 73 Arena* const arena_; // Arena used for allocations of nodes 74 75 Node* const head_; 76 77 // Modified only by Insert(). Read racily by readers, but stale 78 // values are ok. 79 port::AtomicPointer max_height_; // Height of the entire list 80 81 inline int GetMaxHeight() const { 82 return reinterpret_cast<intptr_t>(max_height_.NoBarrier_Load()); 83 } 84 85 // Read/written only by Insert(). 86 Random rnd_; 87 88 Node* NewNode(const Key& key, int height); 89 int RandomHeight(); 90 bool Equal(const Key& a, const Key& b) const { return (compare_(a, b) == 0); } 91 92 // Return true if key is greater than the data stored in "n" 93 bool KeyIsAfterNode(const Key& key, Node* n) const; 94 95 // Return the earliest node that comes at or after key. 96 // Return NULL if there is no such node. 97 // 98 // If prev is non-NULL, fills prev[level] with pointer to previous 99 // node at "level" for every level in [0..max_height_-1]. 100 Node* FindGreaterOrEqual(const Key& key, Node** prev) const; 101 102 // Return the latest node with a key < key. 103 // Return head_ if there is no such node. 104 Node* FindLessThan(const Key& key) const; 105 106 // Return the last node in the list. 107 // Return head_ if list is empty. 108 Node* FindLast() const; 109 110 // No copying allowed 111 SkipList(const SkipList&); 112 void operator=(const SkipList&); 113 }; 114 115 116 //Node 构造函数 KEY赋值 117 // Implementation details follow 118 template<typename Key, class Comparator> 119 struct SkipList<Key,Comparator>::Node { 120 explicit Node(const Key& k) : key(k) { } 121 122 Key const key; 123 124 // Accessors/mutators for links. Wrapped in methods so we can 125 // add the appropriate barriers as necessary. 126 // 访问修改器使用 包装在方法中 可以使用内存屏障 127 // Node指向的另一层? 128 Node* Next(int n) { 129 assert(n >= 0); 130 // Use an 'acquire load' so that we observe a fully initialized 131 // version of the returned Node. 132 return reinterpret_cast<Node*>(next_[n].Acquire_Load()); 133 } 134 //设置下层Node指向 135 void SetNext(int n, Node* x) { 136 assert(n >= 0); 137 // Use a 'release store' so that anybody who reads through this 138 // pointer observes a fully initialized version of the inserted node. 139 next_[n].Release_Store(x); 140 } 141 142 // No-barrier variants that can be safely used in a few locations. 143 // 读取本Node在N层的NODE指向 非内存屏蔽操作 144 Node* NoBarrier_Next(int n) { 145 assert(n >= 0); 146 return reinterpret_cast<Node*>(next_[n].NoBarrier_Load()); 147 } 148 149 //设置Node 在N层的Node指向 非内存屏蔽操作 150 void NoBarrier_SetNext(int n, Node* x) { 151 assert(n >= 0); 152 next_[n].NoBarrier_Store(x); 153 } 154 155 private: 156 // Array of length equal to the node height. next_[0] is lowest level link. 157 // 原子指针数组 指向其他Node 创建时候动态确认数组长度 158 port::AtomicPointer next_[1]; 159 }; 160 161 162 //创建一个NODE 内存池arena_分配内存 height确认该NODE的Node指向数量 163 template<typename Key, class Comparator> 164 typename SkipList<Key,Comparator>::Node* 165 SkipList<Key,Comparator>::NewNode(const Key& key, int height) { 166 char* mem = arena_->AllocateAligned( 167 sizeof(Node) + sizeof(port::AtomicPointer) * (height - 1)); 168 return new (mem) Node(key); 169 } 170 171 //根据输入的SkipList指针构造一个 iterator 172 template<typename Key, class Comparator> 173 inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) { 174 list_ = list; 175 node_ = NULL; 176 } 177 178 // 179 template<typename Key, class Comparator> 180 inline bool SkipList<Key,Comparator>::Iterator::Valid() const { 181 return node_ != NULL; 182 } 183 184 185 //返回iterator指向的Node的key 186 template<typename Key, class Comparator> 187 inline const Key& SkipList<Key,Comparator>::Iterator::key() const { 188 assert(Valid()); 189 return node_->key; 190 } 191 192 193 //获取iterator指向的下一个node 在第0层获取(Node第0层均有记录) 194 template<typename Key, class Comparator> 195 inline void SkipList<Key,Comparator>::Iterator::Next() { 196 assert(Valid()); 197 node_ = node_->Next(0); 198 } 199 200 //寻找该node上一个node 201 template<typename Key, class Comparator> 202 inline void SkipList<Key,Comparator>::Iterator::Prev() { 203 // Instead of using explicit "prev" links, we just search for the 204 // last node that falls before key. 205 assert(Valid()); 206 node_ = list_->FindLessThan(node_->key); 207 if (node_ == list_->head_) { 208 node_ = NULL; 209 } 210 } 211 212 213 //调用 FindGreaterOrEqual 查找 214 template<typename Key, class Comparator> 215 inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) { 216 node_ = list_->FindGreaterOrEqual(target, NULL); 217 } 218 219 //重置到head Node 第0层 第一个Node 220 template<typename Key, class Comparator> 221 inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() { 222 node_ = list_->head_->Next(0); 223 } 224 225 //重置到last Node 226 template<typename Key, class Comparator> 227 inline void SkipList<Key,Comparator>::Iterator::SeekToLast() { 228 node_ = list_->FindLast(); 229 if (node_ == list_->head_) { 230 node_ = NULL; 231 } 232 } 233 234 235 //返回height 随机增加1 236 template<typename Key, class Comparator> 237 int SkipList<Key,Comparator>::RandomHeight() { 238 // Increase height with probability 1 in kBranching 239 static const unsigned int kBranching = 4; 240 int height = 1; 241 while (height < kMaxHeight && ((rnd_.Next() % kBranching) == 0)) { 242 height++; 243 } 244 assert(height > 0); 245 assert(height <= kMaxHeight); 246 return height; 247 } 248 249 //调用 cmp 比较是大小 250 template<typename Key, class Comparator> 251 bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const { 252 // NULL n is considered infinite 253 return (n != NULL) && (compare_(n->key, key) < 0); 254 } 255 256 257 //寻找比key大或者等于的Node 258 template<typename Key, class Comparator> 259 typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev) 260 const { 261 Node* x = head_; 262 int level = GetMaxHeight() - 1; 263 // k在Next后面 则在本level寻找 否则 在下一层level寻找 264 while (true) { 265 Node* next = x->(level); 266 if (KeyIsAfterNode(key, next)) { 267 // Keep searching in this list 268 x = next; 269 } else { 270 if (prev != NULL) prev[level] = x; 271 if (level == 0) { 272 return next; 273 } else { 274 // Switch to next list 275 level--; 276 } 277 } 278 } 279 } 280 281 282 //寻找小于等于KEY的第一个NODE 283 template<typename Key, class Comparator> 284 typename SkipList<Key,Comparator>::Node* 285 SkipList<Key,Comparator>::FindLessThan(const Key& key) const { 286 Node* x = head_; 287 int level = GetMaxHeight() - 1; 288 while (true) { 289 assert(x == head_ || compare_(x->key, key) < 0); 290 Node* next = x->Next(level); 291 if (next == NULL || compare_(next->key, key) >= 0) { 292 if (level == 0) { 293 return x; 294 } else { 295 // Switch to next list 296 level--; 297 } 298 } else { 299 x = next; 300 } 301 } 302 } 303 304 //在最高层 寻找最后一个Node 305 template<typename Key, class Comparator> 306 typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast() 307 const { 308 Node* x = head_; 309 int level = GetMaxHeight() - 1; 310 while (true) { 311 Node* next = x->Next(level); 312 if (next == NULL) { 313 if (level == 0) { 314 return x; 315 } else { 316 // Switch to next list 317 level--; 318 } 319 } else { 320 x = next; 321 } 322 } 323 } 324 325 326 //构建函数 第一个head Node key是0 后继Node指针最大kMaxHeight 327 template<typename Key, class Comparator> 328 SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena) 329 : compare_(cmp), 330 arena_(arena), 331 head_(NewNode(0 /* any key will do */, kMaxHeight)), 332 max_height_(reinterpret_cast<void*>(1)), 333 rnd_(0xdeadbeef) { 334 for (int i = 0; i < kMaxHeight; i++) { 335 head_->SetNext(i, NULL); 336 } 337 } 338 339 //insert算法 340 template<typename Key, class Comparator> 341 void SkipList<Key,Comparator>::Insert(const Key& key) { 342 // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual() 343 // here since Insert() is externally synchronized. 344 Node* prev[kMaxHeight]; 345 Node* x = FindGreaterOrEqual(key, prev); 346 347 // Our data structure does not allow duplicate insertion 348 assert(x == NULL || !Equal(key, x->key)); 349 350 int height = RandomHeight(); 351 if (height > GetMaxHeight()) { 352 for (int i = GetMaxHeight(); i < height; i++) { 353 prev[i] = head_; 354 } 355 //fprintf(stderr, "Change height from %d to %d\n", max_height_, height); 356 357 // It is ok to mutate max_height_ without any synchronization 358 // with concurrent readers. A concurrent reader that observes 359 // the new value of max_height_ will see either the old value of 360 // new level pointers from head_ (NULL), or a new value set in 361 // the loop below. In the former case the reader will 362 // immediately drop to the next level since NULL sorts after all 363 // keys. In the latter case the reader will use the new node. 364 max_height_.NoBarrier_Store(reinterpret_cast<void*>(height)); 365 } 366 367 x = NewNode(key, height); 368 for (int i = 0; i < height; i++) { 369 // NoBarrier_SetNext() suffices since we will add a barrier when 370 // we publish a pointer to "x" in prev[i]. 371 x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i)); 372 prev[i]->SetNext(i, x); 373 } 374 } 375 376 377 //寻找等于KEY 即可确认是否包含与KEY相等的Node 378 template<typename Key, class Comparator> 379 bool SkipList<Key,Comparator>::Contains(const Key& key) const { 380 Node* x = FindGreaterOrEqual(key, NULL); 381 if (x != NULL && Equal(key, x->key)) { 382 return true; 383 } else { 384 return false; 385 } 386 } 387 388 }
varint变长数
leveldb使用了Protocol Buffers的变长字节整形编码 每个字节中使用7位来表示数字 最高位用作他处
300的编码,编码后是两个字节:
它这个例子是每个字节左边是高位,可以看到每个字节的最高位是一个标识位,从左到右第一个字节是10101100,最高位是1,说明后面还有字节需要解码,然后第二个字节是00000010,最高位是0,后面没字节了。所以这两个字节就需要解码成一个整数,再往下看。
→ 010 1100 000 0010 //每个字节去掉最高位
→ 000 0010 010 1100 //字节序转换,两个字节互换位置
→ 000 0010 ++ 010 1100 //两个字节进行链接操作(不是相加)
→ 100101100 //合并后的结果,高位位0的部分截取掉
→ 256 + 32 + 8 + 4 = 300 //每个值为1的bit位乘以以2为底的幂,得出编码后的值
主要函数在
coding.h
extern void PutFixed32(std::string* dst, uint32_t value);
extern void PutFixed64(std::string* dst, uint64_t value);
extern void PutVarint32(std::string* dst, uint32_t value);
extern void PutVarint64(std::string* dst, uint64_t value);
extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value);
extern bool GetVarint32(Slice* input, uint32_t* value);
extern bool GetVarint64(Slice* input, uint64_t* value);
extern bool GetLengthPrefixedSlice(Slice* input, Slice* result);
extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v);
extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v);
extern int VarintLength(uint64_t v);
extern void EncodeFixed32(char* dst, uint32_t value);
extern void EncodeFixed64(char* dst, uint64_t value);
extern char* EncodeVarint32(char* dst, uint32_t value);
extern char* EncodeVarint64(char* dst, uint64_t value);
参考
https://www.cnblogs.com/onlytiancai/archive/2010/10/16/1853003.html
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力