github.com/decred/dcrlnd@v0.7.6/kvdb/etcd/commit_queue_test.go (about) 1 //go:build kvdb_etcd 2 // +build kvdb_etcd 3 4 package etcd 5 6 import ( 7 "context" 8 "sync" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/require" 14 ) 15 16 // TestCommitQueue tests that non-conflicting transactions commit concurrently, 17 // while conflicting transactions are queued up. 18 func TestCommitQueue(t *testing.T) { 19 // The duration of each commit. 20 const commitDuration = time.Millisecond * 500 21 const numCommits = 5 22 23 var wg sync.WaitGroup 24 commits := make([]string, numCommits) 25 idx := int32(-1) 26 27 commit := func(tag string, sleep bool) func() { 28 return func() { 29 defer wg.Done() 30 31 // Update our log of commit order. Avoid blocking 32 // by preallocating the commit log and increasing 33 // the log index atomically. 34 if sleep { 35 time.Sleep(commitDuration) 36 } 37 38 i := atomic.AddInt32(&idx, 1) 39 commits[i] = tag 40 } 41 } 42 43 ctx := context.Background() 44 ctx, cancel := context.WithCancel(ctx) 45 q := NewCommitQueue(ctx) 46 defer q.Stop() 47 defer cancel() 48 49 wg.Add(numCommits) 50 t1 := time.Now() 51 52 // Tx1 (long): reads: key1, key2, writes: key3, conflict: none 53 q.Add( 54 commit("free", true), 55 []string{"key1", "key2"}, 56 []string{"key3"}, 57 ) 58 // Tx2: reads: key1, key2, writes: key3, conflict: Tx1 59 q.Add( 60 commit("blocked1", false), 61 []string{"key1", "key2"}, 62 []string{"key3"}, 63 ) 64 // Tx3 (long): reads: key1, writes: key4, conflict: none 65 q.Add( 66 commit("free", true), 67 []string{"key1", "key2"}, 68 []string{"key4"}, 69 ) 70 // Tx4 (long): reads: key1, writes: none, conflict: none 71 q.Add( 72 commit("free", true), 73 []string{"key1", "key2"}, 74 []string{}, 75 ) 76 // Tx4: reads: key2, writes: key4 conflict: Tx3 77 q.Add( 78 commit("blocked2", false), 79 []string{"key2"}, 80 []string{"key4"}, 81 ) 82 83 // Wait for all commits. 84 wg.Wait() 85 t2 := time.Now() 86 87 // Expected total execution time: delta. 88 // 2 * commitDuration <= delta < 3 * commitDuration 89 delta := t2.Sub(t1) 90 require.LessOrEqual(t, int64(commitDuration*2), int64(delta)) 91 require.Greater(t, int64(commitDuration*3), int64(delta)) 92 93 // Expect that the non-conflicting "free" transactions are executed 94 // before the blocking ones, and the blocking ones are executed in 95 // the order of addition. 96 require.Equal(t, 97 []string{"free", "blocked1", "free", "free", "blocked2"}, 98 commits, 99 ) 100 }