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

lease: use monotime in time.Time for Go 1.9 #8507

Merged
merged 1 commit into from
Sep 7, 2017

Conversation

lorneli
Copy link
Contributor

@lorneli lorneli commented Sep 6, 2017

The golang/time package tracks monotonic time in each time.Time
returned by time.Now function for Go 1.9.

Use time.Time to measure whether a lease is expired, instead of previous
pkg/monotime.

@lorneli
Copy link
Contributor Author

lorneli commented Sep 6, 2017

This is a draft. I have several confusions when implementing this commit:

a. It's hard to find an elegant way to express forever using time.Time. But Lease.expiry does need
a large time value for exported Remaining function.

b. Lease.expiry is accessed atomicly previously. After changing its type to time.Time, have to use a mutex expiryMu to provide concurrent access.

@codecov-io
Copy link

codecov-io commented Sep 6, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@ec36d00). Click here to learn what that means.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #8507   +/-   ##
=========================================
  Coverage          ?   75.46%           
=========================================
  Files             ?      356           
  Lines             ?    29101           
  Branches          ?        0           
=========================================
  Hits              ?    21960           
  Misses            ?     5588           
  Partials          ?     1553
Impacted Files Coverage Δ
lease/lessor.go 86.52% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ec36d00...63aa64d. Read the comment docs.

lease/lessor.go Outdated
)

var (
forever = time.Unix(1<<63-1-unixTimeSeconds, maxNanoseconds)
Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't use time.Unix because the time returned by time.Unix won't include monotonic information as described in

time.Unix, as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. t.UnmarshalJSON, and t.UnmarshalText always create times with no monotonic clock reading.

Source

Copy link
Contributor Author

@lorneli lorneli Sep 6, 2017

Choose a reason for hiding this comment

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

@fanminshi You're right. Since forever variable returned by time.Unix doesn't include monotonic information, time.Sub used in Lease.Remaining calculates in wall time, which may cause an unreasonable phenomenon: remaining time increases itself.

Copy link
Member

Choose a reason for hiding this comment

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

@lorneli @heyitsanthony's suggestion using time.Time{} as forever sounds like a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@fanminshi I think so too. Changing my commit with @heyitsanthony 's suggestion.

"time"

"github.com/coreos/etcd/lease/leasepb"
"github.com/coreos/etcd/mvcc/backend"
"github.com/coreos/etcd/pkg/monotime"
Copy link
Contributor

Choose a reason for hiding this comment

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

git rm -r pkg/monotime too since this orphans the package

lease/lessor.go Outdated
return time.Duration(t - monotime.Now())
l.expiryMu.RLock()
defer l.expiryMu.RUnlock()
return l.expiry.Sub(time.Now())
Copy link
Contributor

Choose a reason for hiding this comment

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

since forever breaks down when switching to time.Time, this patch could instead use time.Time{} to mean forever:

func (l *Lease) Remaining() time.Duration {
    l.expiryMu.RLock()
    defer l.expiryMu.RUnlock()
    if l.expiry.IsZero() {
        return time.Duration(math.MaxInt64)
    }
    return time.Until(l.expiry)
}

@lorneli
Copy link
Contributor Author

lorneli commented Sep 7, 2017

@heyitsanthony Thanks for your suggestions. I've changed this commit:
a. Remove pkg/monotime.
b. Use zero time.Time to mean forever.
c. Update commit message.

Still use l.expiry.Sub(time.Now()) to calculate remaining. It's easier to replace
time.Now with clockwork in this way.


var (
forever = time.Time{}
Copy link
Member

Choose a reason for hiding this comment

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

add a comment here to explain why forever = time.Time{}.

Copy link
Contributor Author

@lorneli lorneli Sep 7, 2017

Choose a reason for hiding this comment

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

@fanminshi How about this?
"Since time.Time with monotonic time only returned by time.Now(), it's hard to create a max time.Time variable with monotonic time. Instead, use zero time.Time to mean forever. It's easy to find whether a expiry is forever via Time.IsZero()."

Copy link
Member

Choose a reason for hiding this comment

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

that's too detailed. I am thinking about just say forever is represented by zero time.Time. Defer to @heyitsanthony for best comment.

Copy link
Contributor Author

@lorneli lorneli Sep 7, 2017

Choose a reason for hiding this comment

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

Maybe use an explicit flag isForever, instead of a zero time.Time variable?

type expiry struct{
	time.Time
	isForever bool // set when lessor is demoted
}

func (l *Lease) Remaining() time.Duration {
	l.expiryMu.RLock()
	defer l.expiryMu.RUnlock()
	if l.expiry.isForever {
		return time.Duration(math.MaxInt64)
	}
	return l.expiry.Sub(time.Now())
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Please just use time.IsZero(); a separate type is excessive. The comment can be:

expiry time.Time // no expiration when expiry.IsZero() is true

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it.

The golang/time package tracks monotonic time in each time.Time
returned by time.Now function for Go 1.9.

Use time.Time to measure whether a lease is expired and remove
previous pkg/monotime. Use zero time.Time to mean forever. No
expiration when expiry.IsZero() is true.
@lorneli
Copy link
Contributor Author

lorneli commented Sep 7, 2017

Update comment 😀

@lorneli
Copy link
Contributor Author

lorneli commented Sep 7, 2017

Semaphore fails at compactor.

2017-09-07 06:27:41.746290 N | compactor: Finished auto-compaction at revision 25
--- FAIL: TestPeriodicPause (5.69s)
	periodic_test.go:115: compact request = revision:25 , want 26

@fanminshi
Copy link
Member

lgtm.

Copy link
Contributor

@heyitsanthony heyitsanthony left a comment

Choose a reason for hiding this comment

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

lgtm thanks

@gyuho gyuho mentioned this pull request Sep 7, 2017
26 tasks
@heyitsanthony heyitsanthony merged commit eb55917 into etcd-io:master Sep 7, 2017
@lorneli lorneli deleted the lease_monotime branch September 8, 2017 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants