Skip to content

Commit

Permalink
decomposedfs: configurable filelock duration factor
Browse files Browse the repository at this point in the history
Signed-off-by: Jörn Friedrich Dreyer <[email protected]>
  • Loading branch information
butonic committed Nov 25, 2022
1 parent 8c4890d commit b8bc1b5
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 6 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/filelock-duration-factor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: configurable filelock duration factor in decomposedfs

The lock cycle duration factor in decomposedfs can now be changed by setting `lock_cycle_duration_factor`.

https://github.com/cs3org/reva/pull/3493
4 changes: 4 additions & 0 deletions pkg/storage/utils/decomposedfs/decomposedfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ func New(o *options.Options, lu *lookup.Lookup, p PermissionsChecker, tp Tree, p
filelocks.SetMaxLockCycles(o.MaxAcquireLockCycles)
}

if o.LockCycleDurationFactor != 0 {
filelocks.SetLockCycleDurationFactor(o.LockCycleDurationFactor)
}

return &Decomposedfs{
tp: tp,
lu: lu,
Expand Down
3 changes: 2 additions & 1 deletion pkg/storage/utils/decomposedfs/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ type Options struct {
PersonalSpaceAliasTemplate string `mapstructure:"personalspacealias_template"`
GeneralSpaceAliasTemplate string `mapstructure:"generalspacealias_template"`

MaxAcquireLockCycles int `mapstructure:"max_acquire_lock_cycles"`
MaxAcquireLockCycles int `mapstructure:"max_acquire_lock_cycles"`
LockCycleDurationFactor int `mapstructure:"lock_cycle_duration_factor"`
}

// New returns a new Options instance for the given configuration
Expand Down
20 changes: 15 additions & 5 deletions pkg/storage/utils/filelocks/filelocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ import (
const LockFileSuffix = ".flock"

var (
_localLocks sync.Map
_lockCycles sync.Once
_lockCyclesValue = 25
_localLocks sync.Map
// waiting 20 lock cycles with a factor of 30 yields 6300ms, or a little over 6 sec
_lockCycles sync.Once
_lockCyclesValue = 20
_lockCycleDuration sync.Once
_lockCycleDurationFactor = 30

// ErrPathEmpty indicates that no path was specified
ErrPathEmpty = errors.New("lock path is empty")
Expand All @@ -49,6 +52,13 @@ func SetMaxLockCycles(v int) {
})
}

// SetLockCycleDurationFactor configures the factor applied to the timeout allowed durig a lock cycle. Subsequent calls to SetLockCycleDurationFactor have no effect
func SetLockCycleDurationFactor(v int) {
_lockCycleDuration.Do(func() {
_lockCycleDurationFactor = v
})
}

// getMutexedFlock returns a new Flock struct for the given file.
// If there is already one in the local store, it returns nil.
// The caller has to wait until it can get a new one out of this
Expand Down Expand Up @@ -93,7 +103,7 @@ func acquireLock(file string, write bool) (*flock.Flock, error) {
if flock = getMutexedFlock(n); flock != nil {
break
}
w := time.Duration(i*3) * time.Millisecond
w := time.Duration(i*_lockCycleDurationFactor) * time.Millisecond

time.Sleep(w)
}
Expand All @@ -113,7 +123,7 @@ func acquireLock(file string, write bool) (*flock.Flock, error) {
break
}

time.Sleep(time.Duration(i*3) * time.Millisecond)
time.Sleep(time.Duration(i*_lockCycleDurationFactor) * time.Millisecond)
}

if !ok {
Expand Down
34 changes: 34 additions & 0 deletions pkg/storage/utils/filelocks/filelocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func TestAcquireWriteLock(t *testing.T) {
defer fin()

filelocks.SetMaxLockCycles(90)
filelocks.SetLockCycleDurationFactor(3)

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
Expand Down Expand Up @@ -61,6 +62,7 @@ func TestAcquireReadLock(t *testing.T) {
defer fin()

filelocks.SetMaxLockCycles(90)
filelocks.SetLockCycleDurationFactor(3)

var wg sync.WaitGroup
for i := 0; i < 10; i++ {
Expand All @@ -86,6 +88,38 @@ func TestAcquireReadLock(t *testing.T) {
wg.Wait()
}

func TestAcquireReadLockFail(t *testing.T) {
file, fin, _ := filelocks.FileFactory()
defer fin()

filelocks.SetMaxLockCycles(1)
filelocks.SetLockCycleDurationFactor(1)

// create a channel big enough for all waiting groups
errors := make(chan error, 8000)
var wg sync.WaitGroup
for i := 0; i < 8000; i++ {
wg.Add(1)
go func() {
defer wg.Done()

l, err := filelocks.AcquireReadLock(file)
if err != nil {
// collect the error in a channel
errors <- err
return
}
err = filelocks.ReleaseLock(l)
assert.Nil(t, err)
}()
}

// at least one error should have occurred
assert.NotNil(t, <-errors)

wg.Wait()
}

func TestReleaseLock(t *testing.T) {
file, fin, _ := filelocks.FileFactory()
defer fin()
Expand Down

0 comments on commit b8bc1b5

Please sign in to comment.