summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-store/storage/lock.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2022-02-12 18:27:58 +0000
committerLibravatar GitHub <noreply@github.com>2022-02-12 18:27:58 +0000
commit31935ee206107f077878d3cdb6a26b82436b6893 (patch)
tree2d522bf98013dc5a4539133561b645fd7457eb06 /vendor/codeberg.org/gruf/go-store/storage/lock.go
parent[chore] Add nightly mirror to Codeberg.org (#392) (diff)
parentGo mod tidy (diff)
downloadgotosocial-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.go70
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)
}