github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/storage/bootstrap/result/shard_ranges_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 result 22 23 import ( 24 "testing" 25 "time" 26 27 xtime "github.com/m3db/m3/src/x/time" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestShardTimeRangesAdd(t *testing.T) { 34 start := xtime.Now().Truncate(testBlockSize) 35 times := []xtime.UnixNano{ 36 start, start.Add(testBlockSize), 37 start.Add(2 * testBlockSize), start.Add(3 * testBlockSize), 38 } 39 40 sr := []ShardTimeRanges{ 41 NewShardTimeRangesFromRange(times[0], times[1], 1, 2, 3), 42 NewShardTimeRangesFromRange(times[1], times[2], 1, 2, 3), 43 NewShardTimeRangesFromRange(times[2], times[3], 1, 2, 3), 44 } 45 ranges := NewShardTimeRanges() 46 for _, r := range sr { 47 ranges.AddRanges(r) 48 } 49 for i, r := range sr { 50 min, max, r := r.MinMaxRange() 51 require.Equal(t, r, testBlockSize) 52 require.Equal(t, min, times[i]) 53 require.Equal(t, max, times[i+1]) 54 } 55 } 56 57 func TestFilterShards(t *testing.T) { 58 start := xtime.Now().Truncate(testBlockSize) 59 end := start.Add(testBlockSize) 60 ranges := NewShardTimeRangesFromRange(start, end, 0, 1, 2) 61 62 tests := []struct { 63 name string 64 filter []uint32 65 result []uint32 66 }{ 67 { 68 name: "empty filter", 69 filter: []uint32{}, 70 result: []uint32{}, 71 }, 72 { 73 name: "all exist", 74 filter: []uint32{0, 1, 2}, 75 result: []uint32{0, 1, 2}, 76 }, 77 { 78 name: "none exists", 79 filter: []uint32{10, 11, 12}, 80 result: []uint32{}, 81 }, 82 { 83 name: "some exist", 84 filter: []uint32{0, 1, 10, 11}, 85 result: []uint32{0, 1}, 86 }, 87 { 88 name: "some filtered out", 89 filter: []uint32{0, 1}, 90 result: []uint32{0, 1}, 91 }, 92 } 93 94 for _, tt := range tests { 95 t.Run(tt.name, func(t *testing.T) { 96 filtered := ranges.FilterShards(tt.filter) 97 require.Equal(t, filtered.Len(), len(tt.result), "unexpected length") 98 for _, s := range tt.result { 99 _, ok := filtered.Get(s) 100 assert.True(t, ok, "missing shard %v", s) 101 } 102 }) 103 } 104 } 105 106 func TestShardTimeRangesIsSuperset(t *testing.T) { 107 start := xtime.Now().Truncate(testBlockSize) 108 109 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 2, 3}) 110 ranges2 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 2}) 111 ranges3 := createShardTimeRanges(start, testBlockSize, 1, []uint32{1, 2, 3}) 112 113 require.True(t, ranges1.IsSuperset(ranges2)) 114 require.True(t, ranges1.IsSuperset(ranges1)) 115 require.True(t, ranges1.IsSuperset(ranges3)) 116 117 // Subset of shards fails superset condition. 118 require.False(t, ranges2.IsSuperset(ranges1)) 119 // Subset of time ranges fails superset condition. 120 require.False(t, ranges3.IsSuperset(ranges1)) 121 } 122 123 func TestShardTimeRangesIsSupersetNoOverlapShards(t *testing.T) { 124 start := xtime.Now().Truncate(testBlockSize) 125 126 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 3, 5}) 127 ranges2 := createShardTimeRanges(start, testBlockSize, 3, []uint32{2, 4, 6}) 128 129 // Neither are supersets of each other as they have non overlapping shards. 130 require.False(t, ranges1.IsSuperset(ranges2)) 131 require.False(t, ranges2.IsSuperset(ranges1)) 132 } 133 134 func TestShardTimeRangesIsSupersetPartialOverlapShards(t *testing.T) { 135 start := xtime.Now().Truncate(testBlockSize) 136 137 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 3, 5}) 138 ranges2 := createShardTimeRanges(start, testBlockSize, 3, []uint32{3, 4, 6}) 139 140 // Neither are supersets of each other as they only have partially overlapping shards. 141 require.False(t, ranges1.IsSuperset(ranges2)) 142 require.False(t, ranges2.IsSuperset(ranges1)) 143 } 144 145 func TestShardTimeRangesIsSupersetNoOverlapTimeRanges(t *testing.T) { 146 start := xtime.Now().Truncate(testBlockSize) 147 148 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 3, 5}) 149 ranges2 := createShardTimeRanges(start.Add(testBlockSize*3), testBlockSize, 3, 150 []uint32{1, 3, 5}) 151 152 // Neither are supersets of each other as they have non overlapping time ranges. 153 require.False(t, ranges1.IsSuperset(ranges2)) 154 require.False(t, ranges2.IsSuperset(ranges1)) 155 } 156 157 func TestShardTimeRangesIsSupersetPartialOverlapTimeRanges(t *testing.T) { 158 start := xtime.Now().Truncate(testBlockSize) 159 160 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 3, 5}) 161 ranges2 := createShardTimeRanges(start.Add(testBlockSize*2), testBlockSize, 3, 162 []uint32{1, 3, 5}) 163 164 // Neither are supersets of each other as they have non overlapping time ranges. 165 require.False(t, ranges1.IsSuperset(ranges2)) 166 require.False(t, ranges2.IsSuperset(ranges1)) 167 } 168 169 func TestShardTimeRangesIsSupersetEmpty(t *testing.T) { 170 start := xtime.Now().Truncate(testBlockSize) 171 172 ranges1 := createShardTimeRanges(start, testBlockSize, 3, []uint32{1, 3, 5}) 173 ranges2 := NewShardTimeRanges() 174 175 require.True(t, ranges1.IsSuperset(ranges2)) 176 require.False(t, ranges2.IsSuperset(ranges1)) 177 require.True(t, ranges2.IsSuperset(ranges2)) 178 } 179 180 func createShardTimeRanges( 181 start xtime.UnixNano, 182 blockSize time.Duration, 183 numBlocks int, 184 shards []uint32, 185 ) ShardTimeRanges { 186 ranges := NewShardTimeRanges() 187 for i := 0; i < numBlocks; i++ { 188 blockStart := start.Add(time.Duration(i) * blockSize) 189 ranges.AddRanges(NewShardTimeRangesFromRange( 190 blockStart, 191 blockStart.Add(blockSize), 192 shards..., 193 )) 194 } 195 return ranges 196 }