-
Notifications
You must be signed in to change notification settings - Fork 3
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
[Sumtree]: Rebalancing #81
Conversation
@@ -232,6 +232,15 @@ impl TreeNode { | |||
} | |||
} | |||
|
|||
/// Synchronizes the range and value of the current node and recursively updates its ancestors. | |||
pub fn sync_range_and_value_up(&mut self, storage: &mut dyn Storage) -> ContractResult<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% on the naming of this function but couldn't think of anything better.
It may also be unncessary if we don't use the delete
method.
} | ||
|
||
#[test] | ||
fn test_node_insert_large_quantity() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we see any value in keeping this test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably good to keep around so we can add prefix sum based assertions to it later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, great work! Glad we finally landed on something that works :)
@@ -446,7 +510,8 @@ impl TreeNode { | |||
parent.delete(storage)?; | |||
} else { | |||
// Update parents values after removing node | |||
parent.sync_range_and_value(storage)?; | |||
// TODO: Adjust for call time changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm what does this mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had changed the sync_range_and_value
method to not iterate up the tree after syncing but this method hadn't been adjusted for that. I wrote a new method called sync_range_and_value_up
that iterates up the tree and forgot to remove the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the comment now
@@ -507,6 +783,19 @@ impl TreeNode { | |||
} | |||
Ok(result) | |||
} | |||
|
|||
#[cfg(test)] | |||
pub fn count_ancestral_leaves(&self, storage: &dyn Storage) -> u64 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this function still necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't see much use for it, I'll strip it out. Easy to readd if we ever need it.
} | ||
|
||
#[test] | ||
fn test_node_insert_large_quantity() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably good to keep around so we can add prefix sum based assertions to it later
Co-authored-by: Alpo <62043214+AlpinYukseloglu@users.noreply.github.com>
Closes: #60
What is the purpose of the change
This PR is to add rebalancing logic to the cancelled order sumtree. Previously a tree could be attacked by constant insertion on one side of a tree, leading to a search runtime that trends to$O(N)$ . The solution to this is to enforce post insertion rebalancing up the tree to keep it as balanced as possible.
To facilitate the rebalancing of the sumtree internal nodes must store their weight, this was added under the
NodeType::Internal
struct as only internal nodes need to track this data. A node's weight is determined by the depth of the node, i.e. leaf nodes have a weight of 1, their parents 2, etc. If an internal node's children have differing weights the larger of the two is taken.Note: A leaf is given a weight of 1 when called from
get_weight
To implement rebalancing a
rebalance
method was added to nodes, this method errors if the node is not internal or the node has no children. The exact balancing mechanism was taken from a standard AVL tree as described in #60. To facilitate balancing two rotation methods were added;rotate_right
androtate_left
. These methods are called on the root of the subtree that is to be rotated, this then validates the correctness fo the node to be rotated in to its place before correctly reassigning the relationships between the nodes.For each case in the AVL rebalancing algorithm there is an
if
statement, and for theLeftRight/RightLeft
cases the current node (self
) is resynced post child rotation usingself.sync
here:Post rotation nodes have their values and ranges updated appropriate and nodes are balanced/synced as the recursive
insert
method unfolds.Upon rotation if a node has no parent it is assumed to be the new root and assigned as such.
Testing and Verifying
Testing covers three main methods without using any insertion logic:
All tests are contained in
test_node.rs
and can be run with: