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  }