diff --git a/changelog/unreleased/add-write-mutexes.md b/changelog/unreleased/add-write-mutexes.md new file mode 100644 index 000000000..ec16003a1 --- /dev/null +++ b/changelog/unreleased/add-write-mutexes.md @@ -0,0 +1,5 @@ +Bugfix: Add write mutexes + +Concurrent account or groups writes would corrupt the json file on disk, because the different goroutines would be treated as a single thread from the os. We introduce a mutex for account and group file writes each. This locks the update frequency for all accounts/groups and could be further improved by using a concurrent map of mutexes with a mutex per account / group. PR welcome. + +https://github.com/owncloud/ocis-accounts/pull/71 \ No newline at end of file diff --git a/pkg/service/v0/accounts.go b/pkg/service/v0/accounts.go index a72179451..6a3e8ec2c 100644 --- a/pkg/service/v0/accounts.go +++ b/pkg/service/v0/accounts.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "regexp" + "sync" "time" fieldmask_utils "github.com/mennanov/fieldmask-utils" @@ -84,6 +85,8 @@ func (s Service) loadAccount(id string, a *proto.Account) (err error) { return } +var accountMutex sync.Mutex + func (s Service) writeAccount(a *proto.Account) (err error) { // leave only the group id @@ -95,6 +98,9 @@ func (s Service) writeAccount(a *proto.Account) (err error) { } path := filepath.Join(s.Config.Server.AccountsDataPath, "accounts", a.Id) + + accountMutex.Lock() + defer accountMutex.Unlock() if err = ioutil.WriteFile(path, bytes, 0600); err != nil { return merrors.InternalServerError(s.id, "could not write account: %v", err.Error()) } diff --git a/pkg/service/v0/groups.go b/pkg/service/v0/groups.go index 666d8608d..150dc7d60 100644 --- a/pkg/service/v0/groups.go +++ b/pkg/service/v0/groups.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sync" "github.com/CiscoM31/godata" "github.com/blevesearch/bleve" @@ -66,6 +67,8 @@ func (s Service) loadGroup(id string, g *proto.Group) (err error) { return } +var groupMutex sync.Mutex + func (s Service) writeGroup(g *proto.Group) (err error) { // leave only the member id @@ -77,6 +80,9 @@ func (s Service) writeGroup(g *proto.Group) (err error) { } path := filepath.Join(s.Config.Server.AccountsDataPath, "groups", g.Id) + + groupMutex.Lock() + defer groupMutex.Unlock() if err = ioutil.WriteFile(path, bytes, 0600); err != nil { return merrors.InternalServerError(s.id, "could not write group: %v", err.Error()) }