go LevelDB 跳跃表的实现原理

1.levelDB 跳跃表

(图1) 

每个节点包含 keyValue 与 对应的层高,每个hx 记录下一个节点的位置。在 levelDB 中,节点位置(nodeData)与数据(kvData)是分开存储的,所以 keyValue 实际存储的是该键值对在 kvData 中的偏移量 offset。

2.nodeData 数据结构

(图2)

        offset: key-value在kvData的起始位置

        klen: key字节长度

        vlen::value字节长度

        hlen:节点的高度

 3.kvData 数据结构

 (图3)

4.将图 (1) 转换为具体 nodeData 和 kvData

 (图4)

5.代码实现

package main

import (
	"bytes"
	"errors"
	"fmt"
	"math/rand"
)

const (
	nKV = iota 
	nKey 
	nVal
	nHeight
	nNext
)
const tMaxHeight = 12 //最大高度
type SkipList struct {
	rnd *rand.Rand
	kvData []byte
	nodeData []int
	prevNode  [tMaxHeight]int
  //用于在遍历skiplist的时候,保存每一层的前一个节点,用于插入很更新
  //如果某层有元素 a,b,c,e。 当插入元素d是, 该层的prevNode 就是 c。
  //插入数据时(d), d.next = c.next,  c.next = d
  //删除数据时(d), c.next = d.next 
	maxHeight int // skiplist的层高
}

func SimpleSkipList()  {
    //初始化
	sk := &SkipList{
		rnd:  rand.New(rand.NewSource(0xdeadbeef)),
		kvData: make([]byte,0),
		nodeData: make([]int,nNext+tMaxHeight),
		prevNode: [tMaxHeight]int{},
		maxHeight: 1,
	}
	sk.nodeData[nKV] = 0 //offset
	sk.nodeData[nKey] = 0 //keylen
	sk.nodeData[nVal] = 0 //vallen
	sk.nodeData[nHeight] = tMaxHeight //height
	for n := 0; n < tMaxHeight; n++ { 
		sk.nodeData[nNext+n] = 0
		sk.prevNode[n] = 0
	}
    //添加元素
	sk.Put([]byte("a"),[]byte("a1"))
    //获取key的value
	//v,_ := sk.Get([]byte("a"))
	//更新
sk.Put([]byte("a"),[]byte("a11"))
	//添加
sk.Put([]byte("b"),[]byte("b1"))
	sk.Put([]byte("c"),[]byte("c1"))
	//删除
sk.Delete([]byte("a"))
	
}
//添加元素
func (sk *SkipList) Put(key []byte, value []byte) error {
	node,exact := sk.findGE(key,true) //判断是否存在元素
	if exact { //修改元素,只追加不修改
		offset := len(sk.kvData) 
		sk.kvData = append(sk.kvData,key...)
		sk.kvData = append(sk.kvData,value...)
		sk.nodeData[node] = offset
		sk.nodeData[node+nVal] = len(value)
		return nil
	}
	h := sk.randHeight() //随机选择一个高度
	if h>sk.maxHeight {
		for i:=sk.maxHeight; i<h ;i++ {
			sk.prevNode[i] = 0
		}
		sk.maxHeight = h
	}
	offset := len(sk.kvData)
	sk.kvData = append(sk.kvData,key...)
	sk.kvData = append(sk.kvData,value...)
	node = len(sk.nodeData)
	sk.nodeData = append(sk.nodeData,offset,len(key),len(value),h)
	for i,n := range sk.prevNode[:h] {
		m := n+nNext+i
		sk.nodeData = append(sk.nodeData, sk.nodeData[m])
		sk.nodeData[m] = node
	}

	return nil
}
func (sk *SkipList) Delete(key []byte) error {
	node, exact := sk.findGE(key,true)
	if !exact {
		return errors.New("NOT FOUND")
	}
	h := sk.nodeData[node+nHeight]
	for i:=0;i<h;i++ {
		preNode := sk.prevNode[i]
		sk.nodeData[preNode+nNext+i] = sk.nodeData[node+nNext+i]
	}
	return nil
}
func (sk *SkipList) findGE(key []byte, pre bool) (int, bool) {
	node := 0
	h := sk.maxHeight-1 //层高
	for {
		next := sk.nodeData[node+nNext+h]

		cmp := 1
		if next != 0 {
			offset := sk.nodeData[next]
			keyLen := sk.nodeData[next+nKey]
			o := sk.kvData[offset:offset+keyLen]
			cmp = bytes.Compare(o,key)
		}
		if cmp < 0 { //节点key<指定key 沿着当前层走到next节点
			node = next
		} else {
			if pre {//对于插入或者删除而进行的搜索,即使遇到相同的也要继续往下层比较
				sk.prevNode[h] = node //记录前一个节点
			} else if cmp == 0 {
				return next,true
			}
			if h == 0 {
				return next, cmp == 0
			}
			h--
		}

	}
}
func (sk *SkipList) Get(key []byte) (value []byte, err error) {
	node, exact := sk.findGE(key,true)
	if !exact {
		return nil, errors.New("NOT FOUND")
	}
	pos := sk.nodeData[node]
	return sk.kvData[pos+nKey:pos+nKey+nVal],nil
}
func (sk *SkipList) randHeight() (h int) {
	return rand.Intn(5)
	const branching = 4
	h = 1
	for h < tMaxHeight && sk.rnd.Int()%branching == 0 {
		h++
	}
	return
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值