github.com/m3db/m3@v1.5.0/src/dbnode/integration/fake/cluster_services.go (about)

     1  // Copyright (c) 2017 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 fake
    22  
    23  import (
    24  	"fmt"
    25  	"sync"
    26  
    27  	"github.com/m3db/m3/src/cluster/client"
    28  	"github.com/m3db/m3/src/cluster/kv"
    29  	"github.com/m3db/m3/src/cluster/placement"
    30  	"github.com/m3db/m3/src/cluster/services"
    31  	xwatch "github.com/m3db/m3/src/x/watch"
    32  )
    33  
    34  // NB(r): once a lot more feature complete move this to the m3cluster repository
    35  
    36  // M3ClusterClient is a fake m3cluster client
    37  type M3ClusterClient interface {
    38  	client.Client
    39  }
    40  
    41  // M3ClusterServices is a fake m3cluster services
    42  type M3ClusterServices interface {
    43  	services.Services
    44  
    45  	// RegisterService registers a fake m3cluster service
    46  	RegisterService(name string, svc M3ClusterService)
    47  
    48  	// NotifyServiceUpdate will trigger any watch to fire for a service
    49  	NotifyServiceUpdate(name string)
    50  
    51  	// FakePlacementService returns the fake m3cluster placement service
    52  	FakePlacementService() M3ClusterPlacementService
    53  }
    54  
    55  // M3ClusterService is a fake m3cluster service, mainly used
    56  // to add synchronization and avoid data races with the default
    57  // service implementation included in m3cluster
    58  type M3ClusterService interface {
    59  	services.Service
    60  }
    61  
    62  // M3ClusterPlacementService is a fake m3cluster placement service
    63  type M3ClusterPlacementService interface {
    64  	placement.Service
    65  
    66  	// InstanceShardsMarkedAvailable returns instance shards marked as available
    67  	InstanceShardsMarkedAvailable() map[string][]uint32
    68  }
    69  
    70  // M3ClusterKVStore is a fake m3cluster kv store
    71  type M3ClusterKVStore interface {
    72  	kv.Store
    73  }
    74  
    75  // M3ClusterTxnStore is a fake m3cluster txn store
    76  type M3ClusterTxnStore interface {
    77  	kv.TxnStore
    78  }
    79  
    80  // NewM3ClusterClient creates a new fake m3cluster client
    81  func NewM3ClusterClient(
    82  	services M3ClusterServices,
    83  	kvStore M3ClusterKVStore,
    84  ) M3ClusterClient {
    85  	return &m3ClusterClient{services: services, kvStore: kvStore}
    86  }
    87  
    88  type m3ClusterClient struct {
    89  	services M3ClusterServices
    90  	kvStore  M3ClusterKVStore
    91  	txnStore M3ClusterTxnStore
    92  }
    93  
    94  func (c *m3ClusterClient) Services(_ services.OverrideOptions) (services.Services, error) {
    95  	return c.services, nil
    96  }
    97  
    98  func (c *m3ClusterClient) KV() (kv.Store, error) {
    99  	return c.kvStore, nil
   100  }
   101  
   102  func (c *m3ClusterClient) Txn() (kv.TxnStore, error) {
   103  	return c.txnStore, nil
   104  }
   105  
   106  func (c *m3ClusterClient) Store(_ kv.OverrideOptions) (kv.Store, error) {
   107  	return c.kvStore, nil
   108  }
   109  
   110  func (c *m3ClusterClient) TxnStore(_ kv.OverrideOptions) (kv.TxnStore, error) {
   111  	return c.txnStore, nil
   112  }
   113  
   114  // NewM3ClusterServices creates a new fake m3cluster services
   115  func NewM3ClusterServices() M3ClusterServices {
   116  	return &m3ClusterServices{
   117  		services:         make(map[string]*m3RegisteredService),
   118  		placementService: NewM3ClusterPlacementService(),
   119  	}
   120  }
   121  
   122  // NewM3ClusterServicesWithPlacementService creates a new fake m3cluster services with given placement service.
   123  func NewM3ClusterServicesWithPlacementService(placementSvc M3ClusterPlacementService) M3ClusterServices {
   124  	return &m3ClusterServices{
   125  		services:         make(map[string]*m3RegisteredService),
   126  		placementService: placementSvc,
   127  	}
   128  }
   129  
   130  type m3ClusterServices struct {
   131  	sync.RWMutex
   132  	services         map[string]*m3RegisteredService
   133  	placementService M3ClusterPlacementService
   134  }
   135  
   136  type m3RegisteredService struct {
   137  	service   M3ClusterService
   138  	watchable xwatch.Watchable
   139  }
   140  
   141  func (s *m3ClusterServices) RegisterService(
   142  	name string,
   143  	svc M3ClusterService,
   144  ) {
   145  	s.Lock()
   146  	defer s.Unlock()
   147  	watchable := xwatch.NewWatchable()
   148  	watchable.Update(svc)
   149  	s.services[name] = &m3RegisteredService{
   150  		service:   svc,
   151  		watchable: watchable,
   152  	}
   153  }
   154  
   155  func (s *m3ClusterServices) NotifyServiceUpdate(
   156  	name string,
   157  ) {
   158  	s.RLock()
   159  	defer s.RUnlock()
   160  	svc := s.services[name].service
   161  	s.services[name].watchable.Update(svc)
   162  }
   163  
   164  func (s *m3ClusterServices) FakePlacementService() M3ClusterPlacementService {
   165  	return s.placementService
   166  }
   167  
   168  func (s *m3ClusterServices) Advertise(
   169  	ad services.Advertisement,
   170  ) error {
   171  	return fmt.Errorf("not implemented")
   172  }
   173  
   174  func (s *m3ClusterServices) Unadvertise(
   175  	service services.ServiceID,
   176  	id string,
   177  ) error {
   178  	return fmt.Errorf("not implemented")
   179  }
   180  
   181  func (s *m3ClusterServices) Query(
   182  	service services.ServiceID,
   183  	opts services.QueryOptions,
   184  ) (services.Service, error) {
   185  	s.RLock()
   186  	defer s.RUnlock()
   187  	if entry, ok := s.services[service.Name()]; ok {
   188  		return entry.service, nil
   189  	}
   190  	return nil, fmt.Errorf("service not found: %s", service.Name())
   191  }
   192  
   193  func (s *m3ClusterServices) Watch(
   194  	service services.ServiceID,
   195  	opts services.QueryOptions,
   196  ) (services.Watch, error) {
   197  	s.RLock()
   198  	defer s.RUnlock()
   199  	if entry, ok := s.services[service.Name()]; ok {
   200  		_, watch, err := entry.watchable.Watch()
   201  		if err != nil {
   202  			return nil, err
   203  		}
   204  		return services.NewWatch(watch), nil
   205  	}
   206  	return nil, fmt.Errorf("service not found: %s", service.Name())
   207  }
   208  
   209  func (s *m3ClusterServices) Metadata(
   210  	sid services.ServiceID,
   211  ) (services.Metadata, error) {
   212  	return nil, fmt.Errorf("not implemented")
   213  }
   214  
   215  func (s *m3ClusterServices) SetMetadata(
   216  	sid services.ServiceID, m services.Metadata,
   217  ) error {
   218  	return fmt.Errorf("not implemented")
   219  }
   220  
   221  func (s *m3ClusterServices) DeleteMetadata(
   222  	sid services.ServiceID,
   223  ) error {
   224  	return fmt.Errorf("not implemented")
   225  }
   226  
   227  func (s *m3ClusterServices) PlacementService(
   228  	service services.ServiceID,
   229  	popts placement.Options,
   230  ) (placement.Service, error) {
   231  	return s.placementService, nil
   232  }
   233  
   234  func (s *m3ClusterServices) HeartbeatService(
   235  	service services.ServiceID,
   236  ) (services.HeartbeatService, error) {
   237  	return nil, fmt.Errorf("not implemented")
   238  }
   239  
   240  func (s *m3ClusterServices) LeaderService(
   241  	service services.ServiceID,
   242  	opts services.ElectionOptions,
   243  ) (services.LeaderService, error) {
   244  	return nil, fmt.Errorf("not implemented")
   245  }
   246  
   247  // NewM3ClusterPlacementService creates a fake m3cluster placement service
   248  func NewM3ClusterPlacementService() M3ClusterPlacementService {
   249  	return &m3ClusterPlacementService{
   250  		markedAvailable: make(map[string][]uint32),
   251  	}
   252  }
   253  
   254  type m3ClusterPlacementService struct {
   255  	placement.Service
   256  
   257  	markedAvailable map[string][]uint32
   258  }
   259  
   260  func (s *m3ClusterPlacementService) InstanceShardsMarkedAvailable() map[string][]uint32 {
   261  	return s.markedAvailable
   262  }
   263  func (s *m3ClusterPlacementService) MarkShardsAvailable(
   264  	instanceID string, shardIDs ...uint32,
   265  ) (placement.Placement, error) {
   266  	s.markedAvailable[instanceID] = append(s.markedAvailable[instanceID], shardIDs...)
   267  	return nil, nil
   268  }
   269  
   270  // NewM3ClusterService creates a new fake m3cluster service
   271  func NewM3ClusterService() M3ClusterService {
   272  	return &m3ClusterService{}
   273  }
   274  
   275  type m3ClusterService struct {
   276  	sync.RWMutex
   277  	instances   []services.ServiceInstance
   278  	replication services.ServiceReplication
   279  	sharding    services.ServiceSharding
   280  }
   281  
   282  func (s *m3ClusterService) Instance(
   283  	instanceID string,
   284  ) (services.ServiceInstance, error) {
   285  	s.RLock()
   286  	defer s.RUnlock()
   287  	for _, instance := range s.instances {
   288  		if instance.InstanceID() == instanceID {
   289  			return instance, nil
   290  		}
   291  	}
   292  	return nil, fmt.Errorf("instance not found")
   293  }
   294  
   295  func (s *m3ClusterService) Instances() []services.ServiceInstance {
   296  	s.RLock()
   297  	defer s.RUnlock()
   298  	return s.instances
   299  }
   300  
   301  func (s *m3ClusterService) Replication() services.ServiceReplication {
   302  	s.RLock()
   303  	defer s.RUnlock()
   304  	return s.replication
   305  }
   306  
   307  func (s *m3ClusterService) Sharding() services.ServiceSharding {
   308  	s.RLock()
   309  	defer s.RUnlock()
   310  	return s.sharding
   311  }
   312  
   313  func (s *m3ClusterService) SetInstances(
   314  	insts []services.ServiceInstance,
   315  ) services.Service {
   316  	s.Lock()
   317  	defer s.Unlock()
   318  	s.instances = insts
   319  	return s
   320  }
   321  
   322  func (s *m3ClusterService) SetReplication(
   323  	r services.ServiceReplication,
   324  ) services.Service {
   325  	s.Lock()
   326  	defer s.Unlock()
   327  	s.replication = r
   328  	return s
   329  }
   330  
   331  func (s *m3ClusterService) SetSharding(
   332  	ss services.ServiceSharding,
   333  ) services.Service {
   334  	s.Lock()
   335  	defer s.Unlock()
   336  	s.sharding = ss
   337  	return s
   338  }