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
- type NoUpdateErr
- type NtpData
- type NtpSource
- type PeerSyncData
- type SystemClock
- type VClock
- func (c *VClock) ApplySkew(sysTime time.Time, data *VClockData) time.Time
- func (c *VClock) GetVClockData(data *VClockData) error
- func (c *VClock) InitVClockData() error
- func (c *VClock) InjectFakeSysClock(now time.Time, elapsedTime time.Duration)
- func (c *VClock) Now() (time.Time, error)
- func (c *VClock) SysClockVals() (time.Time, time.Duration, error)
- func (c *VClock) SysClockValsIfNotChanged(origNow time.Time, origElapsedTime time.Duration) (time.Time, time.Duration, error)
- func (c *VClock) UpdateVClockData(fn func(*VClockData) (*VClockData, error)) error
- type VClockD
- type VClockData
Constants ¶
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 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 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) GetVClockData ¶
func (c *VClock) GetVClockData(data *VClockData) error
GetVClockData fills 'data' with VClockData read from the store.
func (*VClock) InitVClockData ¶
InitVClockData initializes VClockData in the store (if needed).
func (*VClock) InjectFakeSysClock ¶
func (*VClock) Now ¶
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 ¶
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 ¶
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 ¶
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 ¶
DoNtpUpdate talks to an NTP server and updates VClockData.
func (*VClockD) InjectNtpHost ¶
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) VDLIsZero ¶
func (x VClockData) VDLIsZero() bool
func (VClockData) VDLReflect ¶
func (VClockData) VDLReflect(struct { Name string `vdl:"v.io/x/ref/services/syncbase/vclock.VClockData"` })