github.com/searKing/golang/go@v1.2.117/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 // 79 // (0 is the first repetition) 80 // 81 // @return The key that represents the specific repetition of the node 82 func (f KetamaNodeKeyFormatter) getKeyForNode(node Node, repetition int) string { 83 // Carrried over from the DefaultKetamaNodeLocatorConfiguration: 84 // Internal Using the internal map retrieve the socket addresses 85 // for given nodes. 86 // I'm aware that this code is inherently thread-unsafe as 87 // I'm using a HashMap implementation of the map, but the worst 88 // case ( I believe) is we're slightly in-efficient when 89 // a node has never been seen before concurrently on two different 90 // threads, so it the socketaddress will be requested multiple times! 91 // all other cases should be as fast as possible. 92 nodeKey, has := f.keyByNode[node] 93 if !has { 94 switch f.format { 95 case LibMemcached: 96 nodeKey = node.String() 97 break 98 case SpyMemcached: 99 nodeKey = node.String() 100 if strings.Index(nodeKey, "/") == 0 { 101 nodeKey = strings.TrimLeft(nodeKey, "/") 102 } 103 break 104 default: 105 panic(fmt.Errorf("unsupport format %d", f.format)) 106 } 107 f.keyByNode[node] = nodeKey 108 } 109 return fmt.Sprintf("%s-%d", nodeKey, repetition) 110 }