github.com/searKing/golang/go@v1.2.74/container/hashring/ketama_node_key_formatter.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package hashring 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 // Known key formats used in Ketama for assigning nodes around the ring 13 type Format int 14 15 const ( 16 // SpyMemcached uses the format traditionally used by spymemcached to map 17 // nodes to names. The format is HOSTNAME/IP:PORT-ITERATION 18 // 19 // <p> 20 // This default implementation uses the socket-address of the Node 21 // and concatenates it with a hyphen directly against the repetition number 22 // for example a key for a particular server's first repetition may look like: 23 // <p> 24 // 25 // <p> 26 // <code>myhost/10.0.2.1-0</code> 27 // </p> 28 // 29 // <p> 30 // for the second repetition 31 // </p> 32 // 33 // <p> 34 // <code>myhost/10.0.2.1-1</code> 35 // </p> 36 // 37 // <p> 38 // for a server where reverse lookups are failing the returned keys may look 39 // like 40 // </p> 41 // 42 // <p> 43 // <code>/10.0.2.1-0</code> and <code>/10.0.2.1-1</code> 44 // </p> 45 SpyMemcached Format = iota 46 47 // LibMemcached uses the format traditionally used by libmemcached to map 48 // nodes to names. The format is HOSTNAME:[PORT]-ITERATION the PORT is not 49 // part of the node identifier if it is the default memcached port (11211) 50 LibMemcached 51 ) 52 53 type KetamaNodeKeyFormatter struct { 54 format Format 55 56 // Carried over from the DefaultKetamaNodeLocatorConfiguration: 57 // Internal lookup map to try to carry forward the optimisation that was 58 // previously in NodeLocator 59 keyByNode map[Node]string 60 } 61 62 func (f KetamaNodeKeyFormatter) GetFormat() Format { 63 return f.format 64 } 65 66 func NewKetamaNodeKeyFormatter(format Format) *KetamaNodeKeyFormatter { 67 return &KetamaNodeKeyFormatter{ 68 format: format, 69 keyByNode: make(map[Node]string), 70 } 71 } 72 73 // Returns a uniquely identifying key, suitable for hashing by the 74 // NodeLocator algorithm. 75 // 76 // @param node The Node to use to form the unique identifier 77 // @param repetition The repetition number for the particular node in question 78 // (0 is the first repetition) 79 // @return The key that represents the specific repetition of the node 80 func (f KetamaNodeKeyFormatter) getKeyForNode(node Node, repetition int) string { 81 // Carrried over from the DefaultKetamaNodeLocatorConfiguration: 82 // Internal Using the internal map retrieve the socket addresses 83 // for given nodes. 84 // I'm aware that this code is inherently thread-unsafe as 85 // I'm using a HashMap implementation of the map, but the worst 86 // case ( I believe) is we're slightly in-efficient when 87 // a node has never been seen before concurrently on two different 88 // threads, so it the socketaddress will be requested multiple times! 89 // all other cases should be as fast as possible. 90 nodeKey, has := f.keyByNode[node] 91 if !has { 92 switch f.format { 93 case LibMemcached: 94 nodeKey = node.String() 95 break 96 case SpyMemcached: 97 nodeKey = node.String() 98 if strings.Index(nodeKey, "/") == 0 { 99 nodeKey = strings.TrimLeft(nodeKey, "/") 100 } 101 break 102 default: 103 panic(fmt.Errorf("unsupport format %d", f.format)) 104 } 105 f.keyByNode[node] = nodeKey 106 } 107 return fmt.Sprintf("%s-%d", nodeKey, repetition) 108 }