github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/persist/fs/commitlog/commit_log_conc_test.go (about) 1 // +build big 2 // 3 // Copyright (c) 2018 Uber Technologies, Inc. 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 package commitlog 24 25 import ( 26 "testing" 27 "time" 28 29 "github.com/m3db/m3/src/dbnode/ts" 30 "github.com/m3db/m3/src/x/context" 31 xtime "github.com/m3db/m3/src/x/time" 32 33 "github.com/stretchr/testify/require" 34 ) 35 36 // TestCommitLogActiveLogsConcurrency makes sure that the 37 // ActiveLogs() API behaves correctly even while concurrent 38 // writes are going on. 39 func TestCommitLogActiveLogsConcurrency(t *testing.T) { 40 var ( 41 opts, _ = newTestOptions(t, overrides{ 42 strategy: StrategyWriteBehind, 43 }) 44 numFilesRequired = 10 45 ) 46 47 defer cleanup(t, opts) 48 49 var ( 50 doneCh = make(chan struct{}) 51 commitLog = newTestCommitLog(t, opts) 52 ) 53 54 // One goroutine continuously writing. 55 go func() { 56 for { 57 select { 58 case <-doneCh: 59 return 60 default: 61 time.Sleep(time.Millisecond) 62 err := commitLog.Write( 63 context.NewBackground(), 64 testSeries(t, opts, 0, "foo.bar", testTags1, 127), 65 ts.Datapoint{}, 66 xtime.Second, 67 nil) 68 if err == errCommitLogClosed { 69 return 70 } 71 if err == ErrCommitLogQueueFull { 72 continue 73 } 74 if err != nil { 75 panic(err) 76 } 77 } 78 } 79 }() 80 81 // One goroutine continuously rotating the logs. 82 go func() { 83 for { 84 select { 85 case <-doneCh: 86 return 87 default: 88 time.Sleep(time.Millisecond) 89 _, err := commitLog.RotateLogs() 90 if err == errCommitLogClosed { 91 return 92 } 93 if err != nil { 94 panic(err) 95 } 96 } 97 } 98 }() 99 100 // One goroutine continuously checking active logs. 101 go func() { 102 var ( 103 lastSeenFile string 104 numFilesSeen int 105 ) 106 for numFilesSeen < numFilesRequired { 107 time.Sleep(100 * time.Millisecond) 108 logs, err := commitLog.ActiveLogs() 109 if err != nil { 110 panic(err) 111 } 112 require.Equal(t, 2, len(logs)) 113 if logs[0].FilePath != lastSeenFile { 114 lastSeenFile = logs[0].FilePath 115 numFilesSeen++ 116 } 117 } 118 close(doneCh) 119 }() 120 121 <-doneCh 122 123 require.NoError(t, commitLog.Close()) 124 } 125 126 // TestCommitLogRotateLogsConcurrency makes sure that the 127 // RotateLogs() API behaves correctly even while concurrent 128 // writes are going on. 129 func TestCommitLogRotateLogsConcurrency(t *testing.T) { 130 var ( 131 opts, _ = newTestOptions(t, overrides{ 132 strategy: StrategyWriteBehind, 133 }) 134 numFilesRequired = 10 135 ) 136 137 opts = opts.SetBlockSize(1 * time.Millisecond) 138 defer cleanup(t, opts) 139 140 var ( 141 doneCh = make(chan struct{}) 142 commitLog = newTestCommitLog(t, opts) 143 ) 144 145 // One goroutine continuously writing. 146 go func() { 147 for { 148 select { 149 case <-doneCh: 150 return 151 default: 152 time.Sleep(time.Millisecond) 153 err := commitLog.Write( 154 context.NewBackground(), 155 testSeries(t, opts, 0, "foo.bar", testTags1, 127), 156 ts.Datapoint{}, 157 xtime.Second, 158 nil) 159 if err == errCommitLogClosed { 160 return 161 } 162 if err == ErrCommitLogQueueFull { 163 continue 164 } 165 if err != nil { 166 panic(err) 167 } 168 } 169 } 170 }() 171 172 // One goroutine continuously rotating logs. 173 go func() { 174 var ( 175 lastSeenFile string 176 numFilesSeen int 177 ) 178 for numFilesSeen < numFilesRequired { 179 time.Sleep(100 * time.Millisecond) 180 file, err := commitLog.RotateLogs() 181 if err != nil { 182 panic(err) 183 } 184 if file.FilePath != lastSeenFile { 185 lastSeenFile = file.FilePath 186 numFilesSeen++ 187 } 188 } 189 close(doneCh) 190 }() 191 192 <-doneCh 193 194 require.NoError(t, commitLog.Close()) 195 }