feat(chain): optimize merge_chains
This commit is contained in:
parent
77d35954c1
commit
daf588f016
@ -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))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user