github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/bootstrap/process_test.go (about)

     1  // Copyright (c) 2021 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 bootstrap
    22  
    23  import (
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/cluster/shard"
    28  	"github.com/m3db/m3/src/dbnode/namespace"
    29  	"github.com/m3db/m3/src/dbnode/persist"
    30  	"github.com/m3db/m3/src/dbnode/persist/fs"
    31  	"github.com/m3db/m3/src/dbnode/retention"
    32  	"github.com/m3db/m3/src/dbnode/sharding"
    33  	"github.com/m3db/m3/src/dbnode/storage/bootstrap/result"
    34  	"github.com/m3db/m3/src/dbnode/topology"
    35  	xcontext "github.com/m3db/m3/src/x/context"
    36  	"github.com/m3db/m3/src/x/ident"
    37  	"github.com/m3db/m3/src/x/instrument"
    38  	xtime "github.com/m3db/m3/src/x/time"
    39  
    40  	"github.com/golang/mock/gomock"
    41  	"github.com/stretchr/testify/require"
    42  )
    43  
    44  func TestBootstrapProcessRunActiveBlockAdvanced(t *testing.T) {
    45  	tests := []struct {
    46  		name               string
    47  		shardsInitializing bool
    48  		expectErr          error
    49  	}{
    50  		{
    51  			name:               "time shifted and shards initializing, should return error",
    52  			shardsInitializing: true,
    53  			expectErr:          ErrFileSetSnapshotTypeRangeAdvanced,
    54  		},
    55  		{
    56  			name:               "time shifted and shards all available, should not return error",
    57  			shardsInitializing: false,
    58  		},
    59  	}
    60  
    61  	for _, test := range tests {
    62  		t.Run(test.name, func(t *testing.T) {
    63  			ctrl := gomock.NewController(t)
    64  			defer ctrl.Finish()
    65  
    66  			var (
    67  				ctx          = xcontext.NewBackground()
    68  				blockSize    = time.Hour
    69  				startTime    = xtime.Now().Truncate(blockSize)
    70  				bufferPast   = 30 * time.Minute
    71  				bufferFuture = 30 * time.Minute
    72  				// shift 'now' just enough so that after adding 'bufferFuture' it would reach the next block
    73  				now           = startTime.Add(blockSize - bufferFuture)
    74  				shards        = []uint32{0}
    75  				retentionOpts = retention.NewOptions().
    76  						SetBlockSize(blockSize).
    77  						SetRetentionPeriod(12 * blockSize).
    78  						SetBufferPast(bufferPast).
    79  						SetBufferFuture(bufferFuture)
    80  				nsOptions = namespace.NewOptions().SetRetentionOptions(retentionOpts)
    81  				nsID      = ident.StringID("ns")
    82  				ns, err   = namespace.NewMetadata(nsID, nsOptions)
    83  			)
    84  			require.NoError(t, err)
    85  
    86  			processNs := []ProcessNamespace{
    87  				{
    88  					Metadata:        ns,
    89  					Shards:          shards,
    90  					DataAccumulator: NewMockNamespaceDataAccumulator(ctrl),
    91  				},
    92  			}
    93  
    94  			bootstrapper := NewMockBootstrapper(ctrl)
    95  			bootstrapper.EXPECT().String().Return("mock_bootstrapper").AnyTimes()
    96  			bootstrapper.EXPECT().
    97  				Bootstrap(gomock.Any(), gomock.Any(), gomock.Any()).
    98  				DoAndReturn(func(_, _, _ interface{}) (NamespaceResults, error) {
    99  					return NewNamespaceResults(NewNamespaces(processNs)), nil
   100  				}).
   101  				AnyTimes()
   102  
   103  			shardState := shard.Available
   104  			if test.shardsInitializing {
   105  				shardState = shard.Initializing
   106  			}
   107  			shardSet, err := sharding.NewShardSet(sharding.NewShards(shards, shardState),
   108  				sharding.DefaultHashFn(len(shards)))
   109  			require.NoError(t, err)
   110  
   111  			origin := topology.NewHost("self", "127.0.0.1:9000")
   112  			hostShardSet := topology.NewHostShardSet(origin, shardSet)
   113  
   114  			topoMapOpts := topology.NewStaticOptions().
   115  				SetReplicas(1).
   116  				SetShardSet(shardSet).
   117  				SetHostShardSets([]topology.HostShardSet{hostShardSet})
   118  			topoMap := topology.NewStaticMap(topoMapOpts)
   119  			topoState, err := newInitialTopologyState(origin, topoMap)
   120  			require.NoError(t, err)
   121  
   122  			processOpts := NewProcessOptions().SetOrigin(origin)
   123  			process := bootstrapProcess{
   124  				processOpts:          processOpts,
   125  				resultOpts:           result.NewOptions(),
   126  				fsOpts:               fs.NewOptions(),
   127  				nowFn:                func() time.Time { return now.ToTime() },
   128  				log:                  instrument.NewOptions().Logger(),
   129  				bootstrapper:         bootstrapper,
   130  				initialTopologyState: topoState,
   131  			}
   132  
   133  			_, err = process.Run(ctx, startTime, processNs)
   134  			require.Equal(t, test.expectErr, err)
   135  		})
   136  	}
   137  }
   138  
   139  func TestTargetRangesFileSetTypeForSnapshotDisabledNamespace(t *testing.T) {
   140  	sut := bootstrapProcess{processOpts: NewProcessOptions()}
   141  	nsOpts := namespace.NewOptions().SetSnapshotEnabled(false)
   142  
   143  	rangesForData := sut.targetRangesForData(xtime.Now(), nsOpts)
   144  	rangesForIndex := sut.targetRangesForIndex(xtime.Now(), nsOpts)
   145  
   146  	requireFilesetTypes(t, rangesForData, persist.FileSetFlushType)
   147  	requireFilesetTypes(t, rangesForIndex, persist.FileSetFlushType)
   148  }
   149  
   150  func TestTargetRangesFileSetTypeForSnapshotEnabledNamespace(t *testing.T) {
   151  	sut := bootstrapProcess{processOpts: NewProcessOptions()}
   152  	nsOpts := namespace.NewOptions().SetSnapshotEnabled(true)
   153  
   154  	rangesForData := sut.targetRangesForData(xtime.Now(), nsOpts)
   155  	rangesForIndex := sut.targetRangesForIndex(xtime.Now(), nsOpts)
   156  
   157  	requireFilesetTypes(t, rangesForData, persist.FileSetSnapshotType)
   158  	requireFilesetTypes(t, rangesForIndex, persist.FileSetSnapshotType)
   159  }
   160  
   161  func requireFilesetTypes(t *testing.T, ranges targetRangesResult, expectedSecond persist.FileSetType) {
   162  	persistConfigFirstRange := ranges.firstRangeWithPersistTrue.RunOptions.PersistConfig()
   163  	require.True(t, persistConfigFirstRange.Enabled)
   164  	require.Equal(t, persist.FileSetFlushType, persistConfigFirstRange.FileSetType)
   165  
   166  	persistConfigSecondRange := ranges.secondRange.RunOptions.PersistConfig()
   167  	require.True(t, persistConfigSecondRange.Enabled)
   168  	require.Equal(t, expectedSecond, persistConfigSecondRange.FileSetType)
   169  }