Skip to content

Conversation

@bep
Copy link
Member

@bep bep commented Nov 23, 2025

The construct in #3 was added to allow setting values while walking but also allow other goroutines to walk the tree concurrently.

But that premiss was flawed, as any walk would read the leaf values, hence causing a potential data race.

This changes makes the Walk take an interface with an option al pre Check method that takes only the key, and a Handle method that takes both key and value.
This allows the caller to skip reading the value if not needed.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a potential data race in the radix tree's Walk functionality by introducing a two-phase approach that allows walking tree keys without necessarily reading their values. The key innovation is the new WalkHandler interface with separate Check and Handle methods, enabling concurrent goroutines to safely walk the tree without race conditions.

Key Changes:

  • Introduced WalkHandler interface with Check(key) and Handle(key, value) methods to separate key inspection from value access
  • Added WalkSkip flag and ShouldSkip() method to allow selective value reading
  • Made WalkFn implement the WalkHandler interface for backward compatibility
  • Refactored all Walk methods to use WalkHandler instead of WalkFn directly

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.

File Description
radix.go Core implementation: added WalkHandler interface, WalkSkip flag, and refactored Walk/WalkPrefix/WalkPath/recursiveWalk to use two-phase Check/Handle approach
radix_test.go Comprehensive test additions including Skip tests, Stop in check/handle tests, parallel walk test for data race verification, and benchmark additions for key-only walks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// WalkHandler is the handler passed to Walk functions.
// When split into two steps, this allows us to walk the
// keys withut reading the values.
Copy link

Copilot AI Nov 23, 2025

Choose a reason for hiding this comment

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

Typo in comment: "withut" should be "without"

Suggested change
// keys withut reading the values.
// keys without reading the values.
Copilot uses AI. Check for mistakes.
c.Assert(collect(r), qt.DeepEquals, []int{0, 1, 20, 3, 40, 5, 60, 7, 80, 9})
})

c.Run("Skip some ", func(c *qt.C) {
Copy link

Copilot AI Nov 23, 2025

Choose a reason for hiding this comment

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

Trailing space in test name: "Skip some " should be "Skip some" (without trailing space)

Suggested change
c.Run("Skip some ", func(c *qt.C) {
c.Run("Skip some", func(c *qt.C) {
Copilot uses AI. Check for mistakes.
The construct in armon#3 was added to allow setting values while walking but also allow other goroutines to walk the tree concurrently.

But that premiss was flawed, as any walk would read the leaf values, hence causing a potential data race.

This changes makes the Walk take an interface with an option al pre Check method that takes only the key, and a Handle method that takes both key and value.
This allows the caller to skip reading the value if not needed.
@bep bep merged commit 3819f72 into gohugoio:master Nov 23, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant