github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/logbroker/subscription.go (about) 1 package logbroker 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "sync" 8 9 events "github.com/docker/go-events" 10 "github.com/docker/swarmkit/api" 11 "github.com/docker/swarmkit/log" 12 "github.com/docker/swarmkit/manager/state" 13 "github.com/docker/swarmkit/manager/state/store" 14 "github.com/docker/swarmkit/watch" 15 ) 16 17 type subscription struct { 18 mu sync.RWMutex 19 wg sync.WaitGroup 20 21 store *store.MemoryStore 22 message *api.SubscriptionMessage 23 changed *watch.Queue 24 25 ctx context.Context 26 cancel context.CancelFunc 27 28 errors []error 29 nodes map[string]struct{} 30 pendingTasks map[string]struct{} 31 } 32 33 func newSubscription(store *store.MemoryStore, message *api.SubscriptionMessage, changed *watch.Queue) *subscription { 34 return &subscription{ 35 store: store, 36 message: message, 37 changed: changed, 38 nodes: make(map[string]struct{}), 39 pendingTasks: make(map[string]struct{}), 40 } 41 } 42 43 func (s *subscription) follow() bool { 44 return s.message.Options != nil && s.message.Options.Follow 45 } 46 47 func (s *subscription) Contains(nodeID string) bool { 48 s.mu.RLock() 49 defer s.mu.RUnlock() 50 51 _, ok := s.nodes[nodeID] 52 return ok 53 } 54 55 func (s *subscription) Nodes() []string { 56 s.mu.RLock() 57 defer s.mu.RUnlock() 58 59 nodes := make([]string, 0, len(s.nodes)) 60 for node := range s.nodes { 61 nodes = append(nodes, node) 62 } 63 return nodes 64 } 65 66 func (s *subscription) Run(ctx context.Context) { 67 s.ctx, s.cancel = context.WithCancel(ctx) 68 69 if s.follow() { 70 wq := s.store.WatchQueue() 71 ch, cancel := state.Watch(wq, api.EventCreateTask{}, api.EventUpdateTask{}) 72 go func() { 73 defer cancel() 74 s.watch(ch) 75 }() 76 } 77 78 s.match() 79 } 80 81 func (s *subscription) Stop() { 82 if s.cancel != nil { 83 s.cancel() 84 } 85 } 86 87 func (s *subscription) Wait(ctx context.Context) <-chan struct{} { 88 // Follow subscriptions never end 89 if s.follow() { 90 return nil 91 } 92 93 ch := make(chan struct{}) 94 go func() { 95 defer close(ch) 96 s.wg.Wait() 97 }() 98 return ch 99 } 100 101 func (s *subscription) Done(nodeID string, err error) { 102 s.mu.Lock() 103 defer s.mu.Unlock() 104 105 if err != nil { 106 s.errors = append(s.errors, err) 107 } 108 109 if s.follow() { 110 return 111 } 112 113 if _, ok := s.nodes[nodeID]; !ok { 114 return 115 } 116 117 delete(s.nodes, nodeID) 118 s.wg.Done() 119 } 120 121 func (s *subscription) Err() error { 122 s.mu.RLock() 123 defer s.mu.RUnlock() 124 125 if len(s.errors) == 0 && len(s.pendingTasks) == 0 { 126 return nil 127 } 128 129 messages := make([]string, 0, len(s.errors)) 130 for _, err := range s.errors { 131 messages = append(messages, err.Error()) 132 } 133 for t := range s.pendingTasks { 134 messages = append(messages, fmt.Sprintf("task %s has not been scheduled", t)) 135 } 136 137 return fmt.Errorf("warning: incomplete log stream. some logs could not be retrieved for the following reasons: %s", strings.Join(messages, ", ")) 138 } 139 140 func (s *subscription) Close() { 141 s.mu.Lock() 142 s.message.Close = true 143 s.mu.Unlock() 144 } 145 146 func (s *subscription) Closed() bool { 147 s.mu.RLock() 148 defer s.mu.RUnlock() 149 return s.message.Close 150 } 151 152 func (s *subscription) match() { 153 s.mu.Lock() 154 defer s.mu.Unlock() 155 156 add := func(t *api.Task) { 157 if t.NodeID == "" { 158 s.pendingTasks[t.ID] = struct{}{} 159 return 160 } 161 if _, ok := s.nodes[t.NodeID]; !ok { 162 s.nodes[t.NodeID] = struct{}{} 163 s.wg.Add(1) 164 } 165 } 166 167 s.store.View(func(tx store.ReadTx) { 168 for _, nid := range s.message.Selector.NodeIDs { 169 s.nodes[nid] = struct{}{} 170 } 171 172 for _, tid := range s.message.Selector.TaskIDs { 173 if task := store.GetTask(tx, tid); task != nil { 174 add(task) 175 } 176 } 177 178 for _, sid := range s.message.Selector.ServiceIDs { 179 tasks, err := store.FindTasks(tx, store.ByServiceID(sid)) 180 if err != nil { 181 log.L.Warning(err) 182 continue 183 } 184 for _, task := range tasks { 185 // if we're not following, don't add tasks that aren't running yet 186 if !s.follow() && task.Status.State < api.TaskStateRunning { 187 continue 188 } 189 add(task) 190 } 191 } 192 }) 193 } 194 195 func (s *subscription) watch(ch <-chan events.Event) error { 196 matchTasks := map[string]struct{}{} 197 for _, tid := range s.message.Selector.TaskIDs { 198 matchTasks[tid] = struct{}{} 199 } 200 201 matchServices := map[string]struct{}{} 202 for _, sid := range s.message.Selector.ServiceIDs { 203 matchServices[sid] = struct{}{} 204 } 205 206 add := func(t *api.Task) { 207 // this mutex does not have a deferred unlock, because there is work 208 // we need to do after we release it. 209 s.mu.Lock() 210 211 // Un-allocated task. 212 if t.NodeID == "" { 213 s.pendingTasks[t.ID] = struct{}{} 214 s.mu.Unlock() 215 return 216 } 217 218 delete(s.pendingTasks, t.ID) 219 if _, ok := s.nodes[t.NodeID]; !ok { 220 s.nodes[t.NodeID] = struct{}{} 221 222 s.mu.Unlock() 223 224 // if we try to call Publish before we release the lock, we can end 225 // up in a situation where the receiver is trying to acquire a read 226 // lock on it. it's hard to explain. 227 s.changed.Publish(s) 228 return 229 } 230 231 s.mu.Unlock() 232 } 233 234 for { 235 var t *api.Task 236 select { 237 case <-s.ctx.Done(): 238 return s.ctx.Err() 239 case event := <-ch: 240 switch v := event.(type) { 241 case api.EventCreateTask: 242 t = v.Task 243 case api.EventUpdateTask: 244 t = v.Task 245 } 246 } 247 248 if t == nil { 249 panic("received invalid task from the watch queue") 250 } 251 252 if _, ok := matchTasks[t.ID]; ok { 253 add(t) 254 } 255 if _, ok := matchServices[t.ServiceID]; ok { 256 add(t) 257 } 258 } 259 }