Skip to content
This repository has been archived by the owner on Dec 20, 2024. It is now read-only.

Commit

Permalink
optimize the hash circle, the algorithm of insert/delete/find is upda…
Browse files Browse the repository at this point in the history
…ted to rbtree instead of array.

Signed-off-by: allen.wq <[email protected]>
  • Loading branch information
wangforthinker committed Jun 8, 2020
1 parent 0da63b0 commit 0fdd9e7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 43 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/dragonflyoss/Dragonfly
go 1.12

require (
github.com/HuKeping/rbtree v0.0.0-20200208030951-29f0b79e84ed
github.com/PuerkitoBio/purell v0.0.0-20170829232023-f619812e3caf // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/asaskevich/govalidator v0.0.0-20170903095215-73945b6115bf // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/HuKeping/rbtree v0.0.0-20200208030951-29f0b79e84ed h1:YKqpA6qf8Bh73vj8Rv9SBB5OU558f2c1A889nCVUSLE=
github.com/HuKeping/rbtree v0.0.0-20200208030951-29f0b79e84ed/go.mod h1:bODsl3NElqKlgf1UkBLj67fYmY5DsqkKrrYm/kMT/6Y=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/PuerkitoBio/purell v0.0.0-20170829232023-f619812e3caf h1:ePmEKucT6HqNzbxw/yeyfoHplmyGDQUW76ppv4igW7Q=
github.com/PuerkitoBio/purell v0.0.0-20170829232023-f619812e3caf/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
Expand Down
95 changes: 52 additions & 43 deletions pkg/hashcircler/hash_circler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ package hashcircler
import (
"fmt"
"hash/fnv"
"sort"
"sync"

"github.com/HuKeping/rbtree"
"github.com/pkg/errors"
)

Expand All @@ -48,8 +48,8 @@ type consistentHashCircler struct {
hashFunc func(string) uint64

keysMap map[uint64]string
sortedSet []uint64
replicationPerKey int
rb *rbtree.Rbtree
}

// NewConsistentHashCircler constructs an instance of HashCircler from keys. And this is thread safety.
Expand All @@ -66,8 +66,8 @@ func NewConsistentHashCircler(keys []string, hashFunc func(string) uint64) (Hash
hc := &consistentHashCircler{
hashFunc: hashFunc,
keysMap: make(map[uint64]string),
sortedSet: []uint64{},
replicationPerKey: 16,
rb: rbtree.New(),
}

for _, k := range keys {
Expand All @@ -87,17 +87,9 @@ func (h *consistentHashCircler) Add(key string) {
continue
}
h.keysMap[m] = key
h.sortedSet = append(h.sortedSet, m)
h.addToRbTree(m, key)
}

// sort hashes ascendingly
sort.Slice(h.sortedSet, func(i int, j int) bool {
if h.sortedSet[i] < h.sortedSet[j] {
return true
}
return false
})

return
}

Expand All @@ -109,10 +101,9 @@ func (h *consistentHashCircler) Hash(input string) (key string, err error) {
return "", ErrKeyNotPresent
}

hashN := h.hashFunc(input)
index := h.search(hashN)
index := h.hashFunc(input)

return h.keysMap[h.sortedSet[index]], nil
return h.searchFromRbTree(index), nil
}

func (h *consistentHashCircler) Delete(key string) {
Expand All @@ -122,46 +113,64 @@ func (h *consistentHashCircler) Delete(key string) {
for i := 0; i < h.replicationPerKey; i++ {
m := h.hashFunc(fmt.Sprintf("%s-%d", key, i))
delete(h.keysMap, m)
h.delSlice(m)
h.deleteFromRbTree(m)
}

return
}

func (h *consistentHashCircler) search(key uint64) int {
idx := sort.Search(len(h.sortedSet), func(i int) bool {
return h.sortedSet[i] >= key
})
func fnvHashFunc(input string) uint64 {
h := fnv.New64a()
h.Write([]byte(input))
return h.Sum64()
}

if idx >= len(h.sortedSet) {
idx = 0
func (h *consistentHashCircler) addToRbTree(index uint64, key string) {
i := &item{
index: index,
key: key,
}
return idx

h.rb.Insert(i)
}

func (h *consistentHashCircler) delSlice(val uint64) {
idx := -1
l := 0
r := len(h.sortedSet) - 1
for l <= r {
m := (l + r) / 2
if h.sortedSet[m] == val {
idx = m
break
} else if h.sortedSet[m] < val {
l = m + 1
} else if h.sortedSet[m] > val {
r = m - 1
}
func (h *consistentHashCircler) deleteFromRbTree(index uint64) {
i := &item{
index: index,
}

if idx != -1 {
h.sortedSet = append(h.sortedSet[:idx], h.sortedSet[idx+1:]...)
h.rb.Delete(i)
}

func (h *consistentHashCircler) searchFromRbTree(index uint64) string {
comp := &item{
index: index,
}

target := ""

// find the key which index of item greater or equal than input index.
h.rb.Ascend(comp, func(i rbtree.Item) bool {
o := i.(*item)
target = o.key
return false
})

// if not found the target, return the max item.
if target == "" {
i := h.rb.Max()
target = i.(*item).key
}

return target
}

func fnvHashFunc(input string) uint64 {
h := fnv.New64a()
h.Write([]byte(input))
return h.Sum64()
type item struct {
index uint64
key string
}

func (i *item) Less(than rbtree.Item) bool {
other := than.(*item)
return i.index < other.index
}

0 comments on commit 0fdd9e7

Please sign in to comment.