3
// Manager provides an interface for allocating multiprocess locks.
4
// Locks returned by Manager MUST be multiprocess - allocating a lock in
5
// process A and retrieving that lock's ID in process B must return handles for
6
// the same lock, and locking the lock in A should exclude B from the lock until
8
// All locks must be identified by a UUID (retrieved with Locker's ID() method).
9
// All locks with a given UUID must refer to the same underlying lock, and it
10
// must be possible to retrieve the lock given its UUID.
11
// Each UUID should refer to a unique underlying lock.
12
// Calls to AllocateLock() must return a unique, unallocated UUID.
13
// AllocateLock() must fail once all available locks have been allocated.
14
// Locks are returned to use by calls to Free(), and can subsequently be
16
type Manager interface {
17
// AllocateLock returns an unallocated lock.
18
// It is guaranteed that the same lock will not be returned again by
19
// AllocateLock until the returned lock has Free() called on it.
20
// If all available locks are allocated, AllocateLock will return an
22
AllocateLock() (Locker, error)
23
// RetrieveLock retrieves a lock given its UUID.
24
// The underlying lock MUST be the same as another other lock with the
26
RetrieveLock(id uint32) (Locker, error)
27
// AllocateAndRetrieveLock marks the lock with the given UUID as in use
29
// RetrieveAndAllocateLock will error if the lock in question has
30
// already been allocated.
31
// This is mostly used after a system restart to repopulate the list of
33
AllocateAndRetrieveLock(id uint32) (Locker, error)
34
// PLEASE READ FULL DESCRIPTION BEFORE USING.
35
// FreeAllLocks frees all allocated locks, in preparation for lock
37
// As this deallocates all presently-held locks, this can be very
38
// dangerous - if there are other processes running that might be
39
// attempting to allocate new locks and free existing locks, we may
40
// encounter races leading to an inconsistent state.
41
// (This is in addition to the fact that FreeAllLocks instantly makes
42
// the state inconsistent simply by using it, and requires a full
43
// lock renumbering to restore consistency!).
44
// In short, this should only be used as part of unit tests, or lock
45
// renumbering, where reasonable guarantees about other processes can be
48
// NumAvailableLocks gets the number of remaining locks available to be
50
// Some lock managers do not have a maximum number of locks, and can
51
// allocate an unlimited number. These implementations should return
53
AvailableLocks() (*uint32, error)
54
// Get a list of locks that are currently locked.
55
// This may not be supported by some drivers, depending on the exact
56
// backend implementation in use.
57
LocksHeld() ([]uint32, error)
60
// Locker is similar to sync.Locker, but provides a method for freeing the lock
62
// All Locker implementations must maintain mutex semantics - the lock only
63
// allows one caller in the critical section at a time.
64
// All locks with the same ID must refer to the same underlying lock, even
65
// if they are within multiple processes.
66
type Locker interface {
67
// ID retrieves the lock's ID.
68
// ID is guaranteed to uniquely identify the lock within the
69
// Manager - that is, calling RetrieveLock with this ID will return
70
// another instance of the same lock.
72
// Lock locks the lock.
73
// This call MUST block until it successfully acquires the lock or
74
// encounters a fatal error.
75
// All errors must be handled internally, as they are not returned. For
76
// the most part, panicking should be appropriate.
77
// Some lock implementations may require that Lock() and Unlock() occur
78
// within the same goroutine (SHM locking, for example). The usual Go
79
// Lock()/defer Unlock() pattern will still work fine in these cases.
81
// Unlock unlocks the lock.
82
// All errors must be handled internally, as they are not returned. For
83
// the most part, panicking should be appropriate.
84
// This includes unlocking locks which are already unlocked.
86
// Free deallocates the underlying lock, allowing its reuse by other
87
// pods and containers.
88
// The lock MUST still be usable after a Free() - some libpod instances
89
// may still retain Container structs with the old lock. This simply
90
// advises the manager that the lock may be reallocated.