github.com/m3db/m3@v1.5.0/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/golang/mock/gomock"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"github.com/m3db/m3/src/cluster/shard"
    31  	"github.com/m3db/m3/src/dbnode/namespace"
    32  	"github.com/m3db/m3/src/dbnode/persist"
    33  	"github.com/m3db/m3/src/dbnode/persist/fs"
    34  	"github.com/m3db/m3/src/dbnode/retention"
    35  	"github.com/m3db/m3/src/dbnode/sharding"
    36  	"github.com/m3db/m3/src/dbnode/storage/bootstrap/result"
    37  	"github.com/m3db/m3/src/dbnode/topology"
    38  	xcontext "github.com/m3db/m3/src/x/context"
    39  	"github.com/m3db/m3/src/x/ident"
    40  	"github.com/m3db/m3/src/x/instrument"
    41  	xtime "github.com/m3db/m3/src/x/time"
    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  
   120  			topoState, err := newInitialTopologyState(origin, topoMap)
   121  			require.NoError(t, err)
   122  
   123  			processOpts := NewProcessOptions().SetOrigin(origin)
   124  			process := bootstrapProcess{
   125  				processOpts:          processOpts,
   126  				resultOpts:           result.NewOptions(),
   127  				fsOpts:               fs.NewOptions(),
   128  				nowFn:                func() time.Time { return now.ToTime() },
   129  				log:                  instrument.NewOptions().Logger(),
   130  				bootstrapper:         bootstrapper,
   131  				initialTopologyState: topoState,
   132  			}
   133  
   134  			_, err = process.Run(ctx, startTime, processNs)
   135  			require.Equal(t, test.expectErr, err)
   136  		})
   137  	}
   138  }
   139  
   140  func TestTargetRangesFileSetTypeForSnapshotDisabledNamespace(t *testing.T) {
   141  	sut := bootstrapProcess{processOpts: NewProcessOptions()}
   142  	nsOpts := namespace.NewOptions().SetSnapshotEnabled(false)
   143  
   144  	rangesForData := sut.targetRangesForData(xtime.Now(), nsOpts)
   145  	rangesForIndex := sut.targetRangesForIndex(xtime.Now(), nsOpts)
   146  
   147  	requireFilesetTypes(t, rangesForData, persist.FileSetFlushType)
   148  	requireFilesetTypes(t, rangesForIndex, persist.FileSetFlushType)
   149  }
   150  
   151  func TestTargetRangesFileSetTypeForSnapshotEnabledNamespace(t *testing.T) {
   152  	sut := bootstrapProcess{processOpts: NewProcessOptions()}
   153  	nsOpts := namespace.NewOptions().SetSnapshotEnabled(true)
   154  
   155  	rangesForData := sut.targetRangesForData(xtime.Now(), nsOpts)
   156  	rangesForIndex := sut.targetRangesForIndex(xtime.Now(), nsOpts)
   157  
   158  	requireFilesetTypes(t, rangesForData, persist.FileSetSnapshotType)
   159  	requireFilesetTypes(t, rangesForIndex, persist.FileSetSnapshotType)
   160  }
   161  
   162  func requireFilesetTypes(t *testing.T, ranges targetRangesResult, expectedSecond persist.FileSetType) {
   163  	persistConfigFirstRange := ranges.firstRangeWithPersistTrue.RunOptions.PersistConfig()
   164  	require.True(t, persistConfigFirstRange.Enabled)
   165  	require.Equal(t, persist.FileSetFlushType, persistConfigFirstRange.FileSetType)
   166  
   167  	persistConfigSecondRange := ranges.secondRange.RunOptions.PersistConfig()
   168  	require.True(t, persistConfigSecondRange.Enabled)
   169  	require.Equal(t, expectedSecond, persistConfigSecondRange.FileSetType)
   170  }