Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lab skiplist #62

Open
wants to merge 2 commits into
base: lab_skiplist
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# corekv

corekv 是一个用来高效率的验证kv引擎feature的项目。
corekv is a project for efficiently verifying kv engine features.
118 changes: 92 additions & 26 deletions utils/skiplist.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package utils

import (
"bytes"
"github.com/hardcore-os/corekv/utils/codec"
"math/rand"
"sync"
Expand All @@ -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
Expand All @@ -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,
}
Expand All @@ -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
}

Expand All @@ -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
}
9 changes: 5 additions & 4 deletions utils/skiplist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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) {
Expand Down