feat(chain): optimize merge_chains

This commit is contained in:
志宇 2024-04-17 14:06:44 +08:00
parent 77d35954c1
commit daf588f016
No known key found for this signature in database
GPG Key ID: F6345C9837C2BDE8

View File

@ -364,13 +364,17 @@ impl LocalChain {
/// ///
/// [module-level documentation]: crate::local_chain /// [module-level documentation]: crate::local_chain
pub fn apply_update(&mut self, update: CheckPoint) -> Result<ChangeSet, CannotConnectError> { pub fn apply_update(&mut self, update: CheckPoint) -> Result<ChangeSet, CannotConnectError> {
let changeset = merge_chains(self.tip.clone(), update.clone())?; let (changeset, can_replace) = merge_chains(self.tip.clone(), update.clone())?;
if can_replace {
self.tip = update;
} else {
// `._check_index_is_consistent_with_tip` and `._check_changeset_is_applied` is called in // `._check_index_is_consistent_with_tip` and `._check_changeset_is_applied` is called in
// `.apply_changeset` // `.apply_changeset`
self.apply_changeset(&changeset) self.apply_changeset(&changeset)
.map_err(|_| CannotConnectError { .map_err(|_| CannotConnectError {
try_include_height: 0, try_include_height: 0,
})?; })?;
}
Ok(changeset) Ok(changeset)
} }
@ -721,10 +725,14 @@ impl core::fmt::Display for ApplyHeaderError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for ApplyHeaderError {} impl std::error::Error for ApplyHeaderError {}
/// Applies `update_tip` onto `original_tip`.
///
/// On success, a tuple is returned `(changeset, can_replace)`. If `can_replace` is true, then the
/// `update_tip` can replace the `original_tip`.
fn merge_chains( fn merge_chains(
original_tip: CheckPoint, original_tip: CheckPoint,
update_tip: CheckPoint, update_tip: CheckPoint,
) -> Result<ChangeSet, CannotConnectError> { ) -> Result<(ChangeSet, bool), CannotConnectError> {
let mut changeset = ChangeSet::default(); let mut changeset = ChangeSet::default();
let mut orig = original_tip.into_iter(); let mut orig = original_tip.into_iter();
let mut update = update_tip.into_iter(); let mut update = update_tip.into_iter();
@ -736,6 +744,11 @@ fn merge_chains(
let mut prev_orig_was_invalidated = false; let mut prev_orig_was_invalidated = false;
let mut potentially_invalidated_heights = vec![]; let mut potentially_invalidated_heights = vec![];
// Flag to set if heights are removed from original chain. If no heights are removed, and we
// have a matching node pointer between the two chains, we can conclude that the update tip can
// just replace the original tip.
let mut has_removed_heights = false;
// To find the difference between the new chain and the original we iterate over both of them // To find the difference between the new chain and the original we iterate over both of them
// from the tip backwards in tandem. We always dealing with the highest one from either chain // from the tip backwards in tandem. We always dealing with the highest one from either chain
// first and move to the next highest. The crucial logic is applied when they have blocks at the // first and move to the next highest. The crucial logic is applied when they have blocks at the
@ -761,6 +774,8 @@ fn merge_chains(
prev_orig_was_invalidated = false; prev_orig_was_invalidated = false;
prev_orig = curr_orig.take(); prev_orig = curr_orig.take();
has_removed_heights = true;
// OPTIMIZATION: we have run out of update blocks so we don't need to continue // OPTIMIZATION: we have run out of update blocks so we don't need to continue
// iterating because there's no possibility of adding anything to changeset. // iterating because there's no possibility of adding anything to changeset.
if u.is_none() { if u.is_none() {
@ -786,7 +801,7 @@ fn merge_chains(
// OPTIMIZATION 2 -- if we have the same underlying pointer at this point, we // OPTIMIZATION 2 -- if we have the same underlying pointer at this point, we
// can guarantee that no older blocks are introduced. // can guarantee that no older blocks are introduced.
if Arc::as_ptr(&o.0) == Arc::as_ptr(&u.0) { if Arc::as_ptr(&o.0) == Arc::as_ptr(&u.0) {
return Ok(changeset); return Ok((changeset, !has_removed_heights));
} }
} else { } else {
// We have an invalidation height so we set the height to the updated hash and // We have an invalidation height so we set the height to the updated hash and
@ -820,5 +835,5 @@ fn merge_chains(
} }
} }
Ok(changeset) Ok((changeset, false))
} }