chanfitness: record timestamped flap count for peers
In preparation for storing our flap count on disk, we start tracking flap count per-peer.
This commit is contained in:
parent
e05b4a8e2e
commit
8b09b2d716
@ -46,6 +46,14 @@ type peerLog struct {
|
|||||||
// onlineEvents is a log of timestamped events observed for the peer.
|
// onlineEvents is a log of timestamped events observed for the peer.
|
||||||
onlineEvents []*event
|
onlineEvents []*event
|
||||||
|
|
||||||
|
// flapCount is the number of times this peer has been observed as
|
||||||
|
// going offline.
|
||||||
|
flapCount int
|
||||||
|
|
||||||
|
// lastFlap is the timestamp of the last flap we recorded for the peer.
|
||||||
|
// This value will be nil if we have never recorded a flap for the peer.
|
||||||
|
lastFlap *time.Time
|
||||||
|
|
||||||
// clock allows creation of deterministic unit tests.
|
// clock allows creation of deterministic unit tests.
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
|
|
||||||
@ -76,8 +84,15 @@ func newChannelInfo(openedAt time.Time) *channelInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// onlineEvent records a peer online or offline event in the log.
|
// onlineEvent records a peer online or offline event in the log and increments
|
||||||
|
// the peer's flap count.
|
||||||
func (p *peerLog) onlineEvent(online bool) {
|
func (p *peerLog) onlineEvent(online bool) {
|
||||||
|
eventTime := p.clock.Now()
|
||||||
|
|
||||||
|
// Record flap count information and online state regardless of whether
|
||||||
|
// we have any channels open with this peer.
|
||||||
|
p.flapCount++
|
||||||
|
p.lastFlap = &eventTime
|
||||||
p.online = online
|
p.online = online
|
||||||
|
|
||||||
// If we have no channels currently open with the peer, we do not want
|
// If we have no channels currently open with the peer, we do not want
|
||||||
@ -87,7 +102,7 @@ func (p *peerLog) onlineEvent(online bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.addEvent(online, p.clock.Now())
|
p.addEvent(online, eventTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// addEvent records an online or offline event in our event log.
|
// addEvent records an online or offline event in our event log.
|
||||||
@ -176,6 +191,12 @@ func (p *peerLog) channelUptime(channelPoint wire.OutPoint) (time.Duration,
|
|||||||
return now.Sub(channel.openedAt), uptime, nil
|
return now.Sub(channel.openedAt), uptime, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getFlapCount returns the peer's flap count and the timestamp that we last
|
||||||
|
// recorded a flap.
|
||||||
|
func (p *peerLog) getFlapCount() (int, *time.Time) {
|
||||||
|
return p.flapCount, p.lastFlap
|
||||||
|
}
|
||||||
|
|
||||||
// onlinePeriod represents a period of time over which a peer was online.
|
// onlinePeriod represents a period of time over which a peer was online.
|
||||||
type onlinePeriod struct {
|
type onlinePeriod struct {
|
||||||
start, end time.Time
|
start, end time.Time
|
||||||
|
@ -14,29 +14,53 @@ func TestPeerLog(t *testing.T) {
|
|||||||
clock := clock.NewTestClock(testNow)
|
clock := clock.NewTestClock(testNow)
|
||||||
peerLog := newPeerLog(clock)
|
peerLog := newPeerLog(clock)
|
||||||
|
|
||||||
|
// assertFlapCount is a helper that asserts that our peer's flap count
|
||||||
|
// and timestamp is set to expected values.
|
||||||
|
assertFlapCount := func(expectedCount int, expectedTs *time.Time) {
|
||||||
|
flapCount, flapTs := peerLog.getFlapCount()
|
||||||
|
require.Equal(t, expectedCount, flapCount)
|
||||||
|
require.Equal(t, expectedTs, flapTs)
|
||||||
|
}
|
||||||
|
|
||||||
require.Zero(t, peerLog.channelCount())
|
require.Zero(t, peerLog.channelCount())
|
||||||
require.False(t, peerLog.online)
|
require.False(t, peerLog.online)
|
||||||
|
assertFlapCount(0, nil)
|
||||||
|
|
||||||
// Test that looking up an unknown channel fails.
|
// Test that looking up an unknown channel fails.
|
||||||
_, _, err := peerLog.channelUptime(wire.OutPoint{Index: 1})
|
_, _, err := peerLog.channelUptime(wire.OutPoint{Index: 1})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
|
lastFlap := clock.Now()
|
||||||
|
|
||||||
// Add an offline event, since we have no channels, we do not expect
|
// Add an offline event, since we have no channels, we do not expect
|
||||||
// to have any online periods recorded for our peer.
|
// to have any online periods recorded for our peer. However, we should
|
||||||
|
// increment our flap count for the peer.
|
||||||
peerLog.onlineEvent(false)
|
peerLog.onlineEvent(false)
|
||||||
require.Len(t, peerLog.getOnlinePeriods(), 0)
|
require.Len(t, peerLog.getOnlinePeriods(), 0)
|
||||||
|
assertFlapCount(1, &lastFlap)
|
||||||
|
|
||||||
|
// Bump our test clock's time by an hour so that we can create an online
|
||||||
|
// event with a distinct time.
|
||||||
|
lastFlap = testNow.Add(time.Hour)
|
||||||
|
clock.SetTime(lastFlap)
|
||||||
|
|
||||||
// Likewise, if we have an online event, nothing beyond the online state
|
// Likewise, if we have an online event, nothing beyond the online state
|
||||||
// of our peer log should change.
|
// of our peer log should change, but our flap count should change.
|
||||||
peerLog.onlineEvent(true)
|
peerLog.onlineEvent(true)
|
||||||
require.Len(t, peerLog.getOnlinePeriods(), 0)
|
require.Len(t, peerLog.getOnlinePeriods(), 0)
|
||||||
|
assertFlapCount(2, &lastFlap)
|
||||||
|
|
||||||
// Add a channel and assert that we have one channel listed.
|
// Add a channel and assert that we have one channel listed. Since this
|
||||||
|
// is the first channel we track for the peer, we expect an online
|
||||||
|
// event to be added, however, our flap count should not change because
|
||||||
|
// this is not a new online event, we are just copying one into our log
|
||||||
|
// for our purposes.
|
||||||
chan1 := wire.OutPoint{
|
chan1 := wire.OutPoint{
|
||||||
Index: 1,
|
Index: 1,
|
||||||
}
|
}
|
||||||
require.NoError(t, peerLog.addChannel(chan1))
|
require.NoError(t, peerLog.addChannel(chan1))
|
||||||
require.Equal(t, 1, peerLog.channelCount())
|
require.Equal(t, 1, peerLog.channelCount())
|
||||||
|
assertFlapCount(2, &lastFlap)
|
||||||
|
|
||||||
// Assert that we can now successfully get our added channel.
|
// Assert that we can now successfully get our added channel.
|
||||||
_, _, err = peerLog.channelUptime(chan1)
|
_, _, err = peerLog.channelUptime(chan1)
|
||||||
@ -44,8 +68,8 @@ func TestPeerLog(t *testing.T) {
|
|||||||
|
|
||||||
// Bump our test clock's time so that our current time is different to
|
// Bump our test clock's time so that our current time is different to
|
||||||
// channel open time.
|
// channel open time.
|
||||||
now := testNow.Add(time.Hour)
|
lastFlap = clock.Now().Add(time.Hour)
|
||||||
clock.SetTime(now)
|
clock.SetTime(lastFlap)
|
||||||
|
|
||||||
// Now that we have added a channel and an hour has passed, we expect
|
// Now that we have added a channel and an hour has passed, we expect
|
||||||
// our uptime and lifetime to both equal an hour.
|
// our uptime and lifetime to both equal an hour.
|
||||||
@ -54,8 +78,10 @@ func TestPeerLog(t *testing.T) {
|
|||||||
require.Equal(t, time.Hour, lifetime)
|
require.Equal(t, time.Hour, lifetime)
|
||||||
require.Equal(t, time.Hour, uptime)
|
require.Equal(t, time.Hour, uptime)
|
||||||
|
|
||||||
// Add an offline event for our peer.
|
// Add an offline event for our peer and assert that our flap count is
|
||||||
|
// incremented.
|
||||||
peerLog.onlineEvent(false)
|
peerLog.onlineEvent(false)
|
||||||
|
assertFlapCount(3, &lastFlap)
|
||||||
|
|
||||||
// Now we add another channel to our store and assert that we now report
|
// Now we add another channel to our store and assert that we now report
|
||||||
// two channels for this peer.
|
// two channels for this peer.
|
||||||
@ -67,7 +93,7 @@ func TestPeerLog(t *testing.T) {
|
|||||||
|
|
||||||
// Progress our time again, so that our peer has now been offline for
|
// Progress our time again, so that our peer has now been offline for
|
||||||
// two hours.
|
// two hours.
|
||||||
now = now.Add(time.Hour * 2)
|
now := lastFlap.Add(time.Hour * 2)
|
||||||
clock.SetTime(now)
|
clock.SetTime(now)
|
||||||
|
|
||||||
// Our first channel should report as having been monitored for three
|
// Our first channel should report as having been monitored for three
|
||||||
@ -91,10 +117,11 @@ func TestPeerLog(t *testing.T) {
|
|||||||
require.Equal(t, time.Duration(0), uptime)
|
require.Equal(t, time.Duration(0), uptime)
|
||||||
|
|
||||||
// Finally, remove our second channel and assert that our peer cleans
|
// Finally, remove our second channel and assert that our peer cleans
|
||||||
// up its in memory set of events.
|
// up its in memory set of events but keeps its flap count record.
|
||||||
require.NoError(t, peerLog.removeChannel(chan2))
|
require.NoError(t, peerLog.removeChannel(chan2))
|
||||||
require.Equal(t, 0, peerLog.channelCount())
|
require.Equal(t, 0, peerLog.channelCount())
|
||||||
require.Len(t, peerLog.onlineEvents, 0)
|
require.Len(t, peerLog.onlineEvents, 0)
|
||||||
|
assertFlapCount(3, &lastFlap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestGetOnlinePeriod tests the getOnlinePeriod function. It tests the case
|
// TestGetOnlinePeriod tests the getOnlinePeriod function. It tests the case
|
||||||
|
@ -26,4 +26,9 @@ type peerMonitor interface {
|
|||||||
// the channel has been monitored for and its uptime over this period.
|
// the channel has been monitored for and its uptime over this period.
|
||||||
channelUptime(channelPoint wire.OutPoint) (time.Duration,
|
channelUptime(channelPoint wire.OutPoint) (time.Duration,
|
||||||
time.Duration, error)
|
time.Duration, error)
|
||||||
|
|
||||||
|
// getFlapCount returns the peer's flap count and the timestamp that we
|
||||||
|
// last recorded a flap, which may be nil if we have never recorded a
|
||||||
|
// flap for this peer.
|
||||||
|
getFlapCount() (int, *time.Time)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user