gotosocial/vendor/codeberg.org/gruf/go-store/v2/storage/lock.go

60 lines
1.3 KiB
Go
Raw Normal View History

package storage
import (
2022-01-24 16:35:13 +00:00
"sync/atomic"
"syscall"
)
2022-01-29 11:15:51 +00:00
// LockFile is our standard lockfile name.
const LockFile = "store.lock"
2022-01-24 16:35:13 +00:00
// Lock represents a filesystem lock to ensure only one storage instance open per path.
type Lock struct {
fd int
st uint32
}
2022-01-16 17:52:30 +00:00
// OpenLock opens a lockfile at path.
2022-01-24 16:35:13 +00:00
func OpenLock(path string) (*Lock, error) {
var fd int
// Open the file descriptor at path
err := retryOnEINTR(func() (err error) {
2022-01-24 16:35:13 +00:00
fd, err = syscall.Open(path, defaultFileLockFlags, defaultFilePerms)
return
})
if err != nil {
return nil, err
}
2022-01-24 16:35:13 +00:00
// Get a flock on the file descriptor
err = retryOnEINTR(func() error {
2022-01-24 16:35:13 +00:00
return syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB)
})
if err != nil {
return nil, errSwapUnavailable(err)
}
return &Lock{fd: fd}, nil
}
2022-01-24 16:35:13 +00:00
// Close will attempt to close the lockfile and file descriptor.
func (f *Lock) Close() error {
var err error
if atomic.CompareAndSwapUint32(&f.st, 0, 1) {
// Ensure gets closed
defer syscall.Close(f.fd)
// Call funlock on the file descriptor
err = retryOnEINTR(func() error {
2022-01-24 16:35:13 +00:00
return syscall.Flock(f.fd, syscall.LOCK_UN|syscall.LOCK_NB)
})
}
return err
}
// Closed will return whether this lockfile has been closed (and unlocked).
func (f *Lock) Closed() bool {
return (atomic.LoadUint32(&f.st) == 1)
}