mirror of https://github.com/q191201771/naza
new package consistenthash
parent
d300e839ca
commit
c6a5fa284f
@ -0,0 +1,97 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package consistenthash
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hash/crc32"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ConsistentHash interface {
|
||||
Add(nodes ...string)
|
||||
Del(nodes ...string)
|
||||
Get(key string) (node string, err error)
|
||||
Nodes() map[string]struct{}
|
||||
}
|
||||
|
||||
var ErrIsEmpty = errors.New("naza.consistenthash: is empty")
|
||||
|
||||
func New(dups int) ConsistentHash {
|
||||
return &consistentHash{
|
||||
point2node: make(map[int]string),
|
||||
dups: dups,
|
||||
}
|
||||
}
|
||||
|
||||
type consistentHash struct {
|
||||
point2node map[int]string
|
||||
points []int
|
||||
dups int
|
||||
}
|
||||
|
||||
func (ch *consistentHash) Add(nodes ...string) {
|
||||
for _, node := range nodes {
|
||||
for i := 0; i < ch.dups; i++ {
|
||||
point := hash2point(virtualKey(node, i))
|
||||
ch.point2node[point] = node
|
||||
ch.points = append(ch.points, point)
|
||||
}
|
||||
}
|
||||
sort.Ints(ch.points)
|
||||
}
|
||||
|
||||
func (ch *consistentHash) Del(nodes ...string) {
|
||||
for _, node := range nodes {
|
||||
for i := 0; i < ch.dups; i++ {
|
||||
point := hash2point(virtualKey(node, i))
|
||||
delete(ch.point2node, point)
|
||||
}
|
||||
}
|
||||
|
||||
ch.points = nil
|
||||
for k := range ch.point2node {
|
||||
ch.points = append(ch.points, k)
|
||||
}
|
||||
sort.Ints(ch.points)
|
||||
}
|
||||
|
||||
func (ch *consistentHash) Get(key string) (node string, err error) {
|
||||
if len(ch.points) == 0 {
|
||||
return "", ErrIsEmpty
|
||||
}
|
||||
|
||||
point := hash2point(key)
|
||||
index := sort.Search(len(ch.points), func(i int) bool {
|
||||
return ch.points[i] >= point
|
||||
})
|
||||
|
||||
if index == len(ch.points) {
|
||||
index = 0
|
||||
}
|
||||
|
||||
return ch.point2node[ch.points[index]], nil
|
||||
}
|
||||
|
||||
func (ch *consistentHash) Nodes() map[string]struct{} {
|
||||
ret := make(map[string]struct{})
|
||||
for _, v := range ch.point2node {
|
||||
ret[v] = struct{}{}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func virtualKey(node string, index int) string {
|
||||
return node + strconv.Itoa(index)
|
||||
}
|
||||
|
||||
func hash2point(key string) int {
|
||||
return int(crc32.ChecksumIEEE([]byte(key)))
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// Copyright 2019, Chef. All rights reserved.
|
||||
// https://github.com/q191201771/naza
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style license
|
||||
// that can be found in the License file.
|
||||
//
|
||||
// Author: Chef (191201771@qq.com)
|
||||
|
||||
package consistenthash
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/q191201771/naza/pkg/assert"
|
||||
"github.com/q191201771/naza/pkg/nazalog"
|
||||
)
|
||||
|
||||
func TestConsistentHash(t *testing.T) {
|
||||
ch := New(1024)
|
||||
_, err := ch.Get("aaa")
|
||||
assert.Equal(t, ErrIsEmpty, err)
|
||||
ch.Add("127.0.0.1")
|
||||
ch.Add("0.0.0.0", "8.8.8.8")
|
||||
ch.Del("127.0.0.1", "8.8.8.8")
|
||||
ch.Add("114.114.114.114", "255.255.255.255", "1.1.1.1", "2.2.2.2", "3.3.3.3")
|
||||
exptectedNodes := map[string]struct{}{
|
||||
"0.0.0.0": struct{}{},
|
||||
"114.114.114.114": struct{}{},
|
||||
"255.255.255.255": struct{}{},
|
||||
"1.1.1.1": struct{}{},
|
||||
"2.2.2.2": struct{}{},
|
||||
"3.3.3.3": struct{}{},
|
||||
}
|
||||
actualNodes := ch.Nodes()
|
||||
assert.Equal(t, exptectedNodes, actualNodes)
|
||||
counts := make(map[string]int)
|
||||
for i := 0; i < 16384; i++ {
|
||||
node, err := ch.Get(strconv.Itoa(i))
|
||||
assert.Equal(t, nil, err)
|
||||
counts[node]++
|
||||
}
|
||||
nazalog.Debugf("%+v", counts)
|
||||
}
|
Loading…
Reference in New Issue