github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/gossip/keys.go (about)

     1  // Copyright 2014 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package gossip
    12  
    13  import (
    14  	"regexp"
    15  	"strconv"
    16  	"strings"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    19  	"github.com/cockroachdb/errors"
    20  )
    21  
    22  // separator is used to separate the non-prefix components of a
    23  // Gossip key, facilitating the automated generation of regular
    24  // expressions for various prefixes.
    25  // It must not be contained in any of the other keys defined here.
    26  const separator = ":"
    27  
    28  // Constants for gossip keys.
    29  const (
    30  	// KeyClusterID is the unique UUID for this Cockroach cluster.
    31  	// The value is a string UUID for the cluster.  The cluster ID is
    32  	// gossiped by all nodes that contain a replica of the first range,
    33  	// and it serves as a check for basic gossip connectivity. The
    34  	// Gossip.Connected channel is closed when we see this key.
    35  	KeyClusterID = "cluster-id"
    36  
    37  	// KeyStorePrefix is the key prefix for gossiping stores in the network.
    38  	// The suffix is a store ID and the value is roachpb.StoreDescriptor.
    39  	KeyStorePrefix = "store"
    40  
    41  	// KeyNodeIDPrefix is the key prefix for gossiping node id
    42  	// addresses. The actual key is suffixed with the decimal
    43  	// representation of the node id and the value is the host:port
    44  	// string address of the node. E.g. node:1 => 127.0.0.1:24001
    45  	KeyNodeIDPrefix = "node"
    46  
    47  	// KeyHealthAlertPrefix is the key prefix for gossiping health alerts. The
    48  	// value is a proto of type HealthCheckResult.
    49  	KeyNodeHealthAlertPrefix = "health-alert"
    50  
    51  	// KeyNodeLivenessPrefix is the key prefix for gossiping node liveness info.
    52  	KeyNodeLivenessPrefix = "liveness"
    53  
    54  	// KeySentinel is a key for gossip which must not expire or
    55  	// else the node considers itself partitioned and will retry with
    56  	// bootstrap hosts.  The sentinel is gossiped by the node that holds
    57  	// the range lease for the first range.
    58  	KeySentinel = "sentinel"
    59  
    60  	// KeyFirstRangeDescriptor is the descriptor for the "first"
    61  	// range. The "first" range contains the meta1 key range, the first
    62  	// level of the bi-level key addressing scheme. The value is a slice
    63  	// of storage.Replica structs.
    64  	KeyFirstRangeDescriptor = "first-range"
    65  
    66  	// KeySystemConfig is the gossip key for the system DB span.
    67  	// The value if a config.SystemConfig which holds all key/value
    68  	// pairs in the system DB span.
    69  	KeySystemConfig = "system-db"
    70  
    71  	// KeyDistSQLNodeVersionKeyPrefix is key prefix for each node's DistSQL
    72  	// version.
    73  	KeyDistSQLNodeVersionKeyPrefix = "distsql-version"
    74  
    75  	// KeyDistSQLDrainingPrefix is the key prefix for each node's DistSQL
    76  	// draining state.
    77  	KeyDistSQLDrainingPrefix = "distsql-draining"
    78  
    79  	// KeyTableStatAddedPrefix is the prefix for keys that indicate a new table
    80  	// statistic was computed. The statistics themselves are not stored in gossip;
    81  	// the keys are used to notify nodes to invalidate table statistic caches.
    82  	KeyTableStatAddedPrefix = "table-stat-added"
    83  
    84  	// KeyGossipClientsPrefix is the prefix for keys that indicate which gossip
    85  	// client connections a node has open. This is used by other nodes in the
    86  	// cluster to build a map of the gossip network.
    87  	KeyGossipClientsPrefix = "gossip-clients"
    88  
    89  	// KeyGossipStatementDiagnosticsRequest is the gossip key for new statement
    90  	// diagnostics requests. The values is the id of the request that generated
    91  	// the notification, as a little-endian-encoded uint64.
    92  	// stmtDiagnosticsRequestRegistry listens for notifications and responds by
    93  	// polling for new requests.
    94  	KeyGossipStatementDiagnosticsRequest = "stmt-diag-req"
    95  )
    96  
    97  // MakeKey creates a canonical key under which to gossip a piece of
    98  // information. The first argument will typically be one of the key constants
    99  // defined in this package.
   100  func MakeKey(components ...string) string {
   101  	return strings.Join(components, separator)
   102  }
   103  
   104  // MakePrefixPattern returns a regular expression pattern that
   105  // matches precisely the Gossip keys created by invocations of
   106  // MakeKey with multiple arguments for which the first argument
   107  // is equal to the given prefix.
   108  func MakePrefixPattern(prefix string) string {
   109  	return regexp.QuoteMeta(prefix+separator) + ".*"
   110  }
   111  
   112  // MakeNodeIDKey returns the gossip key for node ID info.
   113  func MakeNodeIDKey(nodeID roachpb.NodeID) string {
   114  	return MakeKey(KeyNodeIDPrefix, nodeID.String())
   115  }
   116  
   117  // IsNodeIDKey returns true iff the provided key is a valid node ID key.
   118  func IsNodeIDKey(key string) bool {
   119  	return strings.HasPrefix(key, KeyNodeIDPrefix+separator)
   120  }
   121  
   122  // NodeIDFromKey attempts to extract a NodeID from the provided key after
   123  // stripping the provided prefix. Returns an error if the key is not of the
   124  // correct type or is not parsable.
   125  func NodeIDFromKey(key string, prefix string) (roachpb.NodeID, error) {
   126  	trimmedKey, err := removePrefixFromKey(key, prefix)
   127  	if err != nil {
   128  		return 0, err
   129  	}
   130  	nodeID, err := strconv.ParseInt(trimmedKey, 10 /* base */, 64 /* bitSize */)
   131  	if err != nil {
   132  		return 0, errors.Wrapf(err, "failed parsing NodeID from key %q", key)
   133  	}
   134  	return roachpb.NodeID(nodeID), nil
   135  }
   136  
   137  // MakeGossipClientsKey returns the gossip client key for the given node.
   138  func MakeGossipClientsKey(nodeID roachpb.NodeID) string {
   139  	return MakeKey(KeyGossipClientsPrefix, nodeID.String())
   140  }
   141  
   142  // MakeNodeHealthAlertKey returns the gossip key under which the given node can
   143  // gossip health alerts.
   144  func MakeNodeHealthAlertKey(nodeID roachpb.NodeID) string {
   145  	return MakeKey(KeyNodeHealthAlertPrefix, strconv.Itoa(int(nodeID)))
   146  }
   147  
   148  // MakeNodeLivenessKey returns the gossip key for node liveness info.
   149  func MakeNodeLivenessKey(nodeID roachpb.NodeID) string {
   150  	return MakeKey(KeyNodeLivenessPrefix, nodeID.String())
   151  }
   152  
   153  // MakeStoreKey returns the gossip key for the given store.
   154  func MakeStoreKey(storeID roachpb.StoreID) string {
   155  	return MakeKey(KeyStorePrefix, storeID.String())
   156  }
   157  
   158  // StoreIDFromKey attempts to extract a StoreID from the provided key after
   159  // stripping the provided prefix. Returns an error if the key is not of the
   160  // correct type or is not parsable.
   161  func StoreIDFromKey(storeKey string) (roachpb.StoreID, error) {
   162  	trimmedKey, err := removePrefixFromKey(storeKey, KeyStorePrefix)
   163  	if err != nil {
   164  		return 0, err
   165  	}
   166  	storeID, err := strconv.ParseInt(trimmedKey, 10 /* base */, 64 /* bitSize */)
   167  	if err != nil {
   168  		return 0, errors.Wrapf(err, "failed parsing StoreID from key %q", storeKey)
   169  	}
   170  	return roachpb.StoreID(storeID), nil
   171  }
   172  
   173  // MakeDistSQLNodeVersionKey returns the gossip key for the given store.
   174  func MakeDistSQLNodeVersionKey(nodeID roachpb.NodeID) string {
   175  	return MakeKey(KeyDistSQLNodeVersionKeyPrefix, nodeID.String())
   176  }
   177  
   178  // MakeDistSQLDrainingKey returns the gossip key for the given node's distsql
   179  // draining state.
   180  func MakeDistSQLDrainingKey(nodeID roachpb.NodeID) string {
   181  	return MakeKey(KeyDistSQLDrainingPrefix, nodeID.String())
   182  }
   183  
   184  // MakeTableStatAddedKey returns the gossip key used to notify that a new
   185  // statistic is available for the given table.
   186  func MakeTableStatAddedKey(tableID uint32) string {
   187  	return MakeKey(KeyTableStatAddedPrefix, strconv.FormatUint(uint64(tableID), 10 /* base */))
   188  }
   189  
   190  // TableIDFromTableStatAddedKey attempts to extract the table ID from the
   191  // provided key.
   192  // The key should have been constructed by MakeTableStatAddedKey.
   193  // Returns an error if the key is not of the correct type or is not parsable.
   194  func TableIDFromTableStatAddedKey(key string) (uint32, error) {
   195  	trimmedKey, err := removePrefixFromKey(key, KeyTableStatAddedPrefix)
   196  	if err != nil {
   197  		return 0, err
   198  	}
   199  	tableID, err := strconv.ParseUint(trimmedKey, 10 /* base */, 32 /* bitSize */)
   200  	if err != nil {
   201  		return 0, errors.Wrapf(err, "failed parsing table ID from key %q", key)
   202  	}
   203  	return uint32(tableID), nil
   204  }
   205  
   206  // removePrefixFromKey removes the key prefix and separator and returns what's
   207  // left. Returns an error if the key doesn't have this prefix.
   208  func removePrefixFromKey(key, prefix string) (string, error) {
   209  	trimmedKey := strings.TrimPrefix(key, prefix+separator)
   210  	if trimmedKey == key {
   211  		return "", errors.Errorf("%q does not have expected prefix %q%s", key, prefix, separator)
   212  	}
   213  	return trimmedKey, nil
   214  }