github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/internal/record/log_writer_test.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package record 6 7 import ( 8 "sync" 9 "sync/atomic" 10 "testing" 11 ) 12 13 func TestSyncQueue(t *testing.T) { 14 var q syncQueue 15 var closed int32 16 17 var flusherWG sync.WaitGroup 18 flusherWG.Add(1) 19 go func() { 20 defer flusherWG.Done() 21 for { 22 if atomic.LoadInt32(&closed) == 1 { 23 return 24 } 25 head, tail := q.load() 26 q.pop(head, tail) 27 } 28 }() 29 30 var commitMu sync.Mutex 31 var doneWG sync.WaitGroup 32 for i := 0; i < SyncConcurrency; i++ { 33 doneWG.Add(1) 34 go func(i int) { 35 defer doneWG.Done() 36 for j := 0; j < 1000; j++ { 37 wg := &sync.WaitGroup{} 38 wg.Add(1) 39 // syncQueue is a single-producer, single-consumer queue. We need to 40 // provide mutual exclusion on the producer side. 41 commitMu.Lock() 42 q.push(wg) 43 commitMu.Unlock() 44 wg.Wait() 45 } 46 }(i) 47 } 48 doneWG.Wait() 49 50 atomic.StoreInt32(&closed, 1) 51 flusherWG.Wait() 52 } 53 54 func TestFlusherCond(t *testing.T) { 55 var mu sync.Mutex 56 var q syncQueue 57 var c flusherCond 58 var closed bool 59 60 c.init(&mu, &q) 61 62 var flusherWG sync.WaitGroup 63 flusherWG.Add(1) 64 go func() { 65 defer flusherWG.Done() 66 67 mu.Lock() 68 defer mu.Unlock() 69 70 for { 71 for { 72 if closed { 73 return 74 } 75 if !q.empty() { 76 break 77 } 78 c.Wait() 79 } 80 81 head, tail := q.load() 82 q.pop(head, tail) 83 } 84 }() 85 86 var commitMu sync.Mutex 87 var doneWG sync.WaitGroup 88 // NB: we're testing with low concurrency here, because what we want to 89 // stress is that signalling of the flusherCond works 90 // correctly. Specifically, we want to make sure that a signal is "lost", 91 // causing the test to wedge. 92 for i := 0; i < 2; i++ { 93 doneWG.Add(1) 94 go func(i int) { 95 defer doneWG.Done() 96 for j := 0; j < 10000; j++ { 97 wg := &sync.WaitGroup{} 98 wg.Add(1) 99 // syncQueue is a single-producer, single-consumer queue. We need to 100 // provide mutual exclusion on the producer side. 101 commitMu.Lock() 102 q.push(wg) 103 commitMu.Unlock() 104 c.Signal() 105 wg.Wait() 106 } 107 }(i) 108 } 109 doneWG.Wait() 110 111 mu.Lock() 112 closed = true 113 c.Signal() 114 mu.Unlock() 115 flusherWG.Wait() 116 }