Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ticker Package #1668

Merged
merged 11 commits into from
Aug 10, 2018
Merged

Conversation

cfromknecht
Copy link
Contributor

@cfromknecht cfromknecht commented Aug 1, 2018

This PR is an extension of #1659, and solidifies a generic ticker.Ticker interface for resumable tickers used within the switch. It replaces the existing tickers within the link and switch with the new resumable ticker, even though only the link's batch ticker actually utilizes the conditional aspect. However, this will allow for similar optimizations to made if others are found to be hotspots.

This is required for #1551, as #1659 broke the previous method for testing link shutdowns. Previously, we used the batch ticker to test when the link becomes blocked during forwarding, so that we can test the ability for the link to be Stop() while synchronously forwarding Adds to the switch. The primary reason for this PR is thus to add the ticker.Mock, which satisfies the behavioral requirements of the production ticker, but also allows us to force feed ticks externally and arbitrarily.

@cfromknecht cfromknecht self-assigned this Aug 1, 2018
@cfromknecht cfromknecht added htlcswitch P2 should be fixed if one has time needs review PR needs review by regular contributors labels Aug 1, 2018
@cfromknecht cfromknecht force-pushed the interface-tickers branch 7 times, most recently from 30decf4 to eb5e221 Compare August 2, 2018 09:37
@cfromknecht cfromknecht changed the title htlcswitch: Interface tickers Ticker Package Aug 2, 2018
@cfromknecht cfromknecht added the testing Improvements/modifications to the test suite label Aug 2, 2018
Copy link
Contributor

@halseth halseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Niiiiice, having a generic ticker interface should make testing much easier

ticker/ticker.go Outdated
// NOTE: Part of the Ticker interface.
func (t *ticker) Resume() {
t.ticker = time.NewTicker(t.interval)
t.ticks = t.ticker.C
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like it would be simpler to just store t.ticker, and return t.ticker.C from Ticks()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe ticker.C is buffered, so calling Stop() might still produce an extra tick. See this example: https://play.golang.org/p/5I4Cm35wyao

Swapping out the channel for nil ensures that this won't produce a tick when selected on

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, in Tick we can do

if t.ticker == nil {
     return nil
}
return t.ticker.C

Should be equivalent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed!

@@ -1028,8 +986,8 @@ out:
// If the downstream packet resulted in a non-empty
// batch, reinstate the batch ticker so that it can be
// cleared.
if l.batchCounter > 0 && maybeBatchTick == nil {
maybeBatchTick = l.cfg.BatchTicker.Start()
if l.batchCounter > 0 && !l.cfg.BatchTicker.IsActive() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't need to check IsActive here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to resume if we're already active, could cause us to reinitialize a ticker every time the batch is non-empty

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make Resume a no-op if the ticker is already active.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh great idea!

ticker/ticker.go Outdated
// false.
//
// NOTE: The behavior of a Ticker is undefined after calling Stop.
Stop()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to distinguish pausing from stopping at this point? I think we should stick to Start/Stop as that should be enough for our use case.

Copy link
Contributor Author

@cfromknecht cfromknecht Aug 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start/Stop is enough, but the mock ticker has a goroutine that needs to be cleaned up. In order to handle forced ticks while paused, i.e. keeping the goroutine alive, there needs to be a distinction between pausing, and actually tearing down the ticker

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't think a mock implementation detail should clutter up the interface, but I surrender to the overlords 🙇

@cfromknecht cfromknecht force-pushed the interface-tickers branch 2 times, most recently from 2e5a269 to bf5f7a3 Compare August 2, 2018 12:07
Copy link
Contributor

@wpaulino wpaulino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I dig the new approach of the mock ticker where we can force ticks to trigger specific behaviors 😎

ticker/ticker.go Outdated

// New returns a new ticker that signals with the given interval
// when not paused.
func New(interval time.Duration) *ticker {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return the interface instead, otherwise we'd be returning an unexported identifier from an exported one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed in person, leaving as concrete type

ticker/mock.go Outdated
"time"
)

// Mock implements the htlcswitch.Ticker interface, and provides a method of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/htlcswitch.Ticker/ticker.Ticker/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

ticker/mock.go Outdated
}

// NOTE: Part of the Ticker interface.
func (m *Mock) Ticks() <-chan time.Time {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing godoc, as well as all the others below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

peer.go Outdated
@@ -416,6 +417,7 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error {
)
if err != nil {
lnChan.Stop()
peerLog.Debugf("unable to add link %v: %v", chanPoint, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: capitalize first word for consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed! also made peer disconnection logged to info, which seems useful as per discussion in #1630

@cfromknecht cfromknecht force-pushed the interface-tickers branch 2 times, most recently from 9d50fea to e1acd1a Compare August 3, 2018 02:31
@cfromknecht cfromknecht force-pushed the interface-tickers branch 3 times, most recently from 5494114 to 9381dee Compare August 4, 2018 02:16
@Roasbeef Roasbeef added this to the 0.5 milestone Aug 8, 2018
@Roasbeef Roasbeef added needs testing PR hasn't yet been actively tested on testnet/mainnet and removed needs review PR needs review by regular contributors labels Aug 9, 2018
Roasbeef
Roasbeef previously approved these changes Aug 9, 2018
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 🏒

The code reads well to me, and will definitely allow us to effectively test any scenario which depends on ticker behavior within the codebase. Before I merge this, will run it on the faucet for a bit to ensure that there hasn't been a regression in the improvements for idle CPU time.

@cfromknecht cfromknecht force-pushed the interface-tickers branch 3 times, most recently from bb43c81 to c532718 Compare August 9, 2018 07:41
halseth
halseth previously approved these changes Aug 9, 2018
Copy link
Contributor

@halseth halseth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ⏰

ticker/ticker.go Outdated
Pause()

// Stop suspends the underlying ticker, such that Ticks() stops
// signaling at regular intervals, and permanently frees up any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: extra white space

ticker/ticker.go Outdated
// false.
//
// NOTE: The behavior of a Ticker is undefined after calling Stop.
Stop()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still don't think a mock implementation detail should clutter up the interface, but I surrender to the overlords 🙇

ticker/ticker.go Outdated
}

// ticker is the production implementation of the resumable Ticker interface.
// This allows various components of the htlcswitch to toggle their need for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove htlcswitch reference

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if l.batchCounter > 0 && maybeBatchTick == nil {
maybeBatchTick = l.cfg.BatchTicker.Start()
if l.batchCounter > 0 {
l.cfg.BatchTicker.Resume()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so beautiful 😻

peer.go Outdated
@@ -576,7 +578,7 @@ func (p *peer) Disconnect(reason error) {
return
}

peerLog.Tracef("Disconnecting %s, reason: %v", p, reason)
peerLog.Infof("Disconnecting %s, reason: %v", p, reason)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debugf?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@cfromknecht
Copy link
Contributor Author

comments addressed!

re: interface clutter, it's not necessarily the mock ticker that's dictating this. In my mind, the aim is to generically encompass the possibility of tickers requiring cleanup that is different from Pause (same for start/resume), of which the mock implementation is one example. Not differentiating assumes that there is no useful ticker requiring these distinctions, even though the mock implementation is what led to me to think that there might be such a case :)

@Roasbeef Roasbeef merged commit d3b1b9a into lightningnetwork:master Aug 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
htlcswitch needs testing PR hasn't yet been actively tested on testnet/mainnet P2 should be fixed if one has time testing Improvements/modifications to the test suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants