github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/coldflush_test.go (about) 1 // Copyright (c) 2020 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package storage 22 23 import ( 24 "errors" 25 "sync" 26 "testing" 27 28 "github.com/golang/mock/gomock" 29 "github.com/m3db/m3/src/dbnode/persist" 30 "github.com/m3db/m3/src/x/instrument" 31 xtest "github.com/m3db/m3/src/x/test" 32 xtime "github.com/m3db/m3/src/x/time" 33 "github.com/stretchr/testify/require" 34 ) 35 36 func TestColdFlushManagerFlushAlreadyInProgress(t *testing.T) { 37 ctrl := xtest.NewController(t) 38 defer ctrl.Finish() 39 40 var ( 41 mockPersistManager = persist.NewMockManager(ctrl) 42 mockFlushPersist = persist.NewMockFlushPreparer(ctrl) 43 44 // Channels used to coordinate cold flushing 45 startCh = make(chan struct{}, 1) 46 doneCh = make(chan struct{}, 1) 47 ) 48 defer func() { 49 close(startCh) 50 close(doneCh) 51 }() 52 53 mockFlushPersist.EXPECT().DoneFlush().Return(nil) 54 mockPersistManager.EXPECT().StartFlushPersist().Do(func() { 55 startCh <- struct{}{} 56 <-doneCh 57 }).Return(mockFlushPersist, nil) 58 59 testOpts := DefaultTestOptions().SetPersistManager(mockPersistManager) 60 db := newMockdatabase(ctrl) 61 db.EXPECT().Options().Return(testOpts).AnyTimes() 62 db.EXPECT().IsBootstrapped().Return(true).AnyTimes() 63 db.EXPECT().OwnedNamespaces().Return(nil, nil).AnyTimes() 64 65 cfm := newColdFlushManager(db, mockPersistManager, testOpts).(*coldFlushManager) 66 cfm.pm = mockPersistManager 67 68 var ( 69 wg sync.WaitGroup 70 now = xtime.UnixNano(0) 71 ) 72 wg.Add(2) 73 74 // Goroutine 1 should successfully flush. 75 go func() { 76 defer wg.Done() 77 require.True(t, cfm.Run(now)) 78 }() 79 80 // Goroutine 2 should indicate already flushing. 81 go func() { 82 defer wg.Done() 83 84 // Wait until we start the cold flushing process. 85 <-startCh 86 87 // Ensure it doesn't allow a parallel flush. 88 require.False(t, cfm.Run(now)) 89 90 // Allow the cold flush to finish. 91 doneCh <- struct{}{} 92 }() 93 94 wg.Wait() 95 96 } 97 98 func TestColdFlushManagerFlushDoneFlushError(t *testing.T) { 99 ctrl := xtest.NewController(t) 100 defer ctrl.Finish() 101 102 var ( 103 fakeErr = errors.New("fake error while marking flush done") 104 mockPersistManager = persist.NewMockManager(ctrl) 105 mockFlushPersist = persist.NewMockFlushPreparer(ctrl) 106 ) 107 108 mockFlushPersist.EXPECT().DoneFlush().Return(fakeErr) 109 mockPersistManager.EXPECT().StartFlushPersist().Return(mockFlushPersist, nil) 110 111 testOpts := DefaultTestOptions().SetPersistManager(mockPersistManager) 112 db := newMockdatabase(ctrl) 113 db.EXPECT().Options().Return(testOpts).AnyTimes() 114 db.EXPECT().OwnedNamespaces().Return(nil, nil) 115 116 cfm := newColdFlushManager(db, mockPersistManager, testOpts).(*coldFlushManager) 117 cfm.pm = mockPersistManager 118 119 require.EqualError(t, fakeErr, cfm.coldFlush().Error()) 120 } 121 122 func TestColdFlushManagerSkipRun(t *testing.T) { 123 ctrl := xtest.NewController(t) 124 defer ctrl.Finish() 125 126 database := newMockdatabase(ctrl) 127 cfm := newColdFlushManager(database, nil, DefaultTestOptions()) 128 129 database.EXPECT().IsBootstrapped().Return(false) 130 require.False(t, cfm.Run(xtime.Now())) 131 } 132 133 func TestColdFlushManagerRunCleanupPanic(t *testing.T) { 134 ctrl := xtest.NewController(t) 135 defer ctrl.Finish() 136 database := newMockdatabase(ctrl) 137 database.EXPECT().IsBootstrapped().Return(true) 138 139 cm := NewMockdatabaseCleanupManager(ctrl) 140 cfm := newColdFlushManager(database, nil, DefaultTestOptions()) 141 mgr := cfm.(*coldFlushManager) 142 mgr.databaseCleanupManager = cm 143 144 ts := xtime.Now() 145 gomock.InOrder( 146 cm.EXPECT().ColdFlushCleanup(ts).Return(errors.New("cleanup error")), 147 ) 148 149 defer instrument.SetShouldPanicEnvironmentVariable(true)() 150 require.Panics(t, func() { mgr.Run(ts) }) 151 } 152 153 func TestColdFlushManagerRunFlushPanic(t *testing.T) { 154 ctrl := xtest.NewController(t) 155 defer ctrl.Finish() 156 database := newMockdatabase(ctrl) 157 database.EXPECT().IsBootstrapped().Return(true) 158 database.EXPECT().OwnedNamespaces().Return(nil, errors.New("flush error")) 159 160 cm := NewMockdatabaseCleanupManager(ctrl) 161 cfm := newColdFlushManager(database, nil, DefaultTestOptions()) 162 mgr := cfm.(*coldFlushManager) 163 mgr.databaseCleanupManager = cm 164 165 ts := xtime.Now() 166 gomock.InOrder( 167 cm.EXPECT().ColdFlushCleanup(ts).Return(nil), 168 ) 169 170 defer instrument.SetShouldPanicEnvironmentVariable(true)() 171 require.Panics(t, func() { mgr.Run(ts) }) 172 }