diff options
author | 2022-04-28 10:18:27 +0100 | |
---|---|---|
committer | 2022-04-28 11:18:27 +0200 | |
commit | cc5f2e98b763b76f1b0d705efcedaa2ea031ad09 (patch) | |
tree | 0edadde7c75d1734a603ae057c7cba4f29c68d5d /internal/federation/federatingdb/lock.go | |
parent | [bugfix] use Exec to rename media_attachments (#498) (diff) | |
download | gotosocial-cc5f2e98b763b76f1b0d705efcedaa2ea031ad09.tar.xz |
[bugfix] Fix possible race condition in federatingdb (#490)
Signed-off-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/federation/federatingdb/lock.go')
-rw-r--r-- | internal/federation/federatingdb/lock.go | 85 |
1 files changed, 4 insertions, 81 deletions
diff --git a/internal/federation/federatingdb/lock.go b/internal/federation/federatingdb/lock.go index 22f2bb77a..e3da99dd6 100644 --- a/internal/federation/federatingdb/lock.go +++ b/internal/federation/federatingdb/lock.go @@ -22,10 +22,6 @@ import ( "context" "errors" "net/url" - "sync" - "sync/atomic" - - "github.com/sirupsen/logrus" ) // Lock takes a lock for the object at the specified id. If an error @@ -39,83 +35,10 @@ import ( // processes require tight loops acquiring and releasing locks. // // Used to ensure race conditions in multiple requests do not occur. -func (f *federatingDB) Lock(c context.Context, id *url.URL) error { - // Before any other Database methods are called, the relevant `id` - // entries are locked to allow for fine-grained concurrency. - - // Strategy: create a new lock, if stored, continue. Otherwise, lock the - // existing mutex. - if id == nil { - return errors.New("Lock: id was nil") - } - idStr := id.String() - - // Acquire map lock - f.mutex.Lock() - - // Get mutex, or create new - mu, ok := f.locks[idStr] - if !ok { - mu, ok = f.pool.Get().(*mutex) - if !ok { - logrus.Panic("Lock: pool entry was not a *mutex") - } - f.locks[idStr] = mu - } - - // Unlock map, acquire mutex lock - f.mutex.Unlock() - mu.Lock() - return nil -} - -// Unlock makes the lock for the object at the specified id available. -// If an error is returned, the lock must have still been freed. -// -// Used to ensure race conditions in multiple requests do not occur. -func (f *federatingDB) Unlock(c context.Context, id *url.URL) error { - // Once Go-Fed is done calling Database methods, the relevant `id` - // entries are unlocked. +func (f *federatingDB) Lock(c context.Context, id *url.URL) (func(), error) { if id == nil { - return errors.New("Unlock: id was nil") + return nil, errors.New("Lock: id was nil") } - idStr := id.String() - - // Check map for mutex - f.mutex.Lock() - mu, ok := f.locks[idStr] - f.mutex.Unlock() - - if !ok { - return errors.New("missing an id in unlock") - } - - // Unlock the mutex - mu.Unlock() - return nil -} - -// mutex defines a mutex we can check the lock status of. -// this is not perfect, but it's good enough for a semi -// regular mutex cleanup routine -type mutex struct { - mu sync.Mutex - st uint32 -} - -// inUse returns if the mutex is in use -func (mu *mutex) inUse() bool { - return atomic.LoadUint32(&mu.st) == 1 -} - -// Lock acquire mutex lock -func (mu *mutex) Lock() { - mu.mu.Lock() - atomic.StoreUint32(&mu.st, 1) -} - -// Unlock releases mutex lock -func (mu *mutex) Unlock() { - mu.mu.Unlock() - atomic.StoreUint32(&mu.st, 0) + unlock := f.locks.Lock(id.String()) + return unlock, nil } |