Skip to content

Commit 4d0ebae

Browse files
committed
smt Inner: drop the actural tree asynchronously
Provides concurrency even if the SMTs are dropped generation by generation by creation order -- originally that will mean no concurrency at all because each drop only unlocks its only child for drop next.
1 parent 5049a5e commit 4d0ebae

File tree

3 files changed

+29
-15
lines changed

3 files changed

+29
-15
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright © Aptos Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
#![forbid(unsafe_code)]
5+
6+
use aptos_drop_helper::async_concurrent_dropper::AsyncConcurrentDropper;
7+
use once_cell::sync::Lazy;
8+
9+
pub(crate) static SUBTREE_DROPPER: Lazy<AsyncConcurrentDropper> =
10+
Lazy::new(|| AsyncConcurrentDropper::new("smt_subtree", 32, 8));

storage/scratchpad/src/sparse_merkle/mod.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,18 @@
7171
#![allow(clippy::while_let_loop)]
7272

7373
pub mod ancestors;
74+
mod dropper;
7475
mod metrics;
7576
mod node;
76-
mod updater;
77-
pub mod utils;
78-
7977
#[cfg(test)]
8078
mod sparse_merkle_test;
8179
#[cfg(any(test, feature = "bench", feature = "fuzzing"))]
8280
pub mod test_utils;
81+
mod updater;
82+
pub mod utils;
8383

8484
use crate::sparse_merkle::{
85+
dropper::SUBTREE_DROPPER,
8586
metrics::{GENERATION, TIMER},
8687
node::{NodeInner, SubTree},
8788
updater::SubTreeUpdater,
@@ -187,7 +188,7 @@ impl<V: Send + Sync + 'static> InnerLinks<V> {
187188
/// INNER of it can still live if referenced by a previous version.
188189
#[derive(Debug)]
189190
struct Inner<V: Send + Sync + 'static> {
190-
root: SubTree<V>,
191+
root: Option<SubTree<V>>,
191192
usage: StateStorageUsage,
192193
links: Mutex<InnerLinks<V>>,
193194
family: HashValue,
@@ -197,6 +198,9 @@ struct Inner<V: Send + Sync + 'static> {
197198

198199
impl<V: Send + Sync + 'static> Drop for Inner<V> {
199200
fn drop(&mut self) {
201+
// Drop the root in a different thread, because that's the slowest part.
202+
SUBTREE_DROPPER.schedule_drop(self.root.take());
203+
200204
// To prevent recursively locking the family, buffer all descendants outside.
201205
let mut processed_descendants = Vec::new();
202206

@@ -228,12 +232,7 @@ impl<V: Send + Sync + 'static> Drop for Inner<V> {
228232
};
229233
// Now that the lock is released, those in `processed_descendants` can be dropped if
230234
// applicable.
231-
//
232-
// Send the Arc to multiple threads so that the dropping happens in parallel (specifically,
233-
// dropping of the SMTs).
234-
for descendant_arc in processed_descendants {
235-
aptos_drop_helper::DEFAULT_DROPPER.schedule_drop(descendant_arc)
236-
}
235+
drop(processed_descendants);
237236

238237
self.log_generation("drop");
239238
}
@@ -245,7 +244,7 @@ impl<V: Send + Sync + 'static> Inner<V> {
245244
let family_lock = Arc::new(Mutex::new(()));
246245
let branch_tracker = BranchTracker::new_head_unknown(None, &family_lock.lock());
247246
let me = Arc::new(Self {
248-
root,
247+
root: Some(root),
249248
usage,
250249
links: InnerLinks::new(branch_tracker.clone()),
251250
family,
@@ -257,6 +256,11 @@ impl<V: Send + Sync + 'static> Inner<V> {
257256
me
258257
}
259258

259+
fn root(&self) -> &SubTree<V> {
260+
// root only goes away during Drop
261+
self.root.as_ref().expect("Root must exist.")
262+
}
263+
260264
fn become_oldest(self: Arc<Self>, locked_family: &MutexGuard<()>) -> Arc<Self> {
261265
{
262266
let links_locked = self.links.lock();
@@ -278,7 +282,7 @@ impl<V: Send + Sync + 'static> Inner<V> {
278282
family_lock: Arc<Mutex<()>>,
279283
) -> Arc<Self> {
280284
Arc::new(Self {
281-
root: child_root,
285+
root: Some(child_root),
282286
usage: child_usage,
283287
links: InnerLinks::new(branch_tracker),
284288
family: self.family,
@@ -443,12 +447,12 @@ where
443447
}
444448

445449
fn root_weak(&self) -> SubTree<V> {
446-
self.inner.root.weak()
450+
self.inner.root().weak()
447451
}
448452

449453
/// Returns the root hash of this tree.
450454
pub fn root_hash(&self) -> HashValue {
451-
self.inner.root.hash()
455+
self.inner.root().hash()
452456
}
453457

454458
fn generation(&self) -> u64 {

storage/scratchpad/src/sparse_merkle/test_utils/proptest_helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ trait AssertNoExternalStrongRef {
130130

131131
impl<V: Send + Sync + 'static> AssertNoExternalStrongRef for SparseMerkleTree<V> {
132132
fn assert_no_external_strong_ref(&self) {
133-
assert_subtree_sole_strong_ref(&self.inner.root);
133+
assert_subtree_sole_strong_ref(self.inner.root());
134134
}
135135
}
136136

0 commit comments

Comments
 (0)