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 }