github.com/m3db/m3@v1.5.0/src/dbnode/topology/testutil/topology.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package testutil
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"github.com/m3db/m3/src/cluster/shard"
    27  	"github.com/m3db/m3/src/dbnode/sharding"
    28  	"github.com/m3db/m3/src/dbnode/topology"
    29  )
    30  
    31  const (
    32  	// SelfID is the string used to represent the ID of the origin node.
    33  	SelfID = "self"
    34  )
    35  
    36  // MustNewTopologyMap returns a new topology.Map with provided parameters.
    37  // It's a utility method to make tests easier to write.
    38  func MustNewTopologyMap(
    39  	replicas int,
    40  	assignment map[string][]shard.Shard,
    41  ) topology.Map {
    42  	v := NewTopologyView(replicas, assignment)
    43  	m, err := v.Map()
    44  	if err != nil {
    45  		panic(err.Error())
    46  	}
    47  	return m
    48  }
    49  
    50  // NewTopologyView returns a new TopologyView with provided parameters.
    51  // It's a utility method to make tests easier to write.
    52  func NewTopologyView(
    53  	replicas int,
    54  	assignment map[string][]shard.Shard,
    55  ) TopologyView {
    56  	total := 0
    57  	for _, shards := range assignment {
    58  		total += len(shards)
    59  	}
    60  
    61  	return TopologyView{
    62  		HashFn:     sharding.DefaultHashFn(total / replicas),
    63  		Replicas:   replicas,
    64  		Assignment: assignment,
    65  	}
    66  }
    67  
    68  // TopologyView represents a snaphshot view of a topology.Map.
    69  type TopologyView struct {
    70  	HashFn     sharding.HashFn
    71  	Replicas   int
    72  	Assignment map[string][]shard.Shard
    73  }
    74  
    75  // Map returns the topology.Map corresponding to a TopologyView.
    76  func (v TopologyView) Map() (topology.Map, error) {
    77  	var (
    78  		hostShardSets []topology.HostShardSet
    79  		allShards     []shard.Shard
    80  		unique        = make(map[uint32]struct{})
    81  	)
    82  
    83  	for hostID, assignedShards := range v.Assignment {
    84  		shardSet, _ := sharding.NewShardSet(assignedShards, v.HashFn)
    85  		host := topology.NewHost(hostID, fmt.Sprintf("%s:9000", hostID))
    86  		hostShardSet := topology.NewHostShardSet(host, shardSet)
    87  		hostShardSets = append(hostShardSets, hostShardSet)
    88  		for _, s := range assignedShards {
    89  			if _, ok := unique[s.ID()]; !ok {
    90  				unique[s.ID()] = struct{}{}
    91  				uniqueShard := shard.NewShard(s.ID()).SetState(shard.Available)
    92  				allShards = append(allShards, uniqueShard)
    93  			}
    94  		}
    95  	}
    96  
    97  	shardSet, err := sharding.NewShardSet(allShards, v.HashFn)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	opts := topology.NewStaticOptions().
   103  		SetHostShardSets(hostShardSets).
   104  		SetReplicas(v.Replicas).
   105  		SetShardSet(shardSet)
   106  
   107  	return topology.NewStaticMap(opts), nil
   108  }
   109  
   110  // HostShardStates is a human-readable way of describing an initial state topology
   111  // on a host-by-host basis.
   112  type HostShardStates map[string][]shard.Shard
   113  
   114  // NewStateSnapshot creates a new initial topology state snapshot using HostShardStates
   115  // as input.
   116  func NewStateSnapshot(numMajorityReplicas int, hostShardStates HostShardStates) *topology.StateSnapshot {
   117  	topoState := &topology.StateSnapshot{
   118  		Origin:           topology.NewHost(SelfID, "127.0.0.1"),
   119  		MajorityReplicas: numMajorityReplicas,
   120  		ShardStates:      make(map[topology.ShardID]map[topology.HostID]topology.HostShardState),
   121  	}
   122  
   123  	for host, shards := range hostShardStates {
   124  		for _, shard := range shards {
   125  			hostShardStates, ok := topoState.ShardStates[topology.ShardID(shard.ID())]
   126  			if !ok {
   127  				hostShardStates = make(map[topology.HostID]topology.HostShardState)
   128  			}
   129  
   130  			hostShardStates[topology.HostID(host)] = topology.HostShardState{
   131  				Host:       topology.NewHost(host, host+"address"),
   132  				ShardState: shard.State(),
   133  			}
   134  			topoState.ShardStates[topology.ShardID(shard.ID())] = hostShardStates
   135  		}
   136  	}
   137  
   138  	return topoState
   139  }