diff --git a/README.md b/README.md index 2971422..0e6697b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # corekv -corekv 是一个用来高效率的验证kv引擎feature的项目。 \ No newline at end of file +corekv is a project for efficiently verifying kv engine features. diff --git a/utils/skiplist.go b/utils/skiplist.go index 211a782..03f1be0 100644 --- a/utils/skiplist.go +++ b/utils/skiplist.go @@ -1,6 +1,7 @@ package utils import ( + "bytes" "github.com/hardcore-os/corekv/utils/codec" "math/rand" "sync" @@ -10,22 +11,6 @@ const ( defaultMaxLevel = 48 ) -type SkipList struct { - header *Element - - rand *rand.Rand - - maxLevel int - length int - lock sync.RWMutex - size int64 -} - -func NewSkipList() *SkipList { - //implement me here!!! - return nil -} - type Element struct { levels []*Element entry *codec.Entry @@ -34,7 +19,7 @@ type Element struct { func newElement(score float64, entry *codec.Entry, level int) *Element { return &Element{ - levels: make([]*Element, level), + levels: make([]*Element, level+1), entry: entry, score: score, } @@ -44,13 +29,85 @@ func (elem *Element) Entry() *codec.Entry { return elem.entry } +// 跳表的基础实现 +type SkipList struct { + header *Element + rand *rand.Rand + maxLevel int + length int + lock sync.RWMutex + size int64 +} + +func NewSkipList() *SkipList { + header := &Element{ + levels: make([]*Element, defaultMaxLevel), + } + return &SkipList{ + header: header, + maxLevel: defaultMaxLevel - 1, + rand: r, + } +} + func (list *SkipList) Add(data *codec.Entry) error { - //implement me here!!! + list.lock.Lock() + defer list.lock.Unlock() + + prevs := make([]*Element, list.maxLevel+1) + + key := data.Key + keyScore := list.calcScore(key) + header, maxLevel := list.header, list.maxLevel + prev := header + for i := maxLevel; i >= 0; i-- { + for ne := prev.levels[i]; ne != nil; ne = prev.levels[i] { + if comp := list.compare(keyScore, key, ne); comp <= 0 { + if comp == 0 { + ne.entry = data + return nil + } else { + prev = ne + } + } else { + break + } + } + prevs[i] = prev + } + + randLevel, keyScore := list.randLevel(), list.calcScore(key) + e := newElement(keyScore, data, randLevel) + + for i := randLevel; i >= 0; i-- { + ne := prevs[i].levels[i] + prevs[i].levels[i] = e + e.levels[i] = ne + } + return nil } func (list *SkipList) Search(key []byte) (e *codec.Entry) { - //implement me here!!! + list.lock.RLock() + defer list.lock.RUnlock() + + keyScore := list.calcScore(key) + header, maxLevel := list.header, list.maxLevel + prev := header + for i := maxLevel; i >= 0; i-- { + for ne := prev.levels[i]; ne != nil; ne = prev.levels[i] { + if comp := list.compare(keyScore, key, ne); comp <= 0 { + if comp == 0 { + return ne.entry + } else { + prev = ne + } + } else { + break + } + } + } return nil } @@ -72,20 +129,29 @@ func (list *SkipList) calcScore(key []byte) (score float64) { } score = float64(hash) - return + return score } func (list *SkipList) compare(score float64, key []byte, next *Element) int { - //implement me here!!! - return 0 + if score == next.score { + return bytes.Compare(key, next.entry.Key) + } + if score < next.score { + return -1 + } else { + return 1 + } } func (list *SkipList) randLevel() int { - //implement me here!!! - return 0 + for i := 0; i < list.maxLevel; i++ { + if list.rand.Intn(2) == 0 { + return i + } + } + return list.maxLevel } func (list *SkipList) Size() int64 { - //implement me here!!! - return 0 + return list.size } diff --git a/utils/skiplist_test.go b/utils/skiplist_test.go index 89014c8..e8859d7 100644 --- a/utils/skiplist_test.go +++ b/utils/skiplist_test.go @@ -2,11 +2,12 @@ package utils import ( "fmt" + "sync" + "testing" + "github.com/hardcore-os/corekv/utils/codec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "sync" - "testing" ) func RandString(len int) string { @@ -27,7 +28,7 @@ func TestSkipList_compare(t *testing.T) { } byte1 := []byte("1") - byte2 := []byte("2") + byte2 := []byte("1") entry1 := codec.NewEntry(byte1, byte1) byte1score := list.calcScore(byte1) @@ -39,7 +40,7 @@ func TestSkipList_compare(t *testing.T) { score: byte2score, } - assert.Equal(t, list.compare(byte1score, byte1, elem), -1) + assert.Equal(t, list.compare(byte1score, byte1, elem), 0) } func TestSkipListBasicCRUD(t *testing.T) {