diff options
author | 2021-05-27 16:06:24 +0200 | |
---|---|---|
committer | 2021-05-27 16:06:24 +0200 | |
commit | 40add686913b7eb6edd5a780e37e7513b43a337f (patch) | |
tree | 75549dff97e5a15f732a505d4d00aa7a686bdad8 /internal/federation/federatingdb/lock.go | |
parent | Faves (#31) (diff) | |
download | gotosocial-40add686913b7eb6edd5a780e37e7513b43a337f.tar.xz |
Notifications (#34)
Notifications working for:
* Mentions
* Faves
* New follow requests
* New followers
Diffstat (limited to 'internal/federation/federatingdb/lock.go')
-rw-r--r-- | internal/federation/federatingdb/lock.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/federation/federatingdb/lock.go b/internal/federation/federatingdb/lock.go new file mode 100644 index 000000000..417fd79b2 --- /dev/null +++ b/internal/federation/federatingdb/lock.go @@ -0,0 +1,70 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package federatingdb + +import ( + "context" + "errors" + "net/url" + "sync" +) + +// Lock takes a lock for the object at the specified id. If an error +// is returned, the lock must not have been taken. +// +// The lock must be able to succeed for an id that does not exist in +// the database. This means acquiring the lock does not guarantee the +// entry exists in the database. +// +// Locks are encouraged to be lightweight and in the Go layer, as some +// 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. + mu := &sync.Mutex{} + mu.Lock() // Optimistically lock if we do store it. + i, loaded := f.locks.LoadOrStore(id.String(), mu) + if loaded { + mu = i.(*sync.Mutex) + 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. + + i, ok := f.locks.Load(id.String()) + if !ok { + return errors.New("missing an id in unlock") + } + mu := i.(*sync.Mutex) + mu.Unlock() + return nil +} |