365046209e
Uses finer grained locking so that each volume name gets its own lock rather than only being protected by the global lock, which itself needs to be unlocked during cetain operations (`create` especially`) Signed-off-by: Brian Goff <cpuguy83@gmail.com> Upstream-commit: fe66fdd18c0307cc02e6aeff8625c179452b8436 Component: engine
91 lines
1.3 KiB
Go
91 lines
1.3 KiB
Go
package locker
|
|
|
|
import (
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
func TestLockCounter(t *testing.T) {
|
|
l := &lockCtr{}
|
|
l.inc()
|
|
|
|
if l.waiters != 1 {
|
|
t.Fatal("counter inc failed")
|
|
}
|
|
|
|
l.dec()
|
|
if l.waiters != 0 {
|
|
t.Fatal("counter dec failed")
|
|
}
|
|
}
|
|
|
|
func TestLockerLock(t *testing.T) {
|
|
l := New()
|
|
l.Lock("test")
|
|
ctr := l.locks["test"]
|
|
|
|
if ctr.count() != 0 {
|
|
t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
|
|
}
|
|
|
|
chDone := make(chan struct{})
|
|
go func() {
|
|
l.Lock("test")
|
|
close(chDone)
|
|
}()
|
|
|
|
runtime.Gosched()
|
|
|
|
select {
|
|
case <-chDone:
|
|
t.Fatal("lock should not have returned while it was still held")
|
|
default:
|
|
}
|
|
|
|
if ctr.count() != 1 {
|
|
t.Fatalf("expected waiters to be 1, got: %d", ctr.count())
|
|
}
|
|
|
|
if err := l.Unlock("test"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
runtime.Gosched()
|
|
|
|
select {
|
|
case <-chDone:
|
|
default:
|
|
// one more time just to be sure
|
|
runtime.Gosched()
|
|
select {
|
|
case <-chDone:
|
|
default:
|
|
t.Fatalf("lock should have completed")
|
|
}
|
|
}
|
|
|
|
if ctr.count() != 0 {
|
|
t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
|
|
}
|
|
}
|
|
|
|
func TestLockerUnlock(t *testing.T) {
|
|
l := New()
|
|
|
|
l.Lock("test")
|
|
l.Unlock("test")
|
|
|
|
chDone := make(chan struct{})
|
|
go func() {
|
|
l.Lock("test")
|
|
close(chDone)
|
|
}()
|
|
|
|
runtime.Gosched()
|
|
|
|
select {
|
|
case <-chDone:
|
|
default:
|
|
t.Fatalf("lock should not be blocked")
|
|
}
|
|
}
|