167 lines
3.2 KiB
Go
167 lines
3.2 KiB
Go
package tsm1_test
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"testing/quick"
|
|
"time"
|
|
|
|
"github.com/influxdb/influxdb/tsdb/engine/tsm1"
|
|
)
|
|
|
|
func TestWriteLock_FullCover(t *testing.T) {
|
|
w := &tsm1.WriteLock{}
|
|
w.LockRange(2, 10)
|
|
|
|
lock := make(chan bool)
|
|
timeout := time.NewTimer(10 * time.Millisecond)
|
|
go func() {
|
|
w.LockRange(1, 11)
|
|
lock <- true
|
|
}()
|
|
select {
|
|
case <-lock:
|
|
t.Fatal("able to get lock when we shouldn't")
|
|
case <-timeout.C:
|
|
// we're all good
|
|
}
|
|
}
|
|
|
|
func TestWriteLock_RightIntersect(t *testing.T) {
|
|
w := &tsm1.WriteLock{}
|
|
w.LockRange(2, 10)
|
|
|
|
lock := make(chan bool)
|
|
timeout := time.NewTimer(10 * time.Millisecond)
|
|
go func() {
|
|
w.LockRange(5, 15)
|
|
lock <- true
|
|
}()
|
|
select {
|
|
case <-lock:
|
|
t.Fatal("able to get lock when we shouldn't")
|
|
case <-timeout.C:
|
|
// we're all good
|
|
}
|
|
}
|
|
|
|
func TestWriteLock_LeftIntersect(t *testing.T) {
|
|
w := &tsm1.WriteLock{}
|
|
w.LockRange(1, 4)
|
|
|
|
lock := make(chan bool)
|
|
timeout := time.NewTimer(10 * time.Millisecond)
|
|
go func() {
|
|
w.LockRange(1, 11)
|
|
lock <- true
|
|
}()
|
|
select {
|
|
case <-lock:
|
|
t.Fatal("able to get lock when we shouldn't")
|
|
case <-timeout.C:
|
|
// we're all good
|
|
}
|
|
}
|
|
|
|
func TestWriteLock_Inside(t *testing.T) {
|
|
w := &tsm1.WriteLock{}
|
|
w.LockRange(4, 8)
|
|
|
|
lock := make(chan bool)
|
|
timeout := time.NewTimer(10 * time.Millisecond)
|
|
go func() {
|
|
w.LockRange(1, 11)
|
|
lock <- true
|
|
}()
|
|
select {
|
|
case <-lock:
|
|
t.Fatal("able to get lock when we shouldn't")
|
|
case <-timeout.C:
|
|
// we're all good
|
|
}
|
|
}
|
|
|
|
func TestWriteLock_Same(t *testing.T) {
|
|
w := &tsm1.WriteLock{}
|
|
w.LockRange(2, 10)
|
|
|
|
lock := make(chan bool)
|
|
timeout := time.NewTimer(10 * time.Millisecond)
|
|
go func() {
|
|
w.LockRange(2, 10)
|
|
lock <- true
|
|
}()
|
|
select {
|
|
case <-lock:
|
|
t.Fatal("able to get lock when we shouldn't")
|
|
case <-timeout.C:
|
|
// we're all good
|
|
}
|
|
}
|
|
|
|
// func TestWriteLock_FreeRangeWithContentionElsewhere(t *testing.T) {
|
|
// w := &tsm1.WriteLock{}
|
|
// w.LockRange(2, 10)
|
|
|
|
// lock := make(chan bool)
|
|
// freeRange := make(chan bool)
|
|
// timeout := time.NewTimer(10 * time.Millisecond)
|
|
// var wg sync.WaitGroup
|
|
|
|
// wg.Add(1)
|
|
// go func() {
|
|
// wg.Done()
|
|
// w.LockRange(4, 12)
|
|
// lock <- true
|
|
// }()
|
|
|
|
// // make sure the other go func has gotten to the point of requesting the lock
|
|
// wg.Wait()
|
|
// go func() {
|
|
// w.LockRange(15, 23)
|
|
// freeRange <- true
|
|
// }()
|
|
// select {
|
|
// case <-lock:
|
|
// t.Fatal("able to get lock when we shouldn't")
|
|
// case <-timeout.C:
|
|
// t.Fatal("unable to get lock of free range when contention exists elsewhere")
|
|
// case <-freeRange:
|
|
// // we're all good
|
|
// }
|
|
// }
|
|
|
|
func TestWriteLock_Quick(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("short mode")
|
|
}
|
|
|
|
quick.Check(func(extents []struct{ Min, Max uint64 }) bool {
|
|
var wg sync.WaitGroup
|
|
var mu tsm1.WriteLock
|
|
for _, extent := range extents {
|
|
// Limit range.
|
|
extent.Min %= 10
|
|
extent.Max %= 10
|
|
|
|
// Reverse if out of order.
|
|
if extent.Min > extent.Max {
|
|
extent.Min, extent.Max = extent.Max, extent.Min
|
|
}
|
|
|
|
// Lock, wait and unlock in a separate goroutine.
|
|
wg.Add(1)
|
|
go func(min, max int64) {
|
|
defer wg.Done()
|
|
mu.LockRange(min, max)
|
|
time.Sleep(1 * time.Millisecond)
|
|
mu.UnlockRange(min, max)
|
|
}(int64(extent.Min), int64(extent.Max))
|
|
}
|
|
|
|
// All locks should return.
|
|
wg.Wait()
|
|
return true
|
|
}, nil)
|
|
}
|