diff options
| author | 2022-02-12 18:27:58 +0000 | |
|---|---|---|
| committer | 2022-02-12 18:27:58 +0000 | |
| commit | 31935ee206107f077878d3cdb6a26b82436b6893 (patch) | |
| tree | 2d522bf98013dc5a4539133561b645fd7457eb06 /vendor/codeberg.org/gruf/go-store/storage/lock.go | |
| parent | [chore] Add nightly mirror to Codeberg.org (#392) (diff) | |
| parent | Go mod tidy (diff) | |
| download | gotosocial-0.2.0.tar.xz | |
Merge pull request #361 from superseriousbusiness/media_refactorv0.2.0
Refactor media handler to allow async media resolution
Diffstat (limited to 'vendor/codeberg.org/gruf/go-store/storage/lock.go')
| -rw-r--r-- | vendor/codeberg.org/gruf/go-store/storage/lock.go | 70 |
1 files changed, 56 insertions, 14 deletions
diff --git a/vendor/codeberg.org/gruf/go-store/storage/lock.go b/vendor/codeberg.org/gruf/go-store/storage/lock.go index 3d794cda9..8a6c4c5e8 100644 --- a/vendor/codeberg.org/gruf/go-store/storage/lock.go +++ b/vendor/codeberg.org/gruf/go-store/storage/lock.go @@ -1,34 +1,76 @@ package storage import ( - "os" + "sync" + "sync/atomic" "syscall" "codeberg.org/gruf/go-store/util" ) -type lockableFile struct { - *os.File +// LockFile is our standard lockfile name. +const LockFile = "store.lock" + +// Lock represents a filesystem lock to ensure only one storage instance open per path. +type Lock struct { + fd int + wg sync.WaitGroup + st uint32 } -func openLock(path string) (*lockableFile, error) { - file, err := open(path, defaultFileLockFlags) +// OpenLock opens a lockfile at path. +func OpenLock(path string) (*Lock, error) { + var fd int + + // Open the file descriptor at path + err := util.RetryOnEINTR(func() (err error) { + fd, err = syscall.Open(path, defaultFileLockFlags, defaultFilePerms) + return + }) if err != nil { return nil, err } - return &lockableFile{file}, nil + + // Get a flock on the file descriptor + err = util.RetryOnEINTR(func() error { + return syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB) + }) + if err != nil { + return nil, errSwapUnavailable(err) + } + + return &Lock{fd: fd}, nil } -func (f *lockableFile) lock() error { - return f.flock(syscall.LOCK_EX | syscall.LOCK_NB) +// Add will add '1' to the underlying sync.WaitGroup. +func (f *Lock) Add() { + f.wg.Add(1) } -func (f *lockableFile) unlock() error { - return f.flock(syscall.LOCK_UN | syscall.LOCK_NB) +// Done will decrememnt '1' from the underlying sync.WaitGroup. +func (f *Lock) Done() { + f.wg.Done() } -func (f *lockableFile) flock(how int) error { - return util.RetryOnEINTR(func() error { - return syscall.Flock(int(f.Fd()), how) - }) +// 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) { + // Wait until done + f.wg.Wait() + + // Ensure gets closed + defer syscall.Close(f.fd) + + // Call funlock on the file descriptor + err = util.RetryOnEINTR(func() error { + 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) } |
