Skip to content

Commit aee48f3

Browse files
authored
Merge pull request #6079 from kantai/perf/2.0-syncing
Perf: 2.0 syncing speedup
2 parents e10f11c + 9434e29 commit aee48f3

File tree

4 files changed

+89
-36
lines changed

4 files changed

+89
-36
lines changed

stackslib/src/chainstate/burn/db/sortdb.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,13 +1264,25 @@ impl<'a> SortitionHandleTx<'a> {
12641264
burn_header_hash: &BurnchainHeaderHash,
12651265
chain_tip: &SortitionId,
12661266
) -> Result<Option<BlockSnapshot>, db_error> {
1267+
let Some(sortition_id) = self.get_sortition_id_for_bhh(burn_header_hash, chain_tip)? else {
1268+
return Ok(None);
1269+
};
1270+
1271+
SortitionDB::get_block_snapshot(self.tx(), &sortition_id)
1272+
}
1273+
1274+
fn get_sortition_id_for_bhh(
1275+
&mut self,
1276+
burn_header_hash: &BurnchainHeaderHash,
1277+
chain_tip: &SortitionId,
1278+
) -> Result<Option<SortitionId>, db_error> {
12671279
let sortition_identifier_key = db_keys::sortition_id_for_bhh(burn_header_hash);
12681280
let sortition_id = match self.get_indexed(chain_tip, &sortition_identifier_key)? {
12691281
None => return Ok(None),
12701282
Some(x) => SortitionId::from_hex(&x).expect("FATAL: bad Sortition ID stored in DB"),
12711283
};
12721284

1273-
SortitionDB::get_block_snapshot(self.tx(), &sortition_id)
1285+
Ok(Some(sortition_id))
12741286
}
12751287

12761288
/// Get a leader key at a specific location in the burn chain's fork history, given the
@@ -6528,25 +6540,25 @@ impl SortitionHandleTx<'_> {
65286540
}
65296541

65306542
// must be an ancestor of this tip, or must be this tip
6531-
if let Some(sn) =
6532-
self.get_block_snapshot(&arrival_sn.burn_header_hash, &parent_tip.sortition_id)?
6543+
if let Some(sortition_id) = self
6544+
.get_sortition_id_for_bhh(&arrival_sn.burn_header_hash, &parent_tip.sortition_id)?
65336545
{
6534-
if !sn.pox_valid || sn != arrival_sn {
6546+
if sortition_id != arrival_sn.sortition_id {
65356547
continue;
65366548
}
65376549

65386550
debug!(
65396551
"New Stacks anchored block arrived: block {}/{} ({}) ari={} tip={}",
6540-
&sn.consensus_hash,
6541-
&sn.winning_stacks_block_hash,
6542-
sn.stacks_block_height,
6552+
&arrival_sn.consensus_hash,
6553+
&arrival_sn.winning_stacks_block_hash,
6554+
arrival_sn.stacks_block_height,
65436555
ari,
65446556
&parent_tip.burn_header_hash
65456557
);
65466558
new_block_arrivals.push((
6547-
sn.consensus_hash,
6548-
sn.winning_stacks_block_hash,
6549-
sn.stacks_block_height,
6559+
arrival_sn.consensus_hash,
6560+
arrival_sn.winning_stacks_block_hash,
6561+
arrival_sn.stacks_block_height,
65506562
));
65516563
} else {
65526564
// this block did not arrive on an ancestor block

stackslib/src/chainstate/stacks/db/mod.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -294,15 +294,15 @@ impl DBConfig {
294294
});
295295
match epoch_id {
296296
StacksEpochId::Epoch10 => true,
297-
StacksEpochId::Epoch20 => version_u32 >= 1 && version_u32 <= 8,
298-
StacksEpochId::Epoch2_05 => version_u32 >= 2 && version_u32 <= 8,
299-
StacksEpochId::Epoch21 => version_u32 >= 3 && version_u32 <= 8,
300-
StacksEpochId::Epoch22 => version_u32 >= 3 && version_u32 <= 8,
301-
StacksEpochId::Epoch23 => version_u32 >= 3 && version_u32 <= 8,
302-
StacksEpochId::Epoch24 => version_u32 >= 3 && version_u32 <= 8,
303-
StacksEpochId::Epoch25 => version_u32 >= 3 && version_u32 <= 8,
304-
StacksEpochId::Epoch30 => version_u32 >= 3 && version_u32 <= 8,
305-
StacksEpochId::Epoch31 => version_u32 >= 3 && version_u32 <= 8,
297+
StacksEpochId::Epoch20 => version_u32 >= 1 && version_u32 <= 9,
298+
StacksEpochId::Epoch2_05 => version_u32 >= 2 && version_u32 <= 9,
299+
StacksEpochId::Epoch21 => version_u32 >= 3 && version_u32 <= 9,
300+
StacksEpochId::Epoch22 => version_u32 >= 3 && version_u32 <= 9,
301+
StacksEpochId::Epoch23 => version_u32 >= 3 && version_u32 <= 9,
302+
StacksEpochId::Epoch24 => version_u32 >= 3 && version_u32 <= 9,
303+
StacksEpochId::Epoch25 => version_u32 >= 3 && version_u32 <= 9,
304+
StacksEpochId::Epoch30 => version_u32 >= 3 && version_u32 <= 9,
305+
StacksEpochId::Epoch31 => version_u32 >= 3 && version_u32 <= 9,
306306
}
307307
}
308308
}
@@ -654,7 +654,7 @@ impl<'a> DerefMut for ChainstateTx<'a> {
654654
}
655655
}
656656

657-
pub const CHAINSTATE_VERSION: &str = "8";
657+
pub const CHAINSTATE_VERSION: &str = "9";
658658

659659
const CHAINSTATE_INITIAL_SCHEMA: &[&str] = &[
660660
"PRAGMA foreign_keys = ON;",
@@ -853,6 +853,15 @@ const CHAINSTATE_SCHEMA_3: &[&str] = &[
853853
"#,
854854
];
855855

856+
const CHAINSTATE_SCHEMA_4: &[&str] = &[
857+
// schema change is JUST a new index, so just bump db_config.version
858+
// and add the index to `CHAINSTATE_INDEXES` (which gets re-execed
859+
// on every schema change)
860+
r#"
861+
UPDATE db_config SET version = "9";
862+
"#,
863+
];
864+
856865
const CHAINSTATE_INDEXES: &[&str] = &[
857866
"CREATE INDEX IF NOT EXISTS index_block_hash_to_primary_key ON block_headers(index_block_hash,consensus_hash,block_hash);",
858867
"CREATE INDEX IF NOT EXISTS block_headers_hash_index ON block_headers(block_hash,block_height);",
@@ -877,6 +886,7 @@ const CHAINSTATE_INDEXES: &[&str] = &[
877886
"CREATE INDEX IF NOT EXISTS index_block_header_by_affirmation_weight ON block_headers(affirmation_weight);",
878887
"CREATE INDEX IF NOT EXISTS index_block_header_by_height_and_affirmation_weight ON block_headers(block_height,affirmation_weight);",
879888
"CREATE INDEX IF NOT EXISTS index_headers_by_consensus_hash ON block_headers(consensus_hash);",
889+
"CREATE INDEX IF NOT EXISTS processable_block ON staging_blocks(processed, orphaned, attachable);",
880890
];
881891

882892
pub use stacks_common::consts::MINER_REWARD_MATURITY;
@@ -1104,6 +1114,14 @@ impl StacksChainState {
11041114
tx.execute_batch(cmd)?;
11051115
}
11061116
}
1117+
"8" => {
1118+
info!(
1119+
"Migrating chainstate schema from version 8 to 9: add index for staging_blocks"
1120+
);
1121+
for cmd in CHAINSTATE_SCHEMA_4.iter() {
1122+
tx.execute_batch(cmd)?;
1123+
}
1124+
}
11071125
_ => {
11081126
error!(
11091127
"Invalid chain state database: expected version = {}, got {}",

stackslib/src/chainstate/stacks/index/cache.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use std::char::from_digit;
18+
use std::collections::hash_map::Entry;
1819
use std::collections::{HashMap, HashSet, VecDeque};
1920
use std::hash::{Hash, Hasher};
2021
use std::io::{BufWriter, Cursor, Read, Seek, SeekFrom, Write};
@@ -137,6 +138,25 @@ impl<T: MarfTrieId> TrieCacheState<T> {
137138
self.block_hash_cache.get(&block_id).cloned()
138139
}
139140

141+
/// Get cached entry for a block hash, given its ID, or, if not
142+
/// found, use `lookup` to get the corresponding block hash and
143+
/// store it in the cache
144+
pub fn get_block_hash_caching<E, F: FnOnce(u32) -> Result<T, E>>(
145+
&mut self,
146+
id: u32,
147+
lookup: F,
148+
) -> Result<&T, E> {
149+
match self.block_hash_cache.entry(id) {
150+
Entry::Occupied(occupied_entry) => Ok(occupied_entry.into_mut()),
151+
Entry::Vacant(vacant_entry) => {
152+
let block_hash = lookup(id)?;
153+
let block_hash_ref = vacant_entry.insert(block_hash.clone());
154+
self.block_id_cache.insert(block_hash, id);
155+
Ok(block_hash_ref)
156+
}
157+
}
158+
}
159+
140160
/// Cache a block hash, given its ID
141161
pub fn store_block_hash(&mut self, block_id: u32, block_hash: T) {
142162
assert!(!self.block_hash_cache.contains_key(&block_id));
@@ -309,6 +329,17 @@ impl<T: MarfTrieId> TrieCache<T> {
309329
self.state_mut().load_block_hash(block_id)
310330
}
311331

332+
/// Get cached entry for a block hash, given its ID, or, if not
333+
/// found, use `lookup` to get the corresponding block hash and
334+
/// store it in the cache
335+
pub fn get_block_hash_caching<E, F: FnOnce(u32) -> Result<T, E>>(
336+
&mut self,
337+
id: u32,
338+
lookup: F,
339+
) -> Result<&T, E> {
340+
self.state_mut().get_block_hash_caching(id, lookup)
341+
}
342+
312343
/// Store a block's ID and hash to teh cache.
313344
pub fn store_block_hash(&mut self, block_id: u32, block_hash: T) {
314345
self.state_mut().store_block_hash(block_id, block_hash)

stackslib/src/chainstate/stacks/index/storage.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
use std::char::from_digit;
18+
use std::collections::hash_map::Entry;
1819
use std::collections::{HashMap, HashSet, VecDeque};
1920
use std::hash::{Hash, Hasher};
2021
use std::io::{BufWriter, Cursor, Read, Seek, SeekFrom, Write};
@@ -72,11 +73,8 @@ impl<T: MarfTrieId> BlockMap for TrieFileStorage<T> {
7273
}
7374

7475
fn get_block_hash_caching(&mut self, id: u32) -> Result<&T, Error> {
75-
if !self.is_block_hash_cached(id) {
76-
let block_hash = self.get_block_hash(id)?;
77-
self.cache.store_block_hash(id, block_hash);
78-
}
79-
self.cache.ref_block_hash(id).ok_or(Error::NotFoundError)
76+
self.cache
77+
.get_block_hash_caching(id, |id| trie_sql::get_block_hash(&self.db, id))
8078
}
8179

8280
fn is_block_hash_cached(&self, id: u32) -> bool {
@@ -108,12 +106,9 @@ impl<T: MarfTrieId> BlockMap for TrieStorageConnection<'_, T> {
108106
trie_sql::get_block_hash(&self.db, id)
109107
}
110108

111-
fn get_block_hash_caching(&mut self, id: u32) -> Result<&T, Error> {
112-
if !self.is_block_hash_cached(id) {
113-
let block_hash = self.get_block_hash(id)?;
114-
self.cache.store_block_hash(id, block_hash);
115-
}
116-
self.cache.ref_block_hash(id).ok_or(Error::NotFoundError)
109+
fn get_block_hash_caching<'a>(&'a mut self, id: u32) -> Result<&'a T, Error> {
110+
self.cache
111+
.get_block_hash_caching(id, |id| trie_sql::get_block_hash(&self.db, id))
117112
}
118113

119114
fn is_block_hash_cached(&self, id: u32) -> bool {
@@ -170,11 +165,8 @@ impl<T: MarfTrieId> BlockMap for TrieSqlHashMapCursor<'_, T> {
170165
}
171166

172167
fn get_block_hash_caching(&mut self, id: u32) -> Result<&T, Error> {
173-
if !self.is_block_hash_cached(id) {
174-
let block_hash = self.get_block_hash(id)?;
175-
self.cache.store_block_hash(id, block_hash);
176-
}
177-
self.cache.ref_block_hash(id).ok_or(Error::NotFoundError)
168+
self.cache
169+
.get_block_hash_caching(id, |id| trie_sql::get_block_hash(&self.db, id))
178170
}
179171

180172
fn is_block_hash_cached(&self, id: u32) -> bool {

0 commit comments

Comments
 (0)