Skip to content

Commit

Permalink
Replace the binary search method for finding the closest snapshot (#791)
Browse files Browse the repository at this point in the history
  • Loading branch information
zivkovicmilos authored Oct 13, 2022
1 parent a72eefc commit b6d968a
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 34 deletions.
44 changes: 40 additions & 4 deletions validators/store/snapshot/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,47 @@ func (s *snapshotStore) deleteLower(num uint64) {
s.Lock()
defer s.Unlock()

i := sort.Search(len(s.list), func(i int) bool {
return s.list[i].Number >= num
})
pruneIndex := s.findClosestSnapshotIndex(num)
s.list = s.list[pruneIndex:]
}

// findClosestSnapshotIndex finds the closest snapshot index for the specified
// block number
func (s *snapshotStore) findClosestSnapshotIndex(blockNum uint64) int {
// Check if the block number is lower than the highest saved snapshot
if blockNum < s.list[0].Number {
return 0
}

// Check if the block number if higher than the highest saved snapshot
if blockNum > s.list[len(s.list)-1].Number {
return len(s.list) - 1
}

var (
low = 0
high = len(s.list) - 1
)

// Find the closest value using binary search
for low <= high {
mid := (high + low) / 2

if blockNum < s.list[mid].Number {
high = mid - 1
} else if blockNum > s.list[mid].Number {
low = mid + 1
} else {
return mid
}
}

// Check which of the two positions is closest (and has a higher block num)
if s.list[low].Number-blockNum < blockNum-s.list[high].Number {
return high
}

s.list = s.list[i:]
return low
}

// find returns the index of the first closest snapshot to the number specified
Expand Down
99 changes: 69 additions & 30 deletions validators/store/snapshot/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1096,41 +1096,80 @@ func Test_snapshotStore_updateLastBlock(t *testing.T) {
func Test_snapshotStore_deleteLower(t *testing.T) {
t.Parallel()

var (
metadata = &SnapshotMetadata{
LastBlock: 10,
}
metadata := &SnapshotMetadata{
LastBlock: 10,
}

snapshots = []*Snapshot{
{Number: 10},
{Number: 19},
{Number: 20},
{Number: 21},
{Number: 30},
}
testTable := []struct {
name string
snapshots []*Snapshot
boundary uint64
expectedSnapshots []*Snapshot
}{
{
"Drop lower-number snapshots",
[]*Snapshot{
{Number: 10},
{Number: 19},
{Number: 25},
{Number: 30},
},
uint64(20),
[]*Snapshot{
{Number: 25},
{Number: 30},
},
},
{
"Higher block value",
[]*Snapshot{
{Number: 10},
{Number: 11},
{Number: 12},
{Number: 13},
{Number: 14},
},
uint64(15),
[]*Snapshot{
{Number: 14},
},
},
{
// Single snapshots shouldn't be dropped
"Single snapshot",
[]*Snapshot{
{Number: 10},
},
uint64(15),
[]*Snapshot{
{Number: 10},
},
},
}

boundary = uint64(20)
)
for _, testCase := range testTable {
testCase := testCase

store := newSnapshotStore(
metadata,
snapshots,
)
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()

store.deleteLower(boundary)
store := newSnapshotStore(
metadata,
testCase.snapshots,
)

assert.Equal(
t,
&snapshotStore{
lastNumber: metadata.LastBlock,
list: []*Snapshot{
{Number: 20},
{Number: 21},
{Number: 30},
},
},
store,
)
store.deleteLower(testCase.boundary)

assert.Equal(
t,
&snapshotStore{
lastNumber: metadata.LastBlock,
list: testCase.expectedSnapshots,
},
store,
)
})
}
}

func Test_snapshotStore_find(t *testing.T) {
Expand Down

0 comments on commit b6d968a

Please sign in to comment.