0

I am new to Rust here. I am trying to build a concurrent btree and I'm struggling with implementing algorithms on the tree.

In this example, I used a simplified version of my tree where the LatchNode's type is Arc<RwLock<Node>>. I would like to implement a method called find_child which not only finds the node with matching key in the tree, I also want a stack of RwLockWriteGuard for all the parent nodes on the way to the child. This way, we are confident that another concurrent operation won't mess up the search result.

pub struct Node {
    k: i32,
    children: Vec<Option<LatchNode>>,
}

type LatchNode = Arc<RwLock<Node>>;

pub fn find_child<'a>(
    root: LatchNode,
    k: i32,
) -> (RwLockWriteGuard<'a, Node>, Vec<RwLockWriteGuard<'a, Node>>) {
    let guard = root.clone().write().unwrap();

    let mut stack = Vec::new();
    stack.push(guard);

    loop {
        let temp = stack.last().unwrap();
        // for simplicity, we travese down first node in children
        let child = temp.children[0].clone();
        match child {
            Some(ref child_node) => {
                let child_guard = child_node.write().unwrap();
                if child_guard.k == k {
                    return (child_guard, stack);
                }
                stack.push(child_guard)
            }
            None => {
                panic!("No node found");
            }
        }
    }
}

However, I am getting the error

cannot return value referencing local data `child.0`
returns a value referencing data owned by the current function
`child.0` is borrowed here -> refers to the line : Some(ref child_node) => {

Looking at the code, it seems like Rust compiler thinks child_node is a temporary variable. But I am confident that RwLock that Arc points to will exist even at the end of the function. How might I be able to fix this method?

Brian Shih
  • 301
  • 1
  • 8
  • Sorry it doesn't answer my question. Here the `guard` references an `Arc` instance that compiler thinks will be out of scope. Also, I am looking for a solution to what I'm trying to fix, not just an explanation. – Brian Shih Feb 13 '23 at 01:51
  • 1
    It doesn't work for the same reasons though. The guard at `stack[n]` references the Arc from `stack[n-1]`, which is self referential. – Colonel Thirty Two Feb 13 '23 at 01:55
  • Ahh I see what you mean, that's a good point! In that case I think a recursive approach may be what I want to simulate a stack but not store them in the same stucture – Brian Shih Feb 13 '23 at 01:59
  • Recursion is the way to go. And you're much better off just cloning the `Arc`'ed node and returning that than trying to keep all the locks alive so you can return a reference. – Colonel Thirty Two Feb 13 '23 at 02:02
  • dumb question but if I return a cloned `Arc` instead of the `lock` wouldn't a concurrent operation be able to modify the node I have returned since the `lock` is out of scope and released? – Brian Shih Feb 13 '23 at 02:06
  • 1
    Yes, the lock will be released when the guards are dropped when the function returns. If that's an issue, an alternative is to pass in a `FnOnce` that does the operation on the node while the locks are held. – Colonel Thirty Two Feb 13 '23 at 14:26

0 Answers0