leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明

这里在介绍 下skiplist的代码

里面有几个模块

template<typename Key, class Comparator>
class SkipList {......}

class Arena;(内存池模块 暂时不介绍)

struct Node;(节点 存储key 和指向其他Node的指针)

  1. //Node 构造函数 KEY赋值
  2. // Implementation details follow
  3. template<typename Key, class Comparator>
  4. struct SkipList<Key,Comparator>::Node {
  5. explicit Node(const Key& k) : key(k) { }
  6.  
  7. Key const key;
  8.  
  9. // Accessors/mutators for links. Wrapped in methods so we can
  10. // add the appropriate barriers as necessary.
  11. // 访问修改器使用 包装在方法中 可以使用内存屏障
  12. // Node指向的另一层?
  13. Node* Next(int n) {
  14. assert(n >= 0);
  15. // Use an 'acquire load' so that we observe a fully initialized
  16. // version of the returned Node.
  17. return reinterpret_cast<Node*>(next_[n].Acquire_Load());
  18. }
  19. //设置下层Node指向
  20. void SetNext(int n, Node* x) {
  21. assert(n >= 0);
  22. // Use a 'release store' so that anybody who reads through this
  23. // pointer observes a fully initialized version of the inserted node.
  24. next_[n].Release_Store(x);
  25. }
  26.  
  27. // No-barrier variants that can be safely used in a few locations.
  28. // 读取本Node在N层的NODE指向 非内存屏蔽操作
  29. Node* NoBarrier_Next(int n) {
  30. assert(n >= 0);
  31. return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
  32. }
  33.  
  34. //设置Node 在N层的Node指向 非内存屏蔽操作
  35. void NoBarrier_SetNext(int n, Node* x) {
  36. assert(n >= 0);
  37. next_[n].NoBarrier_Store(x);
  38. }
  39.  
  40. private:
  41. // Array of length equal to the node height. next_[0] is lowest level link.
  42. // 原子指针数组 指向其他Node 创建时候动态确认数组长度
  43. port::AtomicPointer next_[1];
  44. };

  

结构示意图如下

其他操作可参见系列文章一

最后附上我注释的代码

  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 = };
  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) == ); }
  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. //Node 构造函数 KEY赋值
  116. // Implementation details follow
  117. template<typename Key, class Comparator>
  118. struct SkipList<Key,Comparator>::Node {
  119. explicit Node(const Key& k) : key(k) { }
  120.  
  121. Key const key;
  122.  
  123. // Accessors/mutators for links. Wrapped in methods so we can
  124. // add the appropriate barriers as necessary.
  125. // 访问修改器使用 包装在方法中 可以使用内存屏障
  126. // Node指向的另一层?
  127. Node* Next(int n) {
  128. assert(n >= );
  129. // Use an 'acquire load' so that we observe a fully initialized
  130. // version of the returned Node.
  131. return reinterpret_cast<Node*>(next_[n].Acquire_Load());
  132. }
  133. //设置下层Node指向
  134. void SetNext(int n, Node* x) {
  135. assert(n >= );
  136. // Use a 'release store' so that anybody who reads through this
  137. // pointer observes a fully initialized version of the inserted node.
  138. next_[n].Release_Store(x);
  139. }
  140.  
  141. // No-barrier variants that can be safely used in a few locations.
  142. // 读取本Node在N层的NODE指向 非内存屏蔽操作
  143. Node* NoBarrier_Next(int n) {
  144. assert(n >= );
  145. return reinterpret_cast<Node*>(next_[n].NoBarrier_Load());
  146. }
  147.  
  148. //设置Node 在N层的Node指向 非内存屏蔽操作
  149. void NoBarrier_SetNext(int n, Node* x) {
  150. assert(n >= );
  151. next_[n].NoBarrier_Store(x);
  152. }
  153.  
  154. private:
  155. // Array of length equal to the node height. next_[0] is lowest level link.
  156. // 原子指针数组 指向其他Node 创建时候动态确认数组长度
  157. port::AtomicPointer next_[];
  158. };
  159.  
  160. //创建一个NODE 内存池arena_分配内存 height确认该NODE的Node指向数量
  161. template<typename Key, class Comparator>
  162. typename SkipList<Key,Comparator>::Node*
  163. SkipList<Key,Comparator>::NewNode(const Key& key, int height) {
  164. char* mem = arena_->AllocateAligned(
  165. sizeof(Node) + sizeof(port::AtomicPointer) * (height - ));
  166. return new (mem) Node(key);
  167. }
  168.  
  169. //根据输入的SkipList指针构造一个 iterator
  170. template<typename Key, class Comparator>
  171. inline SkipList<Key,Comparator>::Iterator::Iterator(const SkipList* list) {
  172. list_ = list;
  173. node_ = NULL;
  174. }
  175.  
  176. //
  177. template<typename Key, class Comparator>
  178. inline bool SkipList<Key,Comparator>::Iterator::Valid() const {
  179. return node_ != NULL;
  180. }
  181.  
  182. //返回iterator指向的Node的key
  183. template<typename Key, class Comparator>
  184. inline const Key& SkipList<Key,Comparator>::Iterator::key() const {
  185. assert(Valid());
  186. return node_->key;
  187. }
  188.  
  189. //获取iterator指向的下一个node 在第0层获取(Node第0层均有记录)
  190. template<typename Key, class Comparator>
  191. inline void SkipList<Key,Comparator>::Iterator::Next() {
  192. assert(Valid());
  193. node_ = node_->Next();
  194. }
  195.  
  196. //寻找该node上一个node
  197. template<typename Key, class Comparator>
  198. inline void SkipList<Key,Comparator>::Iterator::Prev() {
  199. // Instead of using explicit "prev" links, we just search for the
  200. // last node that falls before key.
  201. assert(Valid());
  202. node_ = list_->FindLessThan(node_->key);
  203. if (node_ == list_->head_) {
  204. node_ = NULL;
  205. }
  206. }
  207.  
  208. //调用 FindGreaterOrEqual 查找
  209. template<typename Key, class Comparator>
  210. inline void SkipList<Key,Comparator>::Iterator::Seek(const Key& target) {
  211. node_ = list_->FindGreaterOrEqual(target, NULL);
  212. }
  213.  
  214. //重置到head Node 第0层 第一个Node
  215. template<typename Key, class Comparator>
  216. inline void SkipList<Key,Comparator>::Iterator::SeekToFirst() {
  217. node_ = list_->head_->Next();
  218. }
  219.  
  220. //重置到last Node
  221. template<typename Key, class Comparator>
  222. inline void SkipList<Key,Comparator>::Iterator::SeekToLast() {
  223. node_ = list_->FindLast();
  224. if (node_ == list_->head_) {
  225. node_ = NULL;
  226. }
  227. }
  228.  
  229. //返回height 随机增加1
  230. template<typename Key, class Comparator>
  231. int SkipList<Key,Comparator>::RandomHeight() {
  232. // Increase height with probability 1 in kBranching
  233. static const unsigned int kBranching = ;
  234. int height = ;
  235. while (height < kMaxHeight && ((rnd_.Next() % kBranching) == )) {
  236. height++;
  237. }
  238. assert(height > );
  239. assert(height <= kMaxHeight);
  240. return height;
  241. }
  242.  
  243. //调用 cmp 比较是大小
  244. template<typename Key, class Comparator>
  245. bool SkipList<Key,Comparator>::KeyIsAfterNode(const Key& key, Node* n) const {
  246. // NULL n is considered infinite
  247. return (n != NULL) && (compare_(n->key, key) < );
  248. }
  249.  
  250. //寻找比key大或者等于的Node
  251. template<typename Key, class Comparator>
  252. typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindGreaterOrEqual(const Key& key, Node** prev)
  253. const {
  254. Node* x = head_;
  255. int level = GetMaxHeight() - ;
  256. // k在Next后面 则在本level寻找 否则 在下一层level寻找
  257. while (true) {
  258. Node* next = x->(level);
  259. if (KeyIsAfterNode(key, next)) {
  260. // Keep searching in this list
  261. x = next;
  262. } else {
  263. if (prev != NULL) prev[level] = x;
  264. if (level == ) {
  265. return next;
  266. } else {
  267. // Switch to next list
  268. level--;
  269. }
  270. }
  271. }
  272. }
  273.  
  274. //寻找小于等于KEY的第一个NODE
  275. template<typename Key, class Comparator>
  276. typename SkipList<Key,Comparator>::Node*
  277. SkipList<Key,Comparator>::FindLessThan(const Key& key) const {
  278. Node* x = head_;
  279. int level = GetMaxHeight() - ;
  280. while (true) {
  281. assert(x == head_ || compare_(x->key, key) < );
  282. Node* next = x->Next(level);
  283. if (next == NULL || compare_(next->key, key) >= ) {
  284. if (level == ) {
  285. return x;
  286. } else {
  287. // Switch to next list
  288. level--;
  289. }
  290. } else {
  291. x = next;
  292. }
  293. }
  294. }
  295.  
  296. //在最高层 寻找最后一个Node
  297. template<typename Key, class Comparator>
  298. typename SkipList<Key,Comparator>::Node* SkipList<Key,Comparator>::FindLast()
  299. const {
  300. Node* x = head_;
  301. int level = GetMaxHeight() - ;
  302. while (true) {
  303. Node* next = x->Next(level);
  304. if (next == NULL) {
  305. if (level == ) {
  306. return x;
  307. } else {
  308. // Switch to next list
  309. level--;
  310. }
  311. } else {
  312. x = next;
  313. }
  314. }
  315. }
  316.  
  317. //构建函数 第一个head Node key是0 后继Node指针最大kMaxHeight
  318. template<typename Key, class Comparator>
  319. SkipList<Key,Comparator>::SkipList(Comparator cmp, Arena* arena)
  320. : compare_(cmp),
  321. arena_(arena),
  322. head_(NewNode( /* any key will do */, kMaxHeight)),
  323. max_height_(reinterpret_cast<void*>()),
  324. rnd_(0xdeadbeef) {
  325. for (int i = ; i < kMaxHeight; i++) {
  326. head_->SetNext(i, NULL);
  327. }
  328. }
  329.  
  330. //insert算法
  331. template<typename Key, class Comparator>
  332. void SkipList<Key,Comparator>::Insert(const Key& key) {
  333. // TODO(opt): We can use a barrier-free variant of FindGreaterOrEqual()
  334. // here since Insert() is externally synchronized.
  335. Node* prev[kMaxHeight];
  336. Node* x = FindGreaterOrEqual(key, prev);
  337.  
  338. // Our data structure does not allow duplicate insertion
  339. assert(x == NULL || !Equal(key, x->key));
  340.  
  341. int height = RandomHeight();
  342. if (height > GetMaxHeight()) {
  343. for (int i = GetMaxHeight(); i < height; i++) {
  344. prev[i] = head_;
  345. }
  346. //fprintf(stderr, "Change height from %d to %d\n", max_height_, height);
  347.  
  348. // It is ok to mutate max_height_ without any synchronization
  349. // with concurrent readers. A concurrent reader that observes
  350. // the new value of max_height_ will see either the old value of
  351. // new level pointers from head_ (NULL), or a new value set in
  352. // the loop below. In the former case the reader will
  353. // immediately drop to the next level since NULL sorts after all
  354. // keys. In the latter case the reader will use the new node.
  355. max_height_.NoBarrier_Store(reinterpret_cast<void*>(height));
  356. }
  357.  
  358. x = NewNode(key, height);
  359. for (int i = ; i < height; i++) {
  360. // NoBarrier_SetNext() suffices since we will add a barrier when
  361. // we publish a pointer to "x" in prev[i].
  362. x->NoBarrier_SetNext(i, prev[i]->NoBarrier_Next(i));
  363. prev[i]->SetNext(i, x);
  364. }
  365. }
  366.  
  367. //寻找等于KEY 即可确认是否包含与KEY相等的Node
  368. template<typename Key, class Comparator>
  369. bool SkipList<Key,Comparator>::Contains(const Key& key) const {
  370. Node* x = FindGreaterOrEqual(key, NULL);
  371. if (x != NULL && Equal(key, x->key)) {
  372. return true;
  373. } else {
  374. return false;
  375. }
  376. }
  377.  
  378. }

varint变长数

leveldb使用了Protocol Buffers的变长字节整形编码 每个字节中使用7位来表示数字 最高位用作他处

300的编码,编码后是两个字节:

  1. 1010 1100 0000 0010

  它这个例子是每个字节左边是高位,可以看到每个字节的最高位是一个标识位,从左到右第一个字节是10101100,最高位是1,说明后面还有字节需要解码,然后第二个字节是00000010,最高位是0,后面没字节了。所以这两个字节就需要解码成一个整数,再往下看。

  1. 代码
  2.  
  3. 1010 1100 0000 0010
  4. 010 1100 000 0010 //每个字节去掉最高位
  5. 000 0010 010 1100 //字节序转换,两个字节互换位置
  6. 000 0010 ++ 010 1100 //两个字节进行链接操作(不是相加)
  7. 100101100 //合并后的结果,高位位0的部分截取掉
  8. 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

 

leveldb 学习记录(四) skiplist补与变长数字的更多相关文章

  1. leveldb 学习记录(四)Log文件

    前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...

  2. leveldb 学习记录(一) skiplist

    leveldb LevelDb是一个持久化存储的KV系统,并非完全将数据放置于内存中,部分数据也会存储到磁盘上. 想了解这个由谷歌大神编写的经典项目. 可以从数据结构以及数据结构的处理下手,也可以从示 ...

  3. leveldb 学习记录(三) MemTable 与 Immutable Memtable

    前文: leveldb 学习记录(一) skiplist leveldb 学习记录(二) Slice 存储格式: leveldb数据在内存中以 Memtable存储(核心结构是skiplist 已介绍 ...

  4. JavaScript学习记录四

    title: JavaScript学习记录四 toc: true date: 2018-09-16 20:31:22 --<JavaScript高级程序设计(第2版)>学习笔记 要多查阅M ...

  5. 4.VUE前端框架学习记录四:Vue组件化编码2

    VUE前端框架学习记录四:Vue组件化编码2文字信息没办法描述清楚,主要看编码Demo里面,有附带完整的代码下载地址,有需要的同学到脑图里面自取.脑图地址http://naotu.baidu.com/ ...

  6. leveldb 学习记录(五)SSTable格式介绍

    本节主要记录SSTable的结构 为下一步代码阅读打好基础,考虑到已经有大量优秀博客解析透彻 就不再编写了 这里推荐 https://blog.csdn.net/tankles/article/det ...

  7. leveldb 学习记录(七) SSTable构造

    使用TableBuilder构造一个Table struct TableBuilder::Rep { // TableBuilder内部使用的结构,记录当前的一些状态等 Options options ...

  8. leveldb 学习记录(八) compact

    随着运行时间的增加,memtable会慢慢 转化成 sstable. sstable会越来越多 我们就需要进行整合 compact 代码会在写入查询key值 db写入时等多出位置调用MaybeSche ...

  9. Linux 学习记录 四(Bash 和 Shell scirpt)

    一.什么是 Shell? 狭义的shell指的是指令列方面的软件,包括基本的Linux操作窗口Bash等,广义的shell则包括 图形接口的软件,因为图形接口其实也可以操作各种驱动程序来呼叫核心进行工 ...

随机推荐

  1. centos7下安全访问远程服务器

    1. 添加普通账号 众所周知,linux下的root拥有最高权限,可以执行任何命令.在使用root身份操作时,有时的一个不注意就可能将非常重要的删除(最可怕的是 rm -rf /).而linux不像w ...

  2. 2017-07-06 eclipse在线安装SVN1.9插件

    1,百度搜索subeclipse,点击第一个: 2,官网说,文档已移动到github wiki上: 3,打开github wiki,复制最新发布版本地址: 4,在eclipse里面,打开help-&g ...

  3. JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)

    在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作.然而在Java中除了提供Lock API外还在语法层面上提供了synchronized关键字来实现互斥同步 ...

  4. jquery:获取checked复选框的问题

    jquery:获取checked复选框的问题 功能描述:要完成一个全选的功能,但总是获取不到复选框的被选中的个数,究其原因,是Jquery中length和checked使用不当所造成的. // 获取所 ...

  5. echarts属性的设置(完整大全)

    // 全图默认背景  // backgroundColor: ‘rgba(0,0,0,0)’, // 默认色板 color: ['#ff7f50','#87cefa','#da70d6','#32cd ...

  6. @Bean 的用法

    @Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里.添加的bean的id为方法名 定义bean 下面是@Configuratio ...

  7. leetcode647

    class Solution { public: ][],int i,int j){ if(i>=j){ return true; } else{ return DP[i][j]; } } in ...

  8. springBoot框架的搭建

    1新建一个项目: 2.注意选择JDK1.8,和选择spring initializr加载springBoot相关jar包: 3.下一步next: 4.下一步next,选择Web和MyBatis然后ne ...

  9. mysql连接测试java脚本

    JDBC.java import java.io.IOException; import java.io.InputStream; import java.sql.*; import java.uti ...

  10. Linux网络编程学习(六) ----- 管道(第四章)

    1.管道的定义 管道就是将一个程序的输出和另外一个程序的输入连接起来的单向通道,比如命令: ls -l|more,就建立了一个管道,获取ls -l的输出作为more的输入,数据就沿着管道从管道的左边流 ...