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  }