new package consistenthash

pull/2/head
q191201771 5 years ago
parent d300e839ca
commit c6a5fa284f

@ -12,9 +12,10 @@ import (
"bytes"
"flag"
"fmt"
"os"
"github.com/q191201771/naza/pkg/filebatch"
"github.com/q191201771/naza/pkg/nazalog"
"os"
)
//var licenseTmpl = `
@ -27,7 +28,6 @@ var licenseTmpl = `
> **** yoko
> **** `
func main() {
dir := parseFlag()

@ -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…
Cancel
Save