[Core] Add try_link: atomic accept-or-forward slot decision - #99
Conversation
There was a problem hiding this comment.
Pull request overview
Adds the try_link primitive to the core lookup-table abstraction to support the concurrent insert/join protocol (#85) with an atomic “accept-or-forward” decision per (level, direction) slot.
Changes:
- Introduces
LinkOutcomeand addstry_linkto theLookupTabletrait. - Implements
try_linkinArrayLookupTableusing a singleinner.write()critical section for compare+decision+conditional write. - Adds unit tests covering direct-link, overwrite, forward-without-modification, and out-of-bounds error cases.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/node/core_test.rs | Updates test mock LookupTable impl to satisfy the new trait method signature. |
| src/core/model/identity.rs | Adds Eq to support LinkOutcome: Eq derivation. |
| src/core/model/address.rs | Adds Eq to support Identity: Eq derivation. |
| src/core/mod.rs | Re-exports LinkOutcome from core. |
| src/core/lookup/mod.rs | Adds LinkOutcome and the try_link API + rustdoc. |
| src/core/lookup/array_lookup_table.rs | Implements atomic try_link under a single write lock. |
| src/core/lookup/array_lookup_table_test.rs | Adds tests for both try_link outcomes and bounds error behavior. |
Comments suppressed due to low confidence (1)
src/core/lookup/mod.rs:57
- Doc comment has a grammatical omission and inconsistent sentence casing: "
Direction::Rightthis node's own right slot" is missing "is", and the next sentence starts with lowercase "an".
/// `direction` is receiver-owned, never re-interpreted hop-to-hop: it always names this
/// node's own slot (`Direction::Right` this node's own right slot, holding neighbors with
/// larger identifiers; `Direction::Left` its own left slot), never something relative to a
/// caller or hop. an existing entry sits strictly between this node and `candidate` when,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Claude (@claude) review |
|
Claude finished TheP2P (@thep2p)'s task —— View job Review: PR #99 —
|
S T (staheri14)
left a comment
There was a problem hiding this comment.
LGTM, added a non-blocking comment.
| // existing.id() > candidate.id() — it is then closer to the candidate's true position | ||
| // than this node is, so the slot is left untouched and the decision is to forward. | ||
| let outcome = match (existing, direction) { | ||
| (Some(existing), Direction::Right) if existing.id() < candidate.id() => { |
There was a problem hiding this comment.
This accept-vs-forward decision compares only existing.id() vs candidate.id(); it can't check candidate against this node's id, because the lookup table doesn't store it. So it silently trusts the caller to pass a candidate on the correct side of this node for direction (Right ⇒ candidate.id() > self.id(), Left ⇒ <).
If a caller violates that (e.g. a candidate.id() < self.id() passed into a Right slot), this comparison is meaningless and an out-of-order neighbor is installed silently — table corruption rather than an error.
Suggest a /// precondition line on try_link, and optionally a debug_assert! at the call site (where self's id is known) so misuse fails loudly in tests instead of silently corrupting the table. Non-blocking.
There was a problem hiding this comment.
Good catch, thanks. Confirmed against docs/protocol/concurrent-insert.md §4.1/§4.3: the spec's own change_neighbor pseudocode has the same shape — it only ever compares the existing entry against the candidate, never the candidate against self. So try_link is deliberately a low-level, trusted primitive; the caller (the not-yet-written GetLinkOp/BuddyOp handler) owns the "candidate is on the correct side" guarantee.
Added a # Preconditions doc section on the trait in 731a077 spelling this out. Held off on the debug_assert! — there's no call site yet (this PR only adds the primitive, nothing wires it in), and it can't live inside try_link itself since ArrayLookupTable has no notion of its own owner's id by design. Makes sense to add the assert at the actual call site once the handler lands.
Closes #85: single-write-lock
try_link/LinkOutcomeonLookupTable+ArrayLookupTable, perdocs/protocol/concurrent-insert.md§4.