Skip to content

Instantly share code, notes, and snippets.

@shmsr
Forked from karrick/flock.go
Created November 12, 2020 18:03
Show Gist options
  • Save shmsr/e12827551ae6694de8ed94a6d5aa562a to your computer and use it in GitHub Desktop.
Save shmsr/e12827551ae6694de8ed94a6d5aa562a to your computer and use it in GitHub Desktop.
Examples of using advisory locking with golang.org/x/sys/unix
// These funcitons ought to come with a huge warning. Using them without
// understanding the differences between blocking and non-blocking, or
// between exclusive and shared access, and when to use them will cause
// problems that do not necessarily manifest right away, but rather
// fester in your program and rear their ugly head in the middle of the
// night when you're sleeping.
//
// If you use advisory file locking, *always* use Shared locking every
// single time you read the file, and *always* use Exclusive locking every
// single time you write the file. Period. There are no exceptions. Heed
// this advice, or make your life, or the life of someone who is woken up
// in the middle of the night, worse.
// withExclusiveBlocking opens the file for reading and writing, creating it
// when necessary, and attempts to obtain an exclusive advisory lock on the
// file, blocking until the file lock is obtained. It returns the error if it
// cannot open the file or cannot obtain an exclusive advisory lock on the file.
func withExclusiveBlocking(pathname string, callback func(*os.File)) error {
fh, err := os.OpenFile(pathname, os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()
if err = unix.Flock(int(fh.Fd()), unix.LOCK_EX); err != nil {
return err
}
callback(fh)
return nil
}
// withExclusiveNonBlocking opens the file for reading and writing, creating it
// when necessary, and attempts to obtain an exclusive advisory lock on the file
// without blocking. It returns the error if it cannot open the file, or if it
// cannot obtain the exclusive advisory lock on the file.
func withExclusiveNonBlocking(pathname string, callback func(*os.File)) error {
fh, err := os.OpenFile(pathname, os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return err
}
defer fh.Close()
if err = unix.Flock(int(fh.Fd()), unix.LOCK_EX|unix.LOCK_NB); err != nil {
return err
}
callback(fh)
return nil
}
// withSharedBlocking opens the file for reading, creating it when necessary,
// and attempts to obtain a shared advisory lock on the file, blocking until the
// file lock is obtained. It returns the error if it cannot open the file or
// cannot obtain a shared advisory lock on the file.
func withSharedBlocking(pathname string, callback func(*os.File)) error {
fh, err := os.Open(pathname)
if err != nil {
return err
}
defer fh.Close()
if err = unix.Flock(int(fh.Fd()), unix.LOCK_SH); err != nil {
return err
}
callback(fh)
return nil
}
// withSharedNonBlocking opens the file for reading, creating it when necessary,
// and attempts to obtain a sahred advisory lock on the file without
// blocking. It returns the error if it cannot open the file, or if it cannot
// obtain the shared advisory lock on the file.
func withSharedNonBlocking(pathname string, callback func(*os.File)) error {
fh, err := os.Open(pathname)
if err != nil {
return err
}
defer fh.Close()
if err = unix.Flock(int(fh.Fd()), unix.LOCK_SH|unix.LOCK_NB); err != nil {
return err
}
callback(fh)
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment