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  }