Prechádzať zdrojové kódy

statsCollector: fix data race in run()

statsCollector.publishers must be protected to prevent
modifications during the iteration in run().
Being locked for a long time is bad, so pairs of containers &
publishers (pointers) are copied to release the lock fast.

Signed-off-by: Anton Tiurin <noxiouz@yandex.ru>
Anton Tiurin 10 rokov pred
rodič
commit
11a5f1af01
1 zmenil súbory, kde vykonal 28 pridanie a 8 odobranie
  1. 28 8
      daemon/stats_collector.go

+ 28 - 8
daemon/stats_collector.go

@@ -76,22 +76,42 @@ func (s *statsCollector) unsubscribe(c *Container, ch chan interface{}) {
 }
 }
 
 
 func (s *statsCollector) run() {
 func (s *statsCollector) run() {
+	type publishersPair struct {
+		container *Container
+		publisher *pubsub.Publisher
+	}
+	// we cannot determine the capacity here.
+	// it will grow enough in first iteration
+	var pairs []publishersPair
+
 	for range time.Tick(s.interval) {
 	for range time.Tick(s.interval) {
+		systemUsage, err := s.getSystemCpuUsage()
+		if err != nil {
+			logrus.Errorf("collecting system cpu usage: %v", err)
+			continue
+		}
+
+		// it does not make sense in the first iteration,
+		// but saves allocations in further iterations
+		pairs = pairs[:0]
+
+		s.m.Lock()
 		for container, publisher := range s.publishers {
 		for container, publisher := range s.publishers {
-			systemUsage, err := s.getSystemCpuUsage()
-			if err != nil {
-				logrus.Errorf("collecting system cpu usage for %s: %v", container.ID, err)
-				continue
-			}
-			stats, err := container.Stats()
+			// copy pointers here to release the lock ASAP
+			pairs = append(pairs, publishersPair{container, publisher})
+		}
+		s.m.Unlock()
+
+		for _, pair := range pairs {
+			stats, err := pair.container.Stats()
 			if err != nil {
 			if err != nil {
 				if err != execdriver.ErrNotRunning {
 				if err != execdriver.ErrNotRunning {
-					logrus.Errorf("collecting stats for %s: %v", container.ID, err)
+					logrus.Errorf("collecting stats for %s: %v", pair.container.ID, err)
 				}
 				}
 				continue
 				continue
 			}
 			}
 			stats.SystemUsage = systemUsage
 			stats.SystemUsage = systemUsage
-			publisher.Publish(stats)
+			pair.publisher.Publish(stats)
 		}
 		}
 	}
 	}
 }
 }