trafficcontrol-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From els...@apache.org
Subject [1/2] incubator-trafficcontrol git commit: Fix TM2 MonitorConfigPoller livelock
Date Mon, 10 Jul 2017 16:30:06 GMT
Repository: incubator-trafficcontrol
Updated Branches:
  refs/heads/master 1829db984 -> c80e72d5f


Fix TM2 MonitorConfigPoller livelock

Fixes the MonitorConfigPoller for-select to be nonblocking, making
livelocks impossible.


Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/4af1b42e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/4af1b42e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/4af1b42e

Branch: refs/heads/master
Commit: 4af1b42e9446c6cf4ff934acae435bc20bd05c0a
Parents: 1829db9
Author: Robert Butts <robert.o.butts@gmail.com>
Authored: Wed Jul 5 14:29:22 2017 -0600
Committer: Jeff Elsloo <jeffrey_elsloo@cable.comcast.com>
Committed: Mon Jul 10 10:29:27 2017 -0600

----------------------------------------------------------------------
 traffic_monitor_golang/common/poller/poller.go  | 39 +++++++++++++-------
 .../traffic_monitor/version.go                  |  2 +-
 2 files changed, 27 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4af1b42e/traffic_monitor_golang/common/poller/poller.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/common/poller/poller.go b/traffic_monitor_golang/common/poller/poller.go
index b79ddaa..e42e4f7 100644
--- a/traffic_monitor_golang/common/poller/poller.go
+++ b/traffic_monitor_golang/common/poller/poller.go
@@ -110,14 +110,28 @@ type MonitorConfigPoller struct {
 // If tick is false, HttpPoller.TickChan() will return nil
 func NewMonitorConfig(interval time.Duration) MonitorConfigPoller {
 	return MonitorConfigPoller{
-		Interval:         interval,
-		SessionChannel:   make(chan towrap.ITrafficOpsSession),
-		ConfigChannel:    make(chan MonitorCfg),
+		Interval:       interval,
+		SessionChannel: make(chan towrap.ITrafficOpsSession),
+		// ConfigChannel MUST have a buffer size 1, to make the nonblocking writeConfig work
+		ConfigChannel:    make(chan MonitorCfg, 1),
 		OpsConfigChannel: make(chan handler.OpsConfig),
 		IntervalChan:     make(chan time.Duration),
 	}
 }
 
+// writeConfig writes the given config to the Config chan. This is nonblocking, and immediately
returns.
+// Because readers only ever want the latest config, if nobody has read the previous write,
we remove it. Since the config chan is buffered size 1, this function is therefore asynchronous.
+func (p MonitorConfigPoller) writeConfig(cfg MonitorCfg) {
+	for {
+		select {
+		case p.ConfigChannel <- cfg:
+			return // return after successfully writing.
+		case <-p.ConfigChannel:
+			// if the channel buffer was full, read, then loop and try to write again
+		}
+	}
+}
+
 func (p MonitorConfigPoller) Poll() {
 	tick := time.NewTicker(p.Interval)
 	defer tick.Stop()
@@ -130,6 +144,7 @@ func (p MonitorConfigPoller) Poll() {
 		os.Exit(1) // The Monitor can't run without a MonitorConfigPoller
 	}()
 	for {
+		// Every case MUST be asynchronous and non-blocking, to prevent livelocks. If a chan must
be written to, it must either be buffered AND remove existing values, or be written to in
a goroutine.
 		select {
 		case opsConfig := <-p.OpsConfigChannel:
 			log.Infof("MonitorConfigPoller: received new opsConfig: %v\n", opsConfig)
@@ -150,18 +165,16 @@ func (p MonitorConfigPoller) Poll() {
 			tick.Stop()
 			tick = time.NewTicker(p.Interval)
 		case <-tick.C:
-			if p.Session != nil && p.OpsConfig.CdnName != "" {
-				monitorConfig, err := p.Session.TrafficMonitorConfigMap(p.OpsConfig.CdnName)
-
-				if err != nil {
-					log.Errorf("MonitorConfigPoller: %s\n %v\n", err, monitorConfig)
-				} else {
-					log.Debugln("MonitorConfigPoller: fetched monitorConfig")
-					p.ConfigChannel <- MonitorCfg{CDN: p.OpsConfig.CdnName, Cfg: *monitorConfig}
-				}
-			} else {
+			if p.Session == nil || p.OpsConfig.CdnName == "" {
 				log.Warnln("MonitorConfigPoller: skipping this iteration, Session is nil")
+				continue
+			}
+			monitorConfig, err := p.Session.TrafficMonitorConfigMap(p.OpsConfig.CdnName)
+			if err != nil {
+				log.Errorf("MonitorConfigPoller: %s\n %v\n", err, monitorConfig)
+				continue
 			}
+			p.writeConfig(MonitorCfg{CDN: p.OpsConfig.CdnName, Cfg: *monitorConfig})
 		}
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/4af1b42e/traffic_monitor_golang/traffic_monitor/version.go
----------------------------------------------------------------------
diff --git a/traffic_monitor_golang/traffic_monitor/version.go b/traffic_monitor_golang/traffic_monitor/version.go
index e157f45..e0a39ca 100644
--- a/traffic_monitor_golang/traffic_monitor/version.go
+++ b/traffic_monitor_golang/traffic_monitor/version.go
@@ -20,4 +20,4 @@ package main
  */
 
 // Version is the current version of the app, in string form.
-var Version = "2.0.9"
+var Version = "2.0.10"


Mime
View raw message