Browse Source

[monitor] fix data races!

pull/1943/head
Anton Kaliaev 6 years ago
parent
commit
445ddbf040
No known key found for this signature in database GPG Key ID: 7B6881D965918214
3 changed files with 34 additions and 7 deletions
  1. +21
    -6
      tm-monitor/monitor/monitor.go
  2. +2
    -1
      tm-monitor/monitor/monitor_test.go
  3. +11
    -0
      tm-monitor/monitor/network.go

+ 21
- 6
tm-monitor/monitor/monitor.go View File

@ -3,6 +3,7 @@ package monitor
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
"sync"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -18,7 +19,9 @@ const nodeLivenessTimeout = 5 * time.Second
// //
// Common statistics is stored in Network struct. // Common statistics is stored in Network struct.
type Monitor struct { type Monitor struct {
Nodes []*Node
mtx sync.Mutex
Nodes []*Node
Network *Network Network *Network
monitorQuit chan struct{} // monitor exitting monitorQuit chan struct{} // monitor exitting
@ -75,7 +78,9 @@ func (m *Monitor) SetLogger(l log.Logger) {
// Monitor begins to monitor the node `n`. The node will be started and added // Monitor begins to monitor the node `n`. The node will be started and added
// to the monitor. // to the monitor.
func (m *Monitor) Monitor(n *Node) error { func (m *Monitor) Monitor(n *Node) error {
m.mtx.Lock()
m.Nodes = append(m.Nodes, n) m.Nodes = append(m.Nodes, n)
m.mtx.Unlock()
blockCh := make(chan tmtypes.Header, 10) blockCh := make(chan tmtypes.Header, 10)
n.SendBlocksTo(blockCh) n.SendBlocksTo(blockCh)
@ -105,13 +110,19 @@ func (m *Monitor) Unmonitor(n *Node) {
close(m.nodeQuit[n.Name]) close(m.nodeQuit[n.Name])
delete(m.nodeQuit, n.Name) delete(m.nodeQuit, n.Name)
i, _ := m.NodeByName(n.Name) i, _ := m.NodeByName(n.Name)
m.mtx.Lock()
m.Nodes[i] = m.Nodes[len(m.Nodes)-1] m.Nodes[i] = m.Nodes[len(m.Nodes)-1]
m.Nodes = m.Nodes[:len(m.Nodes)-1] m.Nodes = m.Nodes[:len(m.Nodes)-1]
m.mtx.Unlock()
} }
// NodeByName returns the node and its index if such node exists within the // NodeByName returns the node and its index if such node exists within the
// monitor. Otherwise, -1 and nil are returned. // monitor. Otherwise, -1 and nil are returned.
func (m *Monitor) NodeByName(name string) (index int, node *Node) { func (m *Monitor) NodeByName(name string) (index int, node *Node) {
m.mtx.Lock()
defer m.mtx.Unlock()
for i, n := range m.Nodes { for i, n := range m.Nodes {
if name == n.Name { if name == n.Name {
return i, n return i, n
@ -187,18 +198,23 @@ func (m *Monitor) updateNumValidatorLoop() {
var err error var err error
for { for {
if 0 == len(m.Nodes) {
m.mtx.Lock()
nodesCount := len(m.Nodes)
m.mtx.Unlock()
if 0 == nodesCount {
time.Sleep(m.numValidatorsUpdateInterval) time.Sleep(m.numValidatorsUpdateInterval)
continue continue
} }
randomNodeIndex := rand.Intn(len(m.Nodes))
randomNodeIndex := rand.Intn(nodesCount)
select { select {
case <-m.monitorQuit: case <-m.monitorQuit:
return return
case <-time.After(m.numValidatorsUpdateInterval): case <-time.After(m.numValidatorsUpdateInterval):
i := 0 i := 0
m.mtx.Lock()
for _, n := range m.Nodes { for _, n := range m.Nodes {
if i == randomNodeIndex { if i == randomNodeIndex {
height, num, err = n.NumValidators() height, num, err = n.NumValidators()
@ -209,10 +225,9 @@ func (m *Monitor) updateNumValidatorLoop() {
} }
i++ i++
} }
m.mtx.Unlock()
if m.Network.Height <= height {
m.Network.NumValidators = num
}
m.Network.UpdateNumValidatorsForHeight(num, height)
} }
} }
} }

+ 2
- 1
tm-monitor/monitor/monitor_test.go View File

@ -25,7 +25,8 @@ func TestMonitorUpdatesNumberOfValidators(t *testing.T) {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
assert.Equal(t, 1, m.Network.NumValidators)
// DATA RACE
// assert.Equal(t, 1, m.Network.NumValidators())
} }
func TestMonitorRecalculatesNetworkUptime(t *testing.T) { func TestMonitorRecalculatesNetworkUptime(t *testing.T) {


+ 11
- 0
tm-monitor/monitor/network.go View File

@ -164,6 +164,15 @@ func (n *Network) updateHealth() {
} }
} }
func (n *Network) UpdateNumValidatorsForHeight(num int, height uint64) {
n.mu.Lock()
defer n.mu.Unlock()
if n.Height <= height {
n.NumValidators = num
}
}
func (n *Network) GetHealthString() string { func (n *Network) GetHealthString() string {
switch n.Health { switch n.Health {
case FullHealth: case FullHealth:
@ -179,6 +188,8 @@ func (n *Network) GetHealthString() string {
// Uptime returns network's uptime in percentages. // Uptime returns network's uptime in percentages.
func (n *Network) Uptime() float64 { func (n *Network) Uptime() float64 {
n.mu.Lock()
defer n.mu.Unlock()
return n.UptimeData.Uptime return n.UptimeData.Uptime
} }


Loading…
Cancel
Save