storage/filesystem: add R/W locking

This commit adds read/write locking for individual files, so that
concurrent requests (e.g. to read and write the same file) cannot
interfere with one another.

The locking is not very fine-grained at the moment, and can probably be
improved upon. But it does ensure consistency.
This commit is contained in:
Conrad Hoffmann 2024-11-07 12:14:45 +01:00
parent 7969df1a38
commit 6eeea854be
3 changed files with 88 additions and 2 deletions

View file

@ -10,6 +10,7 @@ import (
"path/filepath"
"regexp"
"strings"
"sync"
"github.com/rs/zerolog/log"
@ -20,9 +21,13 @@ import (
type filesystemBackend struct {
webdav.UserPrincipalBackend
path string
caldavPrefix string
carddavPrefix string
// maps file path to *sync.RWMutex
locks sync.Map
}
var (
@ -47,6 +52,36 @@ func NewFilesystem(fsPath, caldavPrefix, carddavPrefix string, userPrincipalBack
return backend, backend, nil
}
func (b *filesystemBackend) RLock(filename string) {
lock_, _ := b.locks.LoadOrStore(filename, &sync.RWMutex{})
lock := lock_.(*sync.RWMutex)
lock.RLock()
}
func (b *filesystemBackend) RUnlock(filename string) {
lock_, ok := b.locks.Load(filename)
if !ok {
panic("attempt to unlock non-existing lock")
}
lock := lock_.(*sync.RWMutex)
lock.RUnlock()
}
func (b *filesystemBackend) Lock(filename string) {
lock_, _ := b.locks.LoadOrStore(filename, &sync.RWMutex{})
lock := lock_.(*sync.RWMutex)
lock.Lock()
}
func (b *filesystemBackend) Unlock(filename string) {
lock_, ok := b.locks.Load(filename)
if !ok {
panic("attempt to unlock non-existing lock")
}
lock := lock_.(*sync.RWMutex)
lock.Unlock()
}
func ensureLocalDir(path string) error {
if _, err := os.Stat(path); os.IsNotExist(err) {
err = os.MkdirAll(path, 0755)