cmd/segment-reaper: Fix bitArray.IsSequence method

The bitArray.IsSequence method had a bug that caused that sometimes the
test "Bitmask/IsSequence/sequence starts at other index than 0" to fail
due to it uses random values.

The test mostly found a corner case, I've added new tests to catch the
bug and then apply the fix.

Change-Id: If01dc07006d261ba40bbd99d36ef776e09ed3efc
This commit is contained in:
Ivan Fraixedes 2020-05-11 16:02:31 +02:00 committed by Ivan Fraixedes
parent e23bd806b4
commit 50e8314279
2 changed files with 86 additions and 35 deletions

View File

@ -74,12 +74,32 @@ func (bytes *bitArray) Count() int {
// IsSequence returns true if mask has only tracked a correlative sequence of // IsSequence returns true if mask has only tracked a correlative sequence of
// indexes starting from index 0. // indexes starting from index 0.
func (bytes *bitArray) IsSequence() bool { func (bytes *bitArray) IsSequence() bool {
ones := bytes.Count() // find the last byte of the sequence that contains some one
zeros := 0 var i int
for byteIndex := len(*bytes) - 1; byteIndex >= 0 && zeros%8 == 0; byteIndex-- { for i = len(*bytes) - 1; i >= 0; i-- {
zeros = bits.LeadingZeros8((*bytes)[byteIndex]) zeros := bits.LeadingZeros8((*bytes)[i])
if zeros == 8 {
continue
}
ones := bits.OnesCount8((*bytes)[i])
if zeros+ones != 8 {
// zeros and ones in this byte aren't in sequence
return false
}
break
} }
return (zeros + ones) == len(*bytes)*8
// The rest of the bytes of the sequence must only contains ones
i--
for ; i >= 0; i-- {
if (*bytes)[i] != 255 {
return false
}
}
return true
} }
// Length returns the current size of the array in bits. // Length returns the current size of the array in bits.

View File

@ -186,36 +186,6 @@ func TestBitmask(t *testing.T) {
assert.True(t, ok) assert.True(t, ok)
}) })
t.Run("sequence started index 0", func(t *testing.T) {
var (
numIndexes = rand.Intn(61) + 2
bits bitArray
)
for i := 0; i < numIndexes; i++ {
err := bits.Set(i)
require.NoError(t, err, "Set")
}
ok := bits.IsSequence()
assert.True(t, ok)
})
t.Run("sequence started other index than 0", func(t *testing.T) {
var (
startIndex = rand.Intn(62) + 1
bits bitArray
)
for i := startIndex; i < 64; i++ {
err := bits.Set(i)
require.NoError(t, err, "Set")
}
ok := bits.IsSequence()
assert.False(t, ok)
})
t.Run("no sequence", func(t *testing.T) { t.Run("no sequence", func(t *testing.T) {
var bits bitArray var bits bitArray
@ -250,7 +220,68 @@ func TestBitmask(t *testing.T) {
assert.False(t, ok) assert.False(t, ok)
}) })
testCases := []struct {
name string
startIndex int
numIndexes int
isSequence bool
}{
{
name: "sequence starts at index 0",
startIndex: 0,
numIndexes: rand.Intn(5000) + 1,
isSequence: true,
},
{
name: "sequence starts at index 8 until index 15",
startIndex: 8,
numIndexes: 15,
isSequence: false,
},
{
name: "sequence starts at index 8 until index 16",
startIndex: 8,
numIndexes: 16,
isSequence: false,
},
{
name: "sequence starts at index 8 until index 17",
startIndex: 8,
numIndexes: 17,
isSequence: false,
},
{
name: "sequence starts at index 8 until index 23",
startIndex: 8,
numIndexes: 23,
isSequence: false,
},
{
name: "sequence starts at other index than 0",
startIndex: rand.Intn(1000) + 1,
numIndexes: rand.Intn(5000) + 1002,
isSequence: false,
},
}
for i := range testCases {
tc := testCases[i]
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
var bits bitArray
for i := tc.startIndex; i < tc.numIndexes; i++ {
err := bits.Set(i)
require.NoError(t, err, "Set")
}
require.Equalf(t, tc.isSequence, bits.IsSequence(),
"startIndex: %d, numIndexes: %d", tc.startIndex, tc.numIndexes,
)
})
}
}) })
t.Run("Unset", func(t *testing.T) { t.Run("Unset", func(t *testing.T) {
t.Run("ok", func(t *testing.T) { t.Run("ok", func(t *testing.T) {
var ( var (