vclock

package
v0.0.0-...-ff5f600 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 30, 2016 License: BSD-3-Clause Imports: 14 Imported by: 0

Documentation

Overview

Package vclock implements the Syncbase virtual clock, or vclock for short. The Syncbase vclock can be thought of as a better version of the system clock, in that it occasionally consults NTP as well as peers to attempt to improve the accuracy of time estimates coming from the system clock.

The vclock implementation consists of several components:

  • SystemClock: a simple API for accessing system clock data, namely the current time and the time elapsed since boot.
  • VClock struct: encapsulates persisted VClockData and provides methods for obtaining Syncbase's notion of current time.
  • VClockD: daemon (goroutine) that periodically consults NTP as well as the current system clock to update the persisted VClockData.
  • Peer clock sync: the sync subsystem obtains VClockData from peers as part of the sync procedure; if this data is deemed more accurate than our local VClockData, we update our local VClockData accordingly.

For more information, see the design doc: TODO(jlodhia): Add link to design doc on v.io.

Index

Constants

View Source
const (
	// Used by VClockD.doNtpUpdate.
	NtpSampleCount        = 15
	NtpSkewDeltaThreshold = 2 * time.Second
	// Used by VClockD.doLocalUpdate.
	SystemClockDriftThreshold = time.Second
	// Used by MaybeUpdateFromPeerData.
	PeerSyncSkewThreshold = NtpSkewDeltaThreshold
	RebootSkewThreshold   = time.Minute
	MaxNumHops            = 2
)

Variables

This section is empty.

Functions

This section is empty.

Types

type NoUpdateErr

type NoUpdateErr struct {
	// contains filtered or unexported fields
}

NoUpdateErr is an error indicating that no update should be performed to VClockData. We define this error type explicitly so that the calling code (syncWithPeer) knows not to log the error with vlog.Errorf.

func (*NoUpdateErr) Error

func (e *NoUpdateErr) Error() string

type NtpData

type NtpData struct {
	// contains filtered or unexported fields
}

type NtpSource

type NtpSource interface {
	// NtpSync obtains 'sampleCount' samples of NtpData from an NTP server and
	// returns the one with the smallest 'delay' value.
	NtpSync(sampleCount int) (*NtpData, error)
}

type PeerSyncData

type PeerSyncData struct {
	MySendTs time.Time // when we sent request (our vclock time)
	RecvTs   time.Time // when peer received request (their vclock time)
	SendTs   time.Time // when peer sent response (their vclock time)
	MyRecvTs time.Time // when we received response (our vclock time)
	// Select fields from peer's VClockData.
	LastNtpTs  time.Time
	NumReboots uint16
	NumHops    uint16
}

PeerSyncData contains data collected during a GetTime RPC to a peer.

type SystemClock

type SystemClock interface {
	// Now returns the system's notion of current UTC time (which may be off).
	Now() time.Time

	// ElapsedTime returns the time elapsed since this device booted.
	ElapsedTime() (time.Duration, error)
}

SystemClock provides access to system clock data.

type VClock

type VClock struct {
	// contains filtered or unexported fields
}

VClock holds everything needed to provide UTC time estimates. VClock is thread-safe.

func NewVClock

func NewVClock(st store.Store) *VClock

NewVClock creates a new VClock.

func NewVClockForTests

func NewVClockForTests(sc SystemClock) *VClock

NewVClockForTests returns a *VClock suitable for tests. It mimics "real" Syncbase behavior in that it calls InitVClockData to ensure that VClockData exists in the store.

func (*VClock) ApplySkew

func (c *VClock) ApplySkew(sysTime time.Time, data *VClockData) time.Time

ApplySkew applies skew correction to the given system clock time.

func (*VClock) GetVClockData

func (c *VClock) GetVClockData(data *VClockData) error

GetVClockData fills 'data' with VClockData read from the store.

func (*VClock) InitVClockData

func (c *VClock) InitVClockData() error

InitVClockData initializes VClockData in the store (if needed).

func (*VClock) InjectFakeSysClock

func (c *VClock) InjectFakeSysClock(now time.Time, elapsedTime time.Duration)

func (*VClock) Now

func (c *VClock) Now() (time.Time, error)

Now returns our estimate of current UTC time based on SystemClock time and our estimate of its skew relative to NTP time.

func (*VClock) SysClockVals

func (c *VClock) SysClockVals() (time.Time, time.Duration, error)

SysClockVals returns the system clock's Now and ElapsedTime values.

func (*VClock) SysClockValsIfNotChanged

func (c *VClock) SysClockValsIfNotChanged(origNow time.Time, origElapsedTime time.Duration) (time.Time, time.Duration, error)

SysClockValsIfNotChanged returns the system clock's Now and ElapsedTime values, but returns an error if it detects that the system clock has changed based on the given origNow and origElapsedTime. IMPORTANT: origNow and origElapsedTime must have come from a call to SysClockVals, not SysClockValsIfNotChanged, to avoid a race condition in system clock change detection.

func (*VClock) UpdateVClockData

func (c *VClock) UpdateVClockData(fn func(*VClockData) (*VClockData, error)) error

UpdateVClockData reads VClockData from the store, applies the given function to produce new VClockData, and writes the resulting VClockData back to the store. The entire read-modify-write operation is performed inside of a transaction.

type VClockD

type VClockD struct {
	// contains filtered or unexported fields
}

VClockD is a daemon (a goroutine) that periodically runs DoLocalUpdate and DoNtpUpdate to update various fields in persisted VClockData based on values reported by the system clock and NTP. VClockD is thread-safe.

func NewVClockD

func NewVClockD(vclock *VClock, ntpHost string) *VClockD

NewVClockD returns a new VClockD instance.

func (*VClockD) Close

func (d *VClockD) Close()

Close cleans up any VClockD state and waits for its run loop to exit.

func (*VClockD) DoLocalUpdate

func (d *VClockD) DoLocalUpdate() error

DoLocalUpdate checks for reboots and drift by comparing our persisted VClockData with the current time and elapsed time reported by the system clock. It always updates {SystemTimeAtBoot, ElapsedTimeSinceBoot}, and may also update either Skew or NumReboots. It does not touch LastNtpTs or NumHops.

func (*VClockD) DoNtpUpdate

func (d *VClockD) DoNtpUpdate() error

DoNtpUpdate talks to an NTP server and updates VClockData.

func (*VClockD) InjectNtpHost

func (d *VClockD) InjectNtpHost(ntpHost string)

func (*VClockD) Start

func (d *VClockD) Start()

Start starts this VClockD's run loop.

type VClockData

type VClockData struct {
	// System time at boot.
	SystemTimeAtBoot time.Time
	// Current estimate of NTP time minus system clock time.
	Skew time.Duration
	// Elapsed time since boot, as seen by VClockD. Used for detecting reboots.
	ElapsedTimeSinceBoot time.Duration
	// NTP server timestamp from the most recent NTP sync, or zero value if none.
	// Note, the NTP sync may have been performed by some peer device.
	LastNtpTs time.Time
	// Number of reboots since last NTP sync, accumulated across all hops of p2p
	// clock sync. E.g. if LastNtpTs came from some peer device, NumReboots will
	// equal that device's NumReboots at the time of sync plus the number of
	// reboots on this device since then.
	NumReboots uint16
	// Number of sync hops between this device and the source of LastNtpTs.
	NumHops uint16
}

VClockData is the persistent state of the Syncbase virtual clock. All times are UTC.

func MaybeUpdateFromPeerData

func MaybeUpdateFromPeerData(c *VClock, data *VClockData, psd *PeerSyncData) (*VClockData, error)

MaybeUpdateFromPeerData updates data (the local VClockData) based on the given PeerSyncData. Returns nil if data has been updated; otherwise, the returned error specifies why the data was not updated. TODO(sadovsky): This design assumes trust across syncgroups, which is generally not desirable. Eventually we may need to perform MaybeUpdateFromPeerData separately for each db or syncgroup, or something along these lines.

func (*VClockData) FillVDLTarget

func (m *VClockData) FillVDLTarget(t vdl.Target, tt *vdl.Type) error

func (*VClockData) MakeVDLTarget

func (m *VClockData) MakeVDLTarget() vdl.Target

func (VClockData) VDLIsZero

func (x VClockData) VDLIsZero() bool

func (*VClockData) VDLRead

func (x *VClockData) VDLRead(dec vdl.Decoder) error

func (VClockData) VDLWrite

func (x VClockData) VDLWrite(enc vdl.Encoder) error

type VClockDataTarget

type VClockDataTarget struct {
	Value *VClockData

	vdl.TargetBase
	vdl.FieldsTargetBase
	// contains filtered or unexported fields
}

func (*VClockDataTarget) FinishField

func (t *VClockDataTarget) FinishField(_, _ vdl.Target) error

func (*VClockDataTarget) FinishFields

func (t *VClockDataTarget) FinishFields(_ vdl.FieldsTarget) error

func (*VClockDataTarget) StartField

func (t *VClockDataTarget) StartField(name string) (key, field vdl.Target, _ error)

func (*VClockDataTarget) StartFields

func (t *VClockDataTarget) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error)

func (*VClockDataTarget) ZeroField

func (t *VClockDataTarget) ZeroField(name string) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL