diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c88aff0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +*.exe +demo +etc/*.conf +etc/*.cfg \ No newline at end of file diff --git a/README.md b/README.md index 1c6d1ff..5fa6346 100644 --- a/README.md +++ b/README.md @@ -35,4 +35,10 @@ hash.AddNode("node3", 3) //get key's node node := hash.GetNode("key") -``` \ No newline at end of file +``` + +坑点: + // 一个9064767行的文件 每行做hashring,结果不一致 原因hashBytes只取4位 529和83 一致 ,这个库是一对多的关系,非多对一 + // node=1000 vitualSpots=20000 + //9063340 key=49f57cf0 node=529 + //9063340 key=49f57cf0 node=83 \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..76a0b56 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/joykk/hashring + +go 1.13 + +require github.com/sirupsen/logrus v1.4.2 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..706fe8d --- /dev/null +++ b/go.sum @@ -0,0 +1,13 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/hashring.go b/hashring.go index 4ac0ffd..cd13dd0 100644 --- a/hashring.go +++ b/hashring.go @@ -88,8 +88,12 @@ func (h *HashRing) generate() { } totalVirtualSpots := h.virualSpots * len(h.weights) - h.nodes = nodesArray{} + var nodeLen, nodeIndex int64 + for _, w := range h.weights { + nodeLen += int64(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots))) + } + h.nodes = make(nodesArray, nodeLen) for nodeKey, w := range h.weights { spots := int(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots))) for i := 1; i <= spots; i++ { @@ -100,7 +104,8 @@ func (h *HashRing) generate() { nodeKey: nodeKey, spotValue: genValue(hashBytes[6:10]), } - h.nodes = append(h.nodes, n) + h.nodes[nodeIndex] = n + nodeIndex += 1 hash.Reset() } } @@ -122,7 +127,6 @@ func (h *HashRing) GetNode(s string) string { if len(h.nodes) == 0 { return "" } - hash := sha1.New() hash.Write([]byte(s)) hashBytes := hash.Sum(nil) diff --git a/hashring_test.go b/hashring_test.go index c92fdfc..93db865 100644 --- a/hashring_test.go +++ b/hashring_test.go @@ -1,8 +1,13 @@ package hashring import ( - // "fmt" + "crypto/sha1" + "fmt" + "regexp" + "runtime" + "strconv" "testing" + "time" ) const ( @@ -22,7 +27,6 @@ func getNodesCount(nodes nodesArray) (int, int, int) { } if node.nodeKey == node2 { node2Count += 1 - } if node.nodeKey == node3 { node3Count += 1 @@ -82,3 +86,75 @@ func TestHash(t *testing.T) { t.Logf("len of nodes is %v after AddNode node1:%v, node2:%v, node3:%v", len(hash.nodes), c1, c2, c3) } + +func TimeTrack(start time.Time) { + elapsed := time.Since(start) + + // Skip this function, and fetch the PC and file for its parent. + pc, _, _, _ := runtime.Caller(1) + + // Retrieve a function object this functions parent. + funcObj := runtime.FuncForPC(pc) + + // Regex to extract just the function name (and not the module path). + runtimeFunc := regexp.MustCompile(`^.*\.(.*)$`) + name := runtimeFunc.ReplaceAllString(funcObj.Name(), "$1") + + fmt.Printf("TimeTrack funcName:%s elapsed:%s \n", name, elapsed) +} + +func TestSpeed(t *testing.T) { + // node=1000 v=50000 on 8GB/win10/i7 init 35s + defer TimeTrack(time.Now()) + nodeWeight := make(map[string]int) + for i := 0; i < 1000; i += 1 { + nodeWeight[strconv.Itoa(i)] = 1 + } + vitualSpots := 50000 + hash := NewHashRing(vitualSpots) + + hash.AddNodes(nodeWeight) +} + +func TestManyTime(t *testing.T) { + // 一个9064767行的文件 每行做hashring,结果不一致 原因hashBytes只取4位 529和83 一致 ,这个库是一对多的关系,非多对一 + // node=1000 vitualSpots=20000 + //9063340 key=49f57cf0 node=529 + //9063340 key=49f57cf0 node=83 + + hash := sha1.New() + hash.Write([]byte("529" + ":" + strconv.Itoa(1))) + hashBytes := hash.Sum(nil) + a := hashBytes[6:10] + + hash2 := sha1.New() + hash2.Write([]byte("83" + ":" + strconv.Itoa(1))) + hashBytes2 := hash.Sum(nil) + a2 := hashBytes2[6:10] + + fmt.Printf("%s %s\n", a, a2) + + //defer TimeTrack(time.Now()) + //nodeWeight := make(map[string]int) + //for i := 0; i < 1000; i += 1 { + // nodeWeight[strconv.Itoa(i)] = 1 + //} + //vitualSpots := 20000 + //hash := NewHashRing(vitualSpots) + //hash.AddNodes(nodeWeight) + //for _, nn := range hash.nodes { + // if "529" != nn.nodeKey { + // fmt.Printf("529 %s\n", nn.nodeKey) + // } + // if "83" != nn.nodeKey { + // fmt.Printf("83 %s\n", nn.nodeKey) + // } + //} + //for i := 0; i <= 906476700; i++ { + // node := hash.GetNode("49f57cf0") + // if "83" != node { + // t.Errorf("err:%s\n", node) + // return + // } + //} +}