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 }