github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/series/series_parallel_test.go (about) 1 // +build big 2 // 3 // Copyright (c) 2016 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 series 24 25 import ( 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/m3db/m3/src/dbnode/namespace" 31 "github.com/m3db/m3/src/dbnode/storage/block" 32 "github.com/m3db/m3/src/dbnode/ts" 33 "github.com/m3db/m3/src/x/context" 34 "github.com/m3db/m3/src/x/ident" 35 xtest "github.com/m3db/m3/src/x/test" 36 xtime "github.com/m3db/m3/src/x/time" 37 38 "github.com/golang/mock/gomock" 39 "github.com/stretchr/testify/require" 40 ) 41 42 // TestSeriesWriteReadParallel is a regression test that was added to capture 43 // panics that might arise when many parallel writes and reads are happening 44 // at the same time. 45 func TestSeriesWriteReadParallel(t *testing.T) { 46 ctrl := gomock.NewController(xtest.Reporter{T: t}) 47 defer ctrl.Finish() 48 49 // Assume all data has not been written yet. 50 blockRetriever := NewMockQueryableBlockRetriever(ctrl) 51 blockRetriever.EXPECT(). 52 IsBlockRetrievable(gomock.Any()). 53 Return(false, nil). 54 AnyTimes() 55 56 var ( 57 numWorkers = 100 58 numStepsPerWorker = numWorkers * 100 59 opts = newSeriesTestOptions() 60 start = xtime.Now() 61 series = NewDatabaseSeries(DatabaseSeriesOptions{ 62 ID: ident.StringID("foo"), 63 UniqueIndex: 1, 64 BlockRetriever: blockRetriever, 65 Options: opts, 66 }).(*dbSeries) 67 dbBlock = block.NewDatabaseBlock(0, time.Hour*2, 68 ts.Segment{}, block.NewOptions(), namespace.Context{}) 69 ) 70 71 err := series.LoadBlock(dbBlock, WarmWrite) 72 require.NoError(t, err) 73 74 ctx := context.NewBackground() 75 defer ctx.Close() 76 77 wg := sync.WaitGroup{} 78 wg.Add(1) 79 go func() { 80 for i := 0; i < numStepsPerWorker; i++ { 81 wasWritten, _, err := series.Write(ctx, xtime.Now(), float64(i), 82 xtime.Nanosecond, nil, WriteOptions{}) 83 if err != nil { 84 panic(err) 85 } 86 if !wasWritten { 87 panic("write failed") 88 } 89 } 90 wg.Done() 91 }() 92 93 // Outer loop so that reads are competing with other reads, not just writes. 94 for j := 0; j < numWorkers; j++ { 95 wg.Add(1) 96 go func() { 97 for i := 0; i < numStepsPerWorker; i++ { 98 now := xtime.Now() 99 _, err := series.ReadEncoded(ctx, start.Add(-time.Minute), 100 now.Add(time.Minute), namespace.Context{}) 101 if err != nil { 102 panic(err) 103 } 104 } 105 wg.Done() 106 }() 107 } 108 wg.Wait() 109 }