Skip to content

Commit

Permalink
Correctly seek in raft's ListPage when after=.
Browse files Browse the repository at this point in the history
When a non-empty path is given that ends in a slash and after=., the
resulting seek prefix from joining the path and the period has the
slash trimmed off. This results in no list results, because this seek
prefix lacks the trailing slash and is thus not prefixed by the expected
prefix. E.g., for foo/ and after=., we end up with seekPrefix=foo, which
doesn't start with our prefix (foo/).

Correctly handle this edge case. This was caught by randomized testing
across multiple storage backends.

Signed-off-by: Alexander Scheel <[email protected]>
  • Loading branch information
cipherboy authored and naphelps committed May 10, 2024
1 parent 154c647 commit eea3d80
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 0 deletions.
3 changes: 3 additions & 0 deletions changelog/294.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
physical/raft: fix ListPage calls when after=. resulting in an empty list
```
6 changes: 6 additions & 0 deletions physical/raft/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,12 @@ func (f *FSM) ListPage(ctx context.Context, prefix string, after string, limit i
seekPrefix := []byte(filepath.Join(prefix, after))
if after == "" {
seekPrefix = prefixBytes
} else if !bytes.HasPrefix(seekPrefix, prefixBytes) {
// filepath.Join has the very unfortunate behavior of trimming the
// trailing slash when after=".". When e.g., prefix=foo/, this gives
// us seekPrefix=foo, which fails the initial HasPrefix check,
// skipping all results.
seekPrefix = prefixBytes
}

var keys []string
Expand Down
4 changes: 4 additions & 0 deletions sdk/physical/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func testListAndPage(t testing.TB, b Backend, prefix string, expected []string)
require.NoError(t, err, "initial list page failed")
sortaEqualSlice(t, expected, page, "expected list page to match")

page, err = b.ListPage(context.Background(), prefix, ".", -100)
require.NoError(t, err, "initial list page failed")
sortaEqualSlice(t, expected, page, "expected list page with after=. to match bare list")

page, err = b.ListPage(context.Background(), prefix, "", -1)
require.NoError(t, err, "initial list page failed")
sortaEqualSlice(t, expected, page, "expected list page to match")
Expand Down

0 comments on commit eea3d80

Please sign in to comment.