diff options
Diffstat (limited to 'internal/federation')
-rw-r--r-- | internal/federation/federatingdb/db.go | 29 | ||||
-rw-r--r-- | internal/federation/federatingdb/lock.go | 85 |
2 files changed, 7 insertions, 107 deletions
diff --git a/internal/federation/federatingdb/db.go b/internal/federation/federatingdb/db.go index 5de7fa607..36df2593f 100644 --- a/internal/federation/federatingdb/db.go +++ b/internal/federation/federatingdb/db.go @@ -20,9 +20,8 @@ package federatingdb import ( "context" - "sync" - "time" + "codeberg.org/gruf/go-mutexes" "github.com/superseriousbusiness/activity/pub" "github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/gotosocial/internal/db" @@ -41,9 +40,7 @@ type DB interface { // FederatingDB uses the underlying DB interface to implement the go-fed pub.Database interface. // It doesn't care what the underlying implementation of the DB interface is, as long as it works. type federatingDB struct { - mutex sync.Mutex - locks map[string]*mutex - pool sync.Pool + locks mutexes.MutexMap db db.DB typeConverter typeutils.TypeConverter } @@ -51,29 +48,9 @@ type federatingDB struct { // New returns a DB interface using the given database and config func New(db db.DB) DB { fdb := federatingDB{ - mutex: sync.Mutex{}, - locks: make(map[string]*mutex, 100), - pool: sync.Pool{New: func() interface{} { return &mutex{} }}, + locks: mutexes.NewMap(-1, -1), // use defaults db: db, typeConverter: typeutils.NewConverter(db), } - go fdb.cleanupLocks() return &fdb } - -func (db *federatingDB) cleanupLocks() { - for { - // Sleep for a minute... - time.Sleep(time.Minute) - - // Delete unused locks from map - db.mutex.Lock() - for id, mu := range db.locks { - if !mu.inUse() { - delete(db.locks, id) - db.pool.Put(mu) - } - } - db.mutex.Unlock() - } -} 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 } |