Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrPolicyViolation = errors.New("policy violation")
ErrPolicyViolation is returned if acquiring a lock causes a policy violation.
var NoPolicy statelessPolicy = func(holding []string, next string) bool { return true }
NoPolicy enforces no constraints on lock ordering.
var StringOrderPolicy statelessPolicy = func(holding []string, next string) bool { if len(holding) == 0 { return true } last := holding[len(holding)-1] return last < next }
StringOrderPolicy enforces that locks are acquired in lexicographic sort order. This Policy guarantees deadlock-free operation.
Functions ¶
func IsUnknownLockError ¶
Types ¶
type Context ¶
type Context interface {
Proof
// AcquireLock acquires the lock with the given ID, unless doing so violates the configured Policy.
// This function will block if the lock is held by another goroutine.
//
// Returns ErrPolicyViolation if acquiring the lock would violate the configured Policy.
// Returns UnknownLockError if no lock with the given ID exists.
// Panics if Release has ever been called on this Context.
AcquireLock(lockID string) error
// Release releases all currently held locks and permanently marks this Context as "used".
// This method is non-blocking.
//
// Panics if Release has ever been called on this Context.
Release()
}
Context represents a goroutine's access to one or more locks managed by a Manager. It provides methods for acquiring and releasing locks and checking whether a lock is held. A new Context must be created every time a goroutine first acquires a lock. A Context is not safe for concurrent access by multiple goroutines.
type DAGPolicyBuilder ¶
type DAGPolicyBuilder struct {
// contains filtered or unexported fields
}
DAGPolicyBuilder is used to construct a DAG policy. A DAG policy uses a directed acyclic graph, where graph nodes are lock IDs, to define when locks may be acquired. If an edge exists from A->B, then if I have most recently acquired lock A, I am allowed to acquire lock B next. Edges are added at construction time with Add. When all edges have been defined, the Policy can be created with Build. A DAG Policy returned from Build guarantees deadlock-free operation.
func NewDAGPolicyBuilder ¶
func NewDAGPolicyBuilder() DAGPolicyBuilder
NewDAGPolicyBuilder returns a DAGPolicyBuilder with an empty graph.
func (DAGPolicyBuilder) Add ¶
func (b DAGPolicyBuilder) Add(lock1, lock2 string) DAGPolicyBuilder
Add defines the Policy by adding a lock acquisition allowance (an edge in the graph). The resulting Policy will allow threads to acquire lock2 if they have just acquired lock1.
func (DAGPolicyBuilder) Build ¶
func (b DAGPolicyBuilder) Build() Policy
Build validates that the constructed graph is acyclic. If the constructed graph is cyclic, this function will panic. DAGPolicyBuilder (and policies in general) are intended to be called at startup with statically defined parameters, hence the use of panic here. If the constructed graph is acyclic, a dagPolicy using the constructed graph is returned.
type Manager ¶
type Manager interface {
// NewContext returns a new Context which is able to acquire locks managed by this Manager.
NewContext() Context
}
Manager controls access to a set of locks. The set of locks and Policy (if any) is defined at construction time and is constant for the lifecycle of the Manager.
func NewManager ¶
type Policy ¶
type Policy interface {
// CanAcquire returns true if a goroutine already holding the given locks is
// allowed to also acquire the next lock.
//
// Implementations must be safe for concurrent use by multiple goroutines.
// Implementations must be non-blocking.
CanAcquire(holding []string, next string) bool
}
Policy defines whether a goroutine is allowed acquire a new lock based on locks it already holds. Policies exist to prevent deadlock by defining a canonical ordering for the set of locks in a Manager.
type Proof ¶
type Proof interface {
// HoldsLock returns true if this goroutine currently holds the lock with the given ID.
// This method is non-blocking.
//
// Panics if no lock with the given ID exists.
HoldsLock(lockID string) bool
}
Proof provides a read-only interface to a Context. A low-level function which must be executed while holding a certain lock, but which is not itself responsible for acquiring that lock, can accept a Proof argument. It can then validate that the caller has acquired the necessary lock.
type UnknownLockError ¶
type UnknownLockError struct {
LockID string
}
UnknownLockError is returned if an unknown lock is acquired.
func NewUnknownLockError ¶
func NewUnknownLockError(lockID string) UnknownLockError
func (UnknownLockError) Error ¶
func (err UnknownLockError) Error() string