Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LowerBound to allow range scans #24

Merged
merged 4 commits into from
May 22, 2019
Merged

Add LowerBound to allow range scans #24

merged 4 commits into from
May 22, 2019

Conversation

banks
Copy link
Member

@banks banks commented May 11, 2019

This PR adds a SeekLowerBound method to Iterator which allows for range scans of the radix tree. Lower bound seeks the iterator to the first key that is greater than or equal to some search key. The iterator can then be used to iterate in order over the rest of the values. A caller can simply stop when the result is "to high" to bound the range at the upper end.

For example, assume radix trees are sorted fixed length representation of an integer such as "00001" (these might represent timestamps or some other sparse, monotonically increasing value).

// Keys 00001 00002 00005 00006
it := tree.Root().Iterator()
it.SeekLowerBound([]byte("00003")
for key, _, ok := it.Next(); ok; key, _, ok = it.Next() {
  fmt.Printf("%s", key)
}
// Output:
//   00005
//   00006

Limitations

There is no *Watch variant of this seek method because in general there is no single node that is guaranteed to be updated when the lower bound changes (other than the root). Note that even if such an algorithm could be found, it likely isn't what callers want when using this for range scans because it only tells them that the start of the range changed not about any changes in the middle or end of the range.

Callers that need to be notified of changes must arrange for that separately, for example by watching another key that is always updated when events they care about occur, or watching the root node and comparing changes to the lower bound.

Testing

This was surprisingly subtle to get right with prefix compression. An initial implementation passed a range of example-based table tests but I wasn't confident still so wrote a Fuzz test using testing/quick which caught several fundamental flaws.

This implementation now passes table tests, including some based on simplified cases caught by fuzz testing, as well as property-based fuzz testing with random keys and comparison to a simple/naive implementation with a sorted list.

iradix_test.go Outdated Show resolved Hide resolved
iradix_test.go Outdated Show resolved Hide resolved
Co-Authored-By: Hans Hasselberg <me@hans.io>
Copy link
Contributor

@kyhavlov kyhavlov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great @banks! One comment typo but the implementation/tests look solid.

iter.go Outdated Show resolved Hide resolved
Co-Authored-By: Kyle Havlovitz <kylehav@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants