Skip to content

Commit 4fc82df

Browse files
authored
Merge pull request #479 from koct9i/fix-try-lock-state
Do not block try lock on state mutex
2 parents baac55b + 0b25f83 commit 4fc82df

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

storage/pkg/lockfile/lockfile.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,10 @@ func (l *LockFile) tryLock(lType rawfilelock.LockType) error {
420420
if !success {
421421
return fmt.Errorf("resource temporarily unavailable")
422422
}
423-
l.stateMutex.Lock()
423+
if !l.stateMutex.TryLock() {
424+
rwMutexUnlocker()
425+
return fmt.Errorf("resource temporarily unavailable")
426+
}
424427
defer l.stateMutex.Unlock()
425428
if l.counter == 0 {
426429
// If we're the first reference on the lock, we need to open the file again.

storage/pkg/lockfile/lockfile_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,55 @@ func TestTryReadLockFile(t *testing.T) {
277277
assert.Nil(t, <-errChan)
278278
}
279279

280+
func TestTryLockState(t *testing.T) {
281+
l, err := getTempLockfile()
282+
require.NoError(t, err, "creating lock")
283+
defer os.Remove(l.name)
284+
285+
// Take a write lock somewhere.
286+
cmd, wc, rc, err := subLock(l)
287+
require.NoError(t, err)
288+
_, err = io.Copy(io.Discard, rc)
289+
require.NoError(t, err)
290+
291+
err = l.TryRLock()
292+
assert.NotNil(t, err)
293+
294+
// Lock and hold state mutex.
295+
locked := make(chan bool)
296+
go func() {
297+
locked <- false
298+
l.RLock()
299+
locked <- true
300+
l.Unlock()
301+
locked <- false
302+
}()
303+
304+
assert.False(t, <-locked)
305+
306+
// Wait state mutex is locked.
307+
for l.stateMutex.TryLock() {
308+
l.stateMutex.Unlock()
309+
time.Sleep(100 * time.Millisecond)
310+
}
311+
312+
// Try locks should fail without blocking.
313+
errChan := make(chan error)
314+
go func() {
315+
errChan <- l.TryRLock()
316+
errChan <- l.TryLock()
317+
}()
318+
assert.NotNil(t, <-errChan)
319+
assert.NotNil(t, <-errChan)
320+
321+
wc.Close()
322+
err = cmd.Wait()
323+
require.NoError(t, err)
324+
325+
assert.True(t, <-locked)
326+
assert.False(t, <-locked)
327+
}
328+
280329
func TestLockfileRead(t *testing.T) {
281330
l, err := getTempLockfile()
282331
require.Nil(t, err, "error getting temporary lock file")

0 commit comments

Comments
 (0)