Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EnableInvariantChecking ¶
func EnableInvariantChecking()
Enable checking of invariants when locking and unlocking InvariantMutex.
func InvariantCheckingEnabled ¶
func InvariantCheckingEnabled() bool
Has EnableInvariantChecking previously been called?
Types ¶
type Bundle ¶
type Bundle struct {
// contains filtered or unexported fields
}
A collection of concurrently-executing operations, each of which may fail.
Operations are defined by functions that accept a context and return an error. If any operation returns a non-nil error, all concurrent and future operations will have their contexts cancelled . When Join() is called on a bundle with one or more operations that returned an error, it always returns the first error (i.e. that which led to the cancellation of others).
Bundles can be used to set up pipelines of concurrent actors sending data to each other, conveniently cancelling the pipeline if anything fails. A typical use looks like the following:
// Run a pipeline that consists of one goroutine listing object names, // while N goroutines concurrently delete the listed objects one by one. // If any listing or deletion operation fails, cancel the whole pipeline // and return the error. func deleteAllObjects(ctx context.Context, N int) error { bundle := syncutil.NewBundle(ctx) // List objects into a channel. Assuming that listObjects responds to // cancellation of its context, it will not get stuck blocking forever // on a write into objectNames if the deleters return early in error // before draining the channel. objectNames := make(chan string) bundle.Add(func(ctx context.Context) error { defer close(objectNames) return listObjects(ctx, objectNames) }) // Run N deletion workers. for i := 0; i < N; i++ { bundle.Add(func(ctx context.Context) error { for name := range objectNames { if err := deleteObject(ctx, name); err != nil { return err } } }) } // Wait for the whole pipeline to finish, and return its status. return bundle.Join() }
Bundles must be created using NewBundle. Bundle methods must not be called concurrently.
func NewBundle ¶
Create a bundle whose operations are fed a context inheriting from the given parent context, which must be non-nil. The bundle must eventually be joined with Join.
type InvariantMutex ¶
type InvariantMutex struct {
// contains filtered or unexported fields
}
A sync.Locker that, when enabled, runs a check for registered invariants at times when invariants should hold. This can aid debugging subtle code by crashing early as soon as something unexpected happens.
Must be created with NewInvariantMutex. See that function for more details.
A typical use looks like this:
type myStruct struct { mu syncutil.InvariantMutex // INVARIANT: nextGeneration == currentGeneration + 1 currentGeneration int // GUARDED_BY(mu) nextGeneration int // GUARDED_BY(mu) } // The constructor function for myStruct sets up the mutex to // call the checkInvariants method. func newMyStruct() *myStruct { s := &myStruct{ currentGeneration: 1, nextGeneration: 2, } s.mu = syncutil.NewInvariantMutex(s.checkInvariants) return s } func (s *myStruct) checkInvariants() { if s.nextGeneration != s.currentGeneration+1 { panic( fmt.Sprintf("%v != %v + 1", s.nextGeneration, s.currentGeneration)) } } // When EnableInvariantChecking has been called, invariants will be // checked at entry to and exit from this function. func (s *myStruct) setGeneration(n int) { s.mu.Lock() defer s.mu.Unlock() s.currentGeneration = n s.nextGeneration = n + 1 }
func NewInvariantMutex ¶
func NewInvariantMutex(check func()) (mu InvariantMutex)
Create a lock which, when EnableInvariantChecking has been called, will call the supplied function at moments when invariants protected by the lock should hold (e.g. just after acquiring the lock). The function should crash if an invariant is violated. It should not have side effects, as there are no guarantees that it will run.
The invariants must hold at the time that NewInvariantMutex is called.
func (*InvariantMutex) Lock ¶
func (i *InvariantMutex) Lock()
func (*InvariantMutex) RLock ¶
func (i *InvariantMutex) RLock()
func (*InvariantMutex) RUnlock ¶
func (i *InvariantMutex) RUnlock()
func (*InvariantMutex) Unlock ¶
func (i *InvariantMutex) Unlock()