juju: github.com/juju/juju/state/lease Index | Files

package lease

import "github.com/juju/juju/state/lease"

The lease package exists to implement distributed lease management on top of mgo/txn, and to expose assert operations that allow us to gate other mgo/txn transactions on lease state. This necessity has affected the package; but, apart from leaking assertion operations, it functions as a distributed lease- management system with various useful properties.

These properties of course rest upon assumptions; ensuring the validity of the following statements is the job of the client.

* The lease package has exclusive access to any collection it's configured
  to use. (Please don't store anything else in there.)

* Given any (collection,namespace) pair, any client Id will be unique at any
  given point in time. (Run no more than one per namespace per server, and
  identify them according to where they're running).

* Global time (i.e. the time returned by the provided global clock) passes
  no faster than wall-clock time.

So long as the above holds true, the following statements will too:

* A successful ClaimLease guarantees lease ownership until *at least* the
  requested duration after the start of the call. (It does *not* guaranntee
  any sort of timely expiry.)

* A successful ExtendLease makes the same guarantees. (In particular, note
  that this cannot cause a lease to be shortened; but that success may
  indicate ownership is guaranteed for longer than requested.)

* ExpireLease will only succeed when the global time is after the
  (start+duration) written to the lease.

Schema design -------------

For each namespace, we store a single document per lease. The lease document holds the name, holder, global start time, duration, and writer of the lease.

Client usage considerations ---------------------------

* Client operates at a relatively low level of abstraction. Claiming a held
  lease will fail, even on behalf of the holder; expiring an expired lease
  will fail; but at least we can allow lease extensions to race benignly,
  because they don't involve ownership change and thus can't break promises.

* ErrInvalid is normal and expected; you should never pass that on to your
  own clients, because it indicates that you tried to manipulate the client
  in an impossible way. You can and should inspect Leases() and figure out
  what to do instead; that may well be "return an error", but please be sure
  to return your own error, suitable for your own level of abstraction.

* You *probably* shouldn't ever need to actually call Refresh. It's perfectly
  safe to let state drift arbitrarily far out of sync; when you try to run
  operations, you will either succeed by luck despite your aged cache... or,
  if you fail, you'll get ErrInvalid and a fresh cache to inspect to find out
  recent state.

* The expiry time returned via lease.Info is relative to the local system
  clock, not the global time. The expiry time should only be used for
  comparison with other local system clock times, and only with Go 1.9+
  (i.e. because Go 1.9 introduced monotonic time components.)


Package Files

config.go doc.go schema.go store.go

func ClaimLeaseOps Uses

func ClaimLeaseOps(
    namespace, name, holder, writer, collection string,
    globalTime time.Time, duration time.Duration,
) ([]txn.Op, error)

ClaimLeaseOps returns txn.Ops to write a new lease. The txn.Ops will fail if the lease document exists, regardless of whether it has expired.

func LookupLease Uses

func LookupLease(coll mongo.Collection, namespace, name string) (leaseDoc, error)

LookupLease returns a lease claim if it exists. If it doesn't exist, expect to get an mgo.NotFoundError, otherwise expect to get

func NewStore Uses

func NewStore(config StoreConfig) (lease.Store, error)

NewStore returns a new Store using the supplied config, or an error. Any of the following situations will prevent store creation:

* invalid config
* invalid lease data stored in the namespace

...but a returned Store will hold a recent cache of lease data and be ready to use. Stores do not need to be cleaned up themselves, but they will not function past the lifetime of their configured Mongo.

type GlobalClock Uses

type GlobalClock interface {

    // Now returns the current global clock time.
    // Now is required to return monotonically increasing times.
    Now() (time.Time, error)

GlobalClock provides the global clock interface required by the lease package.

type LocalClock Uses

type LocalClock interface {

    // Now returns the current, writer-local wall-clock time.
    // Now is required to return times with a monotonic component,
    // as returned by Go 1.9 and onwards, such that local times
    // can be safely compared in the face of wall clock jumps.
    Now() time.Time

LocalClock provides the writer-local wall clock interface required by the lease package.

type Mongo Uses

type Mongo interface {

    // RunTransaction should probably delegate to a jujutxn.Runner's Run method.
    RunTransaction(jujutxn.TransactionSource) error

    // GetCollection should probably call the mongo.CollectionFromName func.
    GetCollection(name string) (collection mongo.Collection, closer func())

Mongo exposes MongoDB operations for use by the lease package.

type StoreConfig Uses

type StoreConfig struct {

    // Id uniquely identifies the store. Multiple stores with the same id
    // running concurrently will cause undefined behaviour.
    Id  string

    // ModelUUID identifies the model the leases will be stored in.
    ModelUUID string

    // Namespace identifies a group of stores which operate on the same data.
    Namespace string

    // Collection names the MongoDB collection in which lease data is stored.
    Collection string

    // Mongo exposes the mgo[/txn] capabilities required by a Store.
    Mongo Mongo

    // LocalClock exposes the writer-local wall-clock time to a Store.
    LocalClock LocalClock

    // GlobalClock exposes the global clock to a Store.
    GlobalClock GlobalClock

StoreConfig contains the resources and information required to create a Store. Multiple stores can collaborate if they share a collection and namespace, so long as they do not share ids; but within a collection, stores for different namespaces will not interfere with one another, regardless of id.

Package lease imports 13 packages (graph) and is imported by 39 packages. Updated 2020-02-18. Refresh now. Tools for package owners.