blob: 7231882b11a5610660468fd1511efcfdc40e00f9 [file] [log] [blame]
// Copyright 2017 by Dan Jacques. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package fslock is a cross-platform filesystem locking implementation.
//
// fslock aims to implement workable filesystem-based locking semantics. Each
// implementation offers its own nuances, and not all of those nuances are
// addressed by this package.
//
// Locks can either be exclusive (default) or shared. For a given file, exactly
// one of the following circumstances may be true at a given moment:
// - No locks are held.
// - A single exclusive lock may be held.
// - Multiple shared locks may be held.
//
// Notably, an exclusive lock may not be held on a file that has shared locks,
// and a shared lock may not be held on a file that has an exclusive lock.
//
// fslock will work as long as you don't do anything particularly weird, such
// as:
//
// - Manually forking your Go process.
// - Circumventing the fslock package and opening and/or manipulating the lock
// file directly.
//
// An attempt to take a filesystem lock is non-blocking, and will return
// ErrLockHeld if the lock is already held elsewhere.
package fslock
// Lock acquires a filesystem lock for the given path.
//
// If the lock could not be acquired because it is held by another entity,
// ErrLockHeld will be returned. If an error is encountered while locking,
// that error will be returned.
//
// Lock is a convenience method for L's Lock.
func Lock(path string) (Handle, error) { return LockBlocking(path, nil) }
// LockBlocking acquires an exclusive filesystem lock for the given path. If the
// lock is already held, LockBlocking will repeatedly attempt to acquire it
// using the supplied Blocker in between attempts.
//
// If no Blocker is provided and the lock could not be acquired because it is
// held by another entity, ErrLockHeld will be returned. If an error is
// encountered while locking, or an error is returned by b, that error will be
// returned.
//
// LockBlocking is a convenience method for L's Lock.
func LockBlocking(path string, b Blocker) (Handle, error) {
l := L{
Path: path,
Block: b,
}
return l.Lock()
}
// With is a convenience function to create a lock, execute a function while
// holding that lock, and then release the lock on completion.
//
// See L's With method for details.
func With(path string, fn func() error) error { return WithBlocking(path, nil, fn) }
// WithBlocking is a convenience function to create a lock, execute a function
// while holding that lock, and then release the lock on completion. The
// supplied block function is used to retry (see L's Block field).
//
// See L's With method for details.
func WithBlocking(path string, b Blocker, fn func() error) error {
l := L{
Path: path,
Block: b,
}
return l.With(fn)
}
// Lock acquires a filesystem lock for the given path.
//
// If the lock could not be acquired because it is held by another entity,
// ErrLockHeld will be returned. If an error is encountered while locking,
// that error will be returned.
//
// Lock is a convenience method for L's Lock.
func LockShared(path string) (Handle, error) { return LockSharedBlocking(path, nil) }
// LockSharedBlocking acquires a shared filesystem lock for the given path. If
// the lock is already held, LockSharedBlocking will repeatedly attempt to
// acquire it using the supplied Blocker in between attempts.
//
// If no Blocker is provided and the lock could not be acquired because it is
// held by another entity, ErrLockHeld will be returned. If an error is
// encountered while locking, or an error is returned by b, that error will be
// returned.
//
// LockSharedBlocking is a convenience method for L's Lock.
func LockSharedBlocking(path string, b Blocker) (Handle, error) {
l := L{
Path: path,
Shared: true,
Block: b,
}
return l.Lock()
}
// WithShared is a convenience function to create a lock, execute a function while
// holding that lock, and then release the lock on completion.
//
// See L's With method for details.
func WithShared(path string, fn func() error) error { return WithSharedBlocking(path, nil, fn) }
// WithSharedBlocking is a convenience function to create a lock, execute a
// function while holding that lock, and then release the lock on completion.
// The supplied block function is used to retry (see L's Block field).
//
// See L's With method for details.
func WithSharedBlocking(path string, b Blocker, fn func() error) error {
l := L{
Path: path,
Shared: true,
Block: b,
}
return l.With(fn)
}