add pkg
This commit is contained in:
		
							parent
							
								
									8359001e34
								
							
						
					
					
						commit
						b84728bd22
					
				
							
								
								
									
										37
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								README.md
									
									
									
									
									
								
							@ -1 +1,38 @@
 | 
				
			|||||||
# hashring
 | 
					# hashring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A golang consistent hashring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Install
 | 
				
			||||||
 | 
					===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go get github.com/g4zhuj/hashring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Usage
 | 
				
			||||||
 | 
					===
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					// virtualSpots means virtual spots created by each node
 | 
				
			||||||
 | 
						nodeWeight := make(map[string]int)
 | 
				
			||||||
 | 
						nodeWeight["node1"] = 1
 | 
				
			||||||
 | 
						nodeWeight["node2"] = 1
 | 
				
			||||||
 | 
						nodeWeight["node3"] = 2
 | 
				
			||||||
 | 
						vitualSpots := 100
 | 
				
			||||||
 | 
						hash := NewHashRing(virtualSpots)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//add nodes
 | 
				
			||||||
 | 
						hash.AddNodes(nodeWeight)
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//remove node
 | 
				
			||||||
 | 
						hash.RemoveNode("node3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//add node
 | 
				
			||||||
 | 
						hash.AddNode("node3", 3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//get key's node
 | 
				
			||||||
 | 
						node := hash.GetNode("key")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										117
									
								
								hashring.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								hashring.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					package hashring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/sha1"
 | 
				
			||||||
 | 
						//	"hash"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						DefaultVirualSpots = 40
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type node struct {
 | 
				
			||||||
 | 
						nodeKey   string
 | 
				
			||||||
 | 
						spotValue uint32
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type nodesArray []node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p nodesArray) Len() int           { return len(p) }
 | 
				
			||||||
 | 
					func (p nodesArray) Less(i, j int) bool { return p[i].spotValue < p[j].spotValue }
 | 
				
			||||||
 | 
					func (p nodesArray) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
 | 
				
			||||||
 | 
					func (p nodesArray) Sort()              { sort.Sort(p) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type HashRing struct {
 | 
				
			||||||
 | 
						virualSpots int
 | 
				
			||||||
 | 
						nodes       nodesArray
 | 
				
			||||||
 | 
						weights     map[string]int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewHashRing(spots int) *HashRing {
 | 
				
			||||||
 | 
						if spots == 0 {
 | 
				
			||||||
 | 
							spots = DefaultVirualSpots
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						h := &HashRing{
 | 
				
			||||||
 | 
							virualSpots: spots,
 | 
				
			||||||
 | 
							weights:     make(map[string]int),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return h
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) AddNodes(nodeWeight map[string]int) {
 | 
				
			||||||
 | 
						for nodeKey, w := range nodeWeight {
 | 
				
			||||||
 | 
							h.weights[nodeKey] = w
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.generate()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) AddNode(nodeKey string, weight int) {
 | 
				
			||||||
 | 
						h.weights[nodeKey] = weight
 | 
				
			||||||
 | 
						h.generate()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) RemoveNode(nodeKey string) {
 | 
				
			||||||
 | 
						delete(h.weights, nodeKey)
 | 
				
			||||||
 | 
						h.generate()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) UpdateNode(nodeKey string, weight int) {
 | 
				
			||||||
 | 
						h.weights[nodeKey] = weight
 | 
				
			||||||
 | 
						h.generate()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) generate() {
 | 
				
			||||||
 | 
						var totalW int
 | 
				
			||||||
 | 
						for _, w := range h.weights {
 | 
				
			||||||
 | 
							totalW += w
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						totalVirtualSpots := h.virualSpots * len(h.weights)
 | 
				
			||||||
 | 
						h.nodes = nodesArray{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for nodeKey, w := range h.weights {
 | 
				
			||||||
 | 
							spots := int(math.Floor(float64(w) / float64(totalW) * float64(totalVirtualSpots)))
 | 
				
			||||||
 | 
							for i := 1; i <= spots; i++ {
 | 
				
			||||||
 | 
								hash := sha1.New()
 | 
				
			||||||
 | 
								hash.Write([]byte(nodeKey + ":" + strconv.Itoa(i)))
 | 
				
			||||||
 | 
								hashBytes := hash.Sum(nil)
 | 
				
			||||||
 | 
								n := node{
 | 
				
			||||||
 | 
									nodeKey:   nodeKey,
 | 
				
			||||||
 | 
									spotValue: genValue(hashBytes[6:10]),
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								h.nodes = append(h.nodes, n)
 | 
				
			||||||
 | 
								hash.Reset()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h.nodes.Sort()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func genValue(bs []byte) uint32 {
 | 
				
			||||||
 | 
						if len(bs) < 4 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						v := (uint32(bs[3]) << 24) | (uint32(bs[2]) << 16) | (uint32(bs[1]) << 8) | (uint32(bs[0]))
 | 
				
			||||||
 | 
						return v
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *HashRing) GetNode(s string) string {
 | 
				
			||||||
 | 
						if len(h.nodes) == 0 {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hash := sha1.New()
 | 
				
			||||||
 | 
						hash.Write([]byte(s))
 | 
				
			||||||
 | 
						hashBytes := hash.Sum(nil)
 | 
				
			||||||
 | 
						v := genValue(hashBytes[6:10])
 | 
				
			||||||
 | 
						i := sort.Search(len(h.nodes), func(i int) bool { return h.nodes[i].spotValue >= v })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if i == len(h.nodes) {
 | 
				
			||||||
 | 
							i = 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return h.nodes[i].nodeKey
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										84
									
								
								hashring_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								hashring_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					package hashring
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						//	"fmt"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						node1 = "192.168.1.1"
 | 
				
			||||||
 | 
						node2 = "192.168.1.2"
 | 
				
			||||||
 | 
						node3 = "192.168.1.3"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getNodesCount(nodes nodesArray) (int, int, int) {
 | 
				
			||||||
 | 
						node1Count := 0
 | 
				
			||||||
 | 
						node2Count := 0
 | 
				
			||||||
 | 
						node3Count := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, node := range nodes {
 | 
				
			||||||
 | 
							if node.nodeKey == node1 {
 | 
				
			||||||
 | 
								node1Count += 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if node.nodeKey == node2 {
 | 
				
			||||||
 | 
								node2Count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if node.nodeKey == node3 {
 | 
				
			||||||
 | 
								node3Count += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return node1Count, node2Count, node3Count
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestHash(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nodeWeight := make(map[string]int)
 | 
				
			||||||
 | 
						nodeWeight[node1] = 2
 | 
				
			||||||
 | 
						nodeWeight[node2] = 2
 | 
				
			||||||
 | 
						nodeWeight[node3] = 3
 | 
				
			||||||
 | 
						vitualSpots := 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hash := NewHashRing(vitualSpots)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hash.AddNodes(nodeWeight)
 | 
				
			||||||
 | 
						if hash.GetNode("1") != node3 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node3, hash.GetNode("1"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("2") != node3 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node3, hash.GetNode("2"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("3") != node2 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node2, hash.GetNode("3"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c1, c2, c3 := getNodesCount(hash.nodes)
 | 
				
			||||||
 | 
						t.Logf("len of nodes is %v after AddNodes node1:%v, node2:%v, node3:%v", len(hash.nodes), c1, c2, c3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hash.RemoveNode(node3)
 | 
				
			||||||
 | 
						if hash.GetNode("1") != node1 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node1, hash.GetNode("1"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("2") != node2 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node1, hash.GetNode("2"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("3") != node2 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node2, hash.GetNode("3"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c1, c2, c3 = getNodesCount(hash.nodes)
 | 
				
			||||||
 | 
						t.Logf("len of nodes is %v after RemoveNode node1:%v, node2:%v, node3:%v", len(hash.nodes), c1, c2, c3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hash.AddNode(node3, 3)
 | 
				
			||||||
 | 
						if hash.GetNode("1") != node3 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node3, hash.GetNode("1"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("2") != node3 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node3, hash.GetNode("2"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if hash.GetNode("3") != node2 {
 | 
				
			||||||
 | 
							t.Fatalf("expetcd %v got %v", node2, hash.GetNode("3"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c1, c2, c3 = getNodesCount(hash.nodes)
 | 
				
			||||||
 | 
						t.Logf("len of nodes is %v after AddNode node1:%v, node2:%v, node3:%v", len(hash.nodes), c1, c2, c3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user