github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/index_claims_manager_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 fs
    22  
    23  import (
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"github.com/m3db/m3/src/dbnode/namespace"
    31  	"github.com/m3db/m3/src/x/ident"
    32  	"github.com/m3db/m3/src/x/instrument"
    33  	xtime "github.com/m3db/m3/src/x/time"
    34  )
    35  
    36  func newTestIndexClaimsManager(t *testing.T, opts Options) IndexClaimsManager {
    37  	// Reset the count of index claim managers.
    38  	ResetIndexClaimsManagersUnsafe()
    39  	mgr, err := NewIndexClaimsManager(opts)
    40  	require.NoError(t, err)
    41  	return mgr
    42  }
    43  
    44  func TestIndexClaimsManagerSingleGlobalManager(t *testing.T) {
    45  	// Reset the count of index claim managers.
    46  	ResetIndexClaimsManagersUnsafe()
    47  
    48  	// First should be able to be created easily.
    49  	_, err := NewIndexClaimsManager(testDefaultOpts)
    50  	require.NoError(t, err)
    51  
    52  	// Second should cause an error.
    53  	defer instrument.SetShouldPanicEnvironmentVariable(true)()
    54  	require.Panics(t, func() { _, _ = NewIndexClaimsManager(testDefaultOpts) })
    55  }
    56  
    57  func TestIndexClaimsManagerConcurrentClaims(t *testing.T) {
    58  	mgr, ok := newTestIndexClaimsManager(t, testDefaultOpts).(*indexClaimsManager)
    59  	require.True(t, ok)
    60  
    61  	// Always return 0 for starting volume index for testing purposes.
    62  	mgr.nextIndexFileSetVolumeIndexFn = func(
    63  		filePathPrefix string,
    64  		namespace ident.ID,
    65  		blockStart xtime.UnixNano,
    66  	) (int, error) {
    67  		return 0, nil
    68  	}
    69  
    70  	md, err := namespace.NewMetadata(ident.StringID("foo"), namespace.NewOptions())
    71  	require.NoError(t, err)
    72  
    73  	var (
    74  		m          sync.Map
    75  		wg         sync.WaitGroup
    76  		blockSize  = md.Options().IndexOptions().BlockSize()
    77  		blockStart = xtime.Now().Truncate(blockSize)
    78  	)
    79  	for i := 0; i < 10; i++ {
    80  		wg.Add(1)
    81  		go func() {
    82  			defer wg.Done()
    83  			for j := 0; j < 100; j++ {
    84  				volumeIndex, err := mgr.ClaimNextIndexFileSetVolumeIndex(
    85  					md,
    86  					blockStart,
    87  				)
    88  				require.NoError(t, err)
    89  				_, loaded := m.LoadOrStore(volumeIndex, true)
    90  				// volume index should not have been previously stored or
    91  				// there are conflicting volume indices.
    92  				require.False(t, loaded)
    93  			}
    94  		}()
    95  	}
    96  	wg.Wait()
    97  }
    98  
    99  // TestIndexClaimsManagerOutOfRetention ensure that we both reject and delete out of
   100  // retention index claims.
   101  func TestIndexClaimsManagerOutOfRetention(t *testing.T) {
   102  	mgr, ok := newTestIndexClaimsManager(t, testDefaultOpts).(*indexClaimsManager)
   103  	require.True(t, ok)
   104  
   105  	// Always return 0 for starting volume index for testing purposes.
   106  	mgr.nextIndexFileSetVolumeIndexFn = func(
   107  		filePathPrefix string,
   108  		namespace ident.ID,
   109  		blockStart xtime.UnixNano,
   110  	) (int, error) {
   111  		return 0, nil
   112  	}
   113  
   114  	md, err := namespace.NewMetadata(ident.StringID("foo"), namespace.NewOptions())
   115  	blockSize := md.Options().IndexOptions().BlockSize()
   116  	blockStart := xtime.Now().Truncate(blockSize)
   117  	require.NoError(t, err)
   118  
   119  	_, err = mgr.ClaimNextIndexFileSetVolumeIndex(
   120  		md,
   121  		blockStart,
   122  	)
   123  	require.NoError(t, err)
   124  
   125  	now := mgr.nowFn().Add(md.Options().RetentionOptions().RetentionPeriod()).
   126  		Add(blockSize)
   127  	mgr.nowFn = func() time.Time { return now }
   128  	_, err = mgr.ClaimNextIndexFileSetVolumeIndex(
   129  		md,
   130  		blockStart,
   131  	)
   132  	require.Equal(t, ErrIndexOutOfRetention, err)
   133  
   134  	// Verify that the out of retention entry has been deleted as well.
   135  	_, ok = mgr.volumeIndexClaims[md.ID().String()][blockStart]
   136  	require.False(t, ok)
   137  }