goleveldb memdb实现

goleveldb [https://github.com/syndtr/goleveldb] 中的memdb是一个跳表, 跳表的原理参看: http://blog.sina.com.cn/s/blog_72995dcc01017w1t.html

跳表高度

memdb采用常数const tMaxHeight = 12,每个插入的key-value的高度是随即确定的。

const tMaxHeight = 12
func (p *DB) randHeight() (h int) {
    const branching = 4
    h = 1
    for h < tMaxHeight && p.rnd.Int()%branching == 0 {
        h++
    }
    return
}

在插入2000万key的情况下:


func TestRandHeight(t *testing.T) {
    db := New(comparer.DefaultComparer, 0)
    fmt.Println("begin")
    m := make(map[int]int)
    for i := 0; i < 20000000; i++ {
        h := db.randHeight()
        m[h] = m[h] + 1

    }
    for k, v := range m {
        fmt.Printf("%d: %d\n", k, v)
    }
}

key高度的分布如下:

1   14998891 
2   3750488
3   938399
4   233846
5   58845
6   14742
7   3565
8   928
9   224
10  54
11  14
12  4

表明在第一级的key的个数约1500万个, 占75%*2000万
表明在第二级的key的个数约375万个, 占25%*75%*2000万
表明在第三级的key的个数约93.75万个, 占25%*25%*75%*2000万
也就是说,高一个级别的key个数是上一级的25%

数据存储

type DB struct {
    kvData []byte  -> 存储key,value值的地方,默认4m大小
    nodeData  []int -> 存放key关系的地方:后一个key的位置
    prevNode  [tMaxHeight]int  -> put/delete过程中临时保存变量的地方
    maxHeight int -> 当前跳表最高高度,默认是 1
    n         int  -> key个数
    kvSize    int -> 有效key,value占的空间
}

kvSize 不等于 len(db.kvData),因为kvData是append模式的。原因是降低gc压力。
nodeData[4:4+12]: 代表跳表高度h指向的第一个key的位置。
每一个key-value在nodeData中是由多个int来表示,假设("a9","v") 位于h1=6跳表高度(1=<h1<=12)
那么在nodeData有 10个数字表示

nodeData:   [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 
nodeData:  [content] 00 00 00 0c 10 10 10 10 10 10 00 00 00 00 00 00 00 02 01 06 00 00 00 00 00 00

kvData: len: 3,     [index]  00 01 02 
kvData: len: 3,  [content]  61 39 76

上图表示插入("a9","v") 数据后,其中nodeData,kvData对应的实际数据。
nodeData 位置从0x10~0x19的10个数据表示("a9","v")
nodeData[0x10] = 00,表示 从kvData[0]开始存储数据。
nodeData[0x11] = 02,表示 key的长度。
nodeData[0x12] = 01,表示 value的长度。
nodeData[0x13] = 06,表示 本key所在的跳表高度。
nodeData[0x14] = 00,表示 本key在的跳表高度1对应的下一个key的位置。
nodeData[0x15] = 00,表示 本key在的跳表高度2对应的下一个key的位置。
nodeData[0x16] = 00,表示 本key在的跳表高度3对应的下一个key的位置。
nodeData[0x17] = 00,表示 本key在的跳表高度4对应的下一个key的位置。
nodeData[0x18] = 00,表示 本key在的跳表高度5对应的下一个key的位置。
nodeData[0x19] = 00,表示 本key在的跳表高度6对应的下一个key的位置。

再插入一个跳表高度6的("a8","v"),后,数据如下:

nodeData:    [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 
nodeData:   [content] 00 00 00 0c 1a 1a 1a 1a 1a 1a 00 00 00 00 00 00 00 02 01 06 00 00 00 00 00 00 03 02 01 06 10 10 10 10 10 10
kvData: len: 6,    [index]  00 01 02 03 04 05 
kvData: len: 6,  [content]  61 39 76 61 38 76

nodeData[0x04] = 1a,表示 跳表高度1对应的第一个key的位置。
nodeData[0x05] = 1a,表示 跳表高度2对应的第一个key的位置。
nodeData[0x06] = 1a,表示 跳表高度3对应的第一个key的位置。
nodeData[0x07] = 1a,表示 跳表高度4对应的第一个key的位置。
nodeData[0x08] = 1a,表示 跳表高度5对应的第一个key的位置。
nodeData[0x09] = 1a,表示 跳表高度6对应的第一个key的位置。

数据更新

put ("a9","v12345")会导致数据更新:

nodeData:    [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 
nodeData:   [content] 00 00 00 0c 1a 1a 1a 1a 1a 1a 00 00 00 00 00 00 06 02 06 06 00 00 00 00 00 00 03 02 01 06 10 10 10 10 10 10

kvData: len: 14,    [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 
kvData: len: 14,  [content]  61 39 76 61 38 76 61 39 76 31 32 33 34 35

发现nodeData的长度没有变化。但是nodeData[0x10] key的位置,nodeData[0x12] value的长度发生变化了。
发现kvData内容增加,原来的key,value(kvData[0:3] )没有删除。

数据删除

delete ("a9")会导致数据更新:

nodeData:    [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 
nodeData:   [content] 00 00 00 0c 1a 1a 1a 1a 1a 1a 00 00 00 00 00 00 06 02 06 06 00 00 00 00 00 00 03 02 01 06 00 00 00 00 00 00

kvData: len: 14,    [index]  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 
kvData: len: 14,  [content]  61 39 76 61 38 76 61 39 76 31 32 33 34 35

发现“a9”这个key,value还是存在的,只有没有节点引用“a9”这个节点了。

数据查询

查询是从跳表高度最高级别开始,找到一个大于等于当前key的节点,然后进入下一个级别查找。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,946评论 6 13
  • Redis是啥 Redis是一个开源的key-value存储系统,由于拥有丰富的数据结构,又被其作者戏称为数据结构...
    一凡呀阅读 1,173评论 0 5
  • Spark SQL, DataFrames and Datasets Guide Overview SQL Dat...
    草里有只羊阅读 18,316评论 0 85
  • 现在的我深刻地体会到 每个人都是独立的个体 所谓的"朋友" 有很多 真正的朋友 少之又少 朋友一旦失去 就再也...
    小疯zi阅读 178评论 0 0