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  }