github.com/m3db/m3@v1.5.0/src/cluster/placement/service/operator.go (about) 1 // Copyright (c) 2020 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 22 package service 23 24 import ( 25 "errors" 26 27 "github.com/m3db/m3/src/cluster/placement" 28 ) 29 30 // NewPlacementOperator constructs a placement.Operator which performs transformations on the 31 // given placement. 32 // If initialPlacement is nil, BuildInitialPlacement must be called before any operations on the 33 // placement. 34 func NewPlacementOperator(initialPlacement placement.Placement, opts ...Option) placement.Operator { 35 store := newDummyStore(initialPlacement) 36 return &placementOperator{ 37 placementServiceImpl: newPlacementServiceImpl(store, opts...), 38 store: store, 39 } 40 } 41 42 // placementOperator is implemented by a placementServiceImpl backed by a dummyStore, which just 43 // sets in memory state and doesn't touch versions. 44 type placementOperator struct { 45 *placementServiceImpl 46 store *dummyStore 47 } 48 49 func (p *placementOperator) Placement() placement.Placement { 50 return p.store.curPlacement 51 } 52 53 // dummyStore is a helper class for placementOperator. It stores a single placement in memory, 54 // allowing us to use the same code to implement the actual placement.Service (which typically talks 55 // to a fully fledged backing store) and placement.Operator, which only operates on memory. 56 // Unlike proper placement.Storage implementations, all operations are unversioned; 57 // version arguments are ignored, and the store never calls Placement.SetVersion. This makes it 58 // distinct from e.g. the implementation in mem.NewStore. 59 type dummyStore struct { 60 curPlacement placement.Placement 61 } 62 63 func newDummyStore(initialPlacement placement.Placement) *dummyStore { 64 return &dummyStore{curPlacement: initialPlacement} 65 } 66 67 func (d *dummyStore) Set(p placement.Placement) (placement.Placement, error) { 68 d.set(p) 69 return d.curPlacement, nil 70 } 71 72 func (d *dummyStore) set(p placement.Placement) { 73 d.curPlacement = p 74 } 75 76 // CheckAndSet on the dummy store is unconditional (no check). 77 func (d *dummyStore) CheckAndSet(p placement.Placement, _ int) (placement.Placement, error) { 78 d.curPlacement = p 79 return d.curPlacement, nil 80 } 81 82 func (d *dummyStore) SetIfNotExist(p placement.Placement) (placement.Placement, error) { 83 if d.curPlacement != nil { 84 return nil, errors.New( 85 "placement already exists and can't be rebuilt. Construct a new placement.Operator", 86 ) 87 } 88 d.curPlacement = p 89 return d.curPlacement, nil 90 } 91 92 func (d *dummyStore) Placement() (placement.Placement, error) { 93 if d.curPlacement == nil { 94 return nil, errors.New( 95 "no initial placement specified at operator construction; call BuildInitialPlacement or pass one in", 96 ) 97 } 98 return d.curPlacement, nil 99 }