github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/allocator/allocator.go (about) 1 package allocator 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/docker/docker/pkg/plugingetter" 8 "github.com/docker/go-events" 9 "github.com/docker/swarmkit/api" 10 "github.com/docker/swarmkit/manager/allocator/cnmallocator" 11 "github.com/docker/swarmkit/manager/state" 12 "github.com/docker/swarmkit/manager/state/store" 13 ) 14 15 // Allocator controls how the allocation stage in the manager is handled. 16 type Allocator struct { 17 // The manager store. 18 store *store.MemoryStore 19 20 // the ballot used to synchronize across all allocators to ensure 21 // all of them have completed their respective allocations so that the 22 // task can be moved to ALLOCATED state. 23 taskBallot *taskBallot 24 25 // context for the network allocator that will be needed by 26 // network allocator. 27 netCtx *networkContext 28 29 // stopChan signals to the allocator to stop running. 30 stopChan chan struct{} 31 // doneChan is closed when the allocator is finished running. 32 doneChan chan struct{} 33 34 // pluginGetter provides access to docker's plugin inventory. 35 pluginGetter plugingetter.PluginGetter 36 37 // networkConfig stores network related config for the cluster 38 networkConfig *cnmallocator.NetworkConfig 39 } 40 41 // taskBallot controls how the voting for task allocation is 42 // coordinated b/w different allocators. This the only structure that 43 // will be written by all allocator goroutines concurrently. Hence the 44 // mutex. 45 type taskBallot struct { 46 sync.Mutex 47 48 // List of registered voters who have to cast their vote to 49 // indicate their allocation complete 50 voters []string 51 52 // List of votes collected for every task so far from different voters. 53 votes map[string][]string 54 } 55 56 // allocActor controls the various phases in the lifecycle of one kind of allocator. 57 type allocActor struct { 58 // Task voter identity of the allocator. 59 taskVoter string 60 61 // Action routine which is called for every event that the 62 // allocator received. 63 action func(context.Context, events.Event) 64 65 // Init routine which is called during the initialization of 66 // the allocator. 67 init func(ctx context.Context) error 68 } 69 70 // New returns a new instance of Allocator for use during allocation 71 // stage of the manager. 72 func New(store *store.MemoryStore, pg plugingetter.PluginGetter, netConfig *cnmallocator.NetworkConfig) (*Allocator, error) { 73 a := &Allocator{ 74 store: store, 75 taskBallot: &taskBallot{ 76 votes: make(map[string][]string), 77 }, 78 stopChan: make(chan struct{}), 79 doneChan: make(chan struct{}), 80 pluginGetter: pg, 81 networkConfig: netConfig, 82 } 83 84 return a, nil 85 } 86 87 // Run starts all allocator go-routines and waits for Stop to be called. 88 func (a *Allocator) Run(ctx context.Context) error { 89 // Setup cancel context for all goroutines to use. 90 ctx, cancel := context.WithCancel(ctx) 91 var ( 92 wg sync.WaitGroup 93 actors []func() error 94 ) 95 96 defer func() { 97 cancel() 98 wg.Wait() 99 close(a.doneChan) 100 }() 101 102 for _, aa := range []allocActor{ 103 { 104 taskVoter: networkVoter, 105 init: a.doNetworkInit, 106 action: a.doNetworkAlloc, 107 }, 108 } { 109 if aa.taskVoter != "" { 110 a.registerToVote(aa.taskVoter) 111 } 112 113 // Assign a pointer for variable capture 114 aaPtr := &aa 115 actor := func() error { 116 wg.Add(1) 117 defer wg.Done() 118 119 // init might return an allocator specific context 120 // which is a child of the passed in context to hold 121 // allocator specific state 122 watch, watchCancel, err := a.init(ctx, aaPtr) 123 if err != nil { 124 return err 125 } 126 127 wg.Add(1) 128 go func(watch <-chan events.Event, watchCancel func()) { 129 defer func() { 130 wg.Done() 131 watchCancel() 132 }() 133 a.run(ctx, *aaPtr, watch) 134 }(watch, watchCancel) 135 return nil 136 } 137 138 actors = append(actors, actor) 139 } 140 141 for _, actor := range actors { 142 if err := actor(); err != nil { 143 return err 144 } 145 } 146 147 <-a.stopChan 148 return nil 149 } 150 151 // Stop stops the allocator 152 func (a *Allocator) Stop() { 153 close(a.stopChan) 154 // Wait for all allocator goroutines to truly exit 155 <-a.doneChan 156 } 157 158 func (a *Allocator) init(ctx context.Context, aa *allocActor) (<-chan events.Event, func(), error) { 159 watch, watchCancel := state.Watch(a.store.WatchQueue(), 160 api.EventCreateNetwork{}, 161 api.EventDeleteNetwork{}, 162 api.EventCreateService{}, 163 api.EventUpdateService{}, 164 api.EventDeleteService{}, 165 api.EventCreateTask{}, 166 api.EventUpdateTask{}, 167 api.EventDeleteTask{}, 168 api.EventCreateNode{}, 169 api.EventUpdateNode{}, 170 api.EventDeleteNode{}, 171 state.EventCommit{}, 172 ) 173 174 if err := aa.init(ctx); err != nil { 175 watchCancel() 176 return nil, nil, err 177 } 178 179 return watch, watchCancel, nil 180 } 181 182 func (a *Allocator) run(ctx context.Context, aa allocActor, watch <-chan events.Event) { 183 for { 184 select { 185 case ev, ok := <-watch: 186 if !ok { 187 return 188 } 189 190 aa.action(ctx, ev) 191 case <-ctx.Done(): 192 return 193 } 194 } 195 } 196 197 func (a *Allocator) registerToVote(name string) { 198 a.taskBallot.Lock() 199 defer a.taskBallot.Unlock() 200 201 a.taskBallot.voters = append(a.taskBallot.voters, name) 202 } 203 204 func (a *Allocator) taskAllocateVote(voter string, id string) bool { 205 a.taskBallot.Lock() 206 defer a.taskBallot.Unlock() 207 208 // If voter has already voted, return false 209 for _, v := range a.taskBallot.votes[id] { 210 // check if voter is in x 211 if v == voter { 212 return false 213 } 214 } 215 216 a.taskBallot.votes[id] = append(a.taskBallot.votes[id], voter) 217 218 // We haven't gotten enough votes yet 219 if len(a.taskBallot.voters) > len(a.taskBallot.votes[id]) { 220 return false 221 } 222 223 nextVoter: 224 for _, voter := range a.taskBallot.voters { 225 for _, vote := range a.taskBallot.votes[id] { 226 if voter == vote { 227 continue nextVoter 228 } 229 } 230 231 // Not every registered voter has registered a vote. 232 return false 233 } 234 235 return true 236 }