Context
search_by_mem_vec is the algorithm that, given a target MembershipVector, finds the node in the skip graph whose membership vector has the longest common prefix with the target. It is a prerequisite for BaseNode::join (#66), which uses it at each level to find prefix-matching neighbors.
The stub exists at src/node/core.rs:165 as todo!().
Algorithm
The search works level by level, starting from the highest level down to 0. At each level, the current node checks whether either neighbor has a longer common-prefix match with the target than itself. If so, it forwards the search to that neighbor. If neither neighbor improves the match, it drops to the level below. If it reaches level 0 with no improvement, it returns itself as the best match.
Pseudocode in codebase terms:
// Executed at node v upon receiving (origin_id, target_mv, level):
let my_match = common_prefix_length(v.mem_vec, target_mv)
if my_match == MV_BITS:
// exact match: this node is the target
return MemVecSearchRes { result: v.id, match_len: my_match }
while level >= 0:
right = v.lt.get_entry(level, Direction::Right)
left = v.lt.get_entry(level, Direction::Left)
if right.is_some() && common_prefix_length(right.mem_vec, target_mv) > my_match:
forward (origin_id, target_mv, level) to right
return
if left.is_some() && common_prefix_length(left.mem_vec, target_mv) > my_match:
forward (origin_id, target_mv, level) to left
return
level -= 1
// No better neighbor found at any level: self is the best match
return MemVecSearchRes { result: v.id, match_len: my_match }
Current signature problem
The existing stub reuses IdSearchReq / IdSearchRes:
fn search_by_mem_vec(&self, _req: &IdSearchReq) -> anyhow::Result<IdSearchRes>;
This is wrong. IdSearchReq carries target: Identifier (a numerical ID) and a single Direction. The membership vector search needs:
target: MembershipVector (not an Identifier)
- no fixed direction — both neighbors are checked at each level
start_level: LookupTableLevel
New request/response types are required (e.g. MemVecSearchReq / MemVecSearchRes), along with new Event variants (SearchByMemVecRequest / SearchByMemVecResponse).
Work breakdown
common_prefix_length — add a method to MembershipVector that returns the number of leading bits two membership vectors share.
MemVecSearchReq / MemVecSearchRes — new model types in src/core/model/search.rs carrying target: MembershipVector and start_level: LookupTableLevel.
Event variants — add SearchByMemVecRequest(MemVecSearchReq) and SearchByMemVecResponse(MemVecSearchRes) to src/network/mod.rs.
Core::search_by_mem_vec — fix the signature in src/node/core.rs and implement the algorithm in BaseCore.
BaseNode routing — handle the two new event variants in process_incoming_event.
- Tests — unit tests for
common_prefix_length; integration tests for single-hop and multi-hop membership vector search over MockNetwork.
Relationship to other issues
Context
search_by_mem_vecis the algorithm that, given a targetMembershipVector, finds the node in the skip graph whose membership vector has the longest common prefix with the target. It is a prerequisite forBaseNode::join(#66), which uses it at each level to find prefix-matching neighbors.The stub exists at
src/node/core.rs:165astodo!().Algorithm
The search works level by level, starting from the highest level down to 0. At each level, the current node checks whether either neighbor has a longer common-prefix match with the target than itself. If so, it forwards the search to that neighbor. If neither neighbor improves the match, it drops to the level below. If it reaches level 0 with no improvement, it returns itself as the best match.
Pseudocode in codebase terms:
Current signature problem
The existing stub reuses
IdSearchReq/IdSearchRes:This is wrong.
IdSearchReqcarriestarget: Identifier(a numerical ID) and a singleDirection. The membership vector search needs:target: MembershipVector(not anIdentifier)start_level: LookupTableLevelNew request/response types are required (e.g.
MemVecSearchReq/MemVecSearchRes), along with newEventvariants (SearchByMemVecRequest/SearchByMemVecResponse).Work breakdown
common_prefix_length— add a method toMembershipVectorthat returns the number of leading bits two membership vectors share.MemVecSearchReq/MemVecSearchRes— new model types insrc/core/model/search.rscarryingtarget: MembershipVectorandstart_level: LookupTableLevel.Eventvariants — addSearchByMemVecRequest(MemVecSearchReq)andSearchByMemVecResponse(MemVecSearchRes)tosrc/network/mod.rs.Core::search_by_mem_vec— fix the signature insrc/node/core.rsand implement the algorithm inBaseCore.BaseNoderouting — handle the two new event variants inprocess_incoming_event.common_prefix_length; integration tests for single-hop and multi-hop membership vector search overMockNetwork.Relationship to other issues
BaseNode::join).search_by_idpattern established in PRs feat: end-to-end distributed search_by_id over mock network #68 and feat: concurrent originator searches via per-request waiter map #69.