Skip to content
This repository was archived by the owner on Feb 1, 2024. It is now read-only.

Commit c6e533c

Browse files
committed
Move and rename StatePruneManager
Move the StatePruneManager to state::state_pruning_manager and rename it to StatePruningManager. Additionally: - Remove reference to the state database in the ChainController's new function, replacing it with a StatePruningManager instance. Signed-off-by: Peter Schwarz <pschwarz@bitwise.io>
1 parent 7767d90 commit c6e533c

4 files changed

Lines changed: 125 additions & 97 deletions

File tree

validator/src/journal/chain.rs

Lines changed: 7 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* ------------------------------------------------------------------------------
1616
*/
1717

18-
use std::collections::VecDeque;
1918
use std::fs::File;
2019
use std::io;
2120
use std::io::prelude::*;
@@ -38,12 +37,11 @@ use std::time::Duration;
3837
use protobuf;
3938

4039
use batch::Batch;
41-
use database::lmdb::LmdbDatabase;
4240
use journal;
4341
use journal::block_validator::{BlockValidationResult, BlockValidator, ValidationError};
4442
use journal::block_wrapper::BlockWrapper;
4543
use metrics;
46-
use state::merkle::MerkleDatabase;
44+
use state::state_pruning_manager::StatePruningManager;
4745

4846
use proto::transaction_receipt::TransactionReceipt;
4947
use scheduler::TxnExecutionResult;
@@ -152,7 +150,7 @@ struct ChainControllerState<BC: BlockCache, BV: BlockValidator, CW: ChainWriter>
152150
chain_head_update_observer: Box<ChainHeadUpdateObserver>,
153151
observers: Vec<Box<ChainObserver>>,
154152

155-
state_prune_manager: StatePruneManager,
153+
state_pruning_manager: StatePruningManager,
156154
}
157155

158156
#[derive(Clone)]
@@ -177,7 +175,7 @@ impl<BC: BlockCache + 'static, BV: BlockValidator + 'static, CW: ChainWriter + '
177175
chain_head_update_observer: Box<ChainHeadUpdateObserver>,
178176
state_pruning_block_depth: u32,
179177
observers: Vec<Box<ChainObserver>>,
180-
state_database: LmdbDatabase,
178+
state_pruning_manager: StatePruningManager,
181179
) -> Self {
182180
let mut chain_controller = ChainController {
183181
state: Arc::new(RwLock::new(ChainControllerState {
@@ -190,7 +188,7 @@ impl<BC: BlockCache + 'static, BV: BlockValidator + 'static, CW: ChainWriter + '
190188
chain_head_update_observer,
191189
observers,
192190
chain_head: None,
193-
state_prune_manager: StatePruneManager::new(state_database),
191+
state_pruning_manager
194192
})),
195193
stop_handle: Arc::new(Mutex::new(None)),
196194
block_queue_sender: None,
@@ -276,7 +274,7 @@ impl<BC: BlockCache + 'static, BV: BlockValidator + 'static, CW: ChainWriter + '
276274
let chain_head_block = new_block.clone();
277275
state.chain_head = Some(new_block);
278276

279-
state.state_prune_manager.update_queue(
277+
state.state_pruning_manager.update_queue(
280278
&result
281279
.new_chain
282280
.iter()
@@ -363,14 +361,14 @@ impl<BC: BlockCache + 'static, BV: BlockValidator + 'static, CW: ChainWriter + '
363361
if chain_head_block_num + 1 > self.state_pruning_block_depth as u64 {
364362
let prune_at = chain_head_block_num - (self.state_pruning_block_depth as u64);
365363
match state.chain_reader.get_block_by_block_num(prune_at) {
366-
Ok(Some(block)) => state.state_prune_manager.add_to_queue(block.state_root_hash()),
364+
Ok(Some(block)) => state.state_pruning_manager.add_to_queue(block.state_root_hash()),
367365
Ok(None) => warn!("No block at block height {}; ignoring...", prune_at),
368366
Err(err) => error!("Unable to fetch block at height {}: {:?}", prune_at, err)
369367
}
370368
}
371369

372370
// Execute pruning:
373-
state.state_prune_manager.decimate()
371+
state.state_pruning_manager.decimate()
374372
} else {
375373
info!("Rejected new chain head: {}", new_block);
376374
}
@@ -698,92 +696,5 @@ impl ChainIdManager {
698696
}
699697
}
700698

701-
/// The StatePruneManager manages a collection of state root hashes that will be
702-
/// prune from the MerkleDatabase at intervals. Pruning will occur by decimating
703-
/// the state root hashes. I.e. ten percent (rounded down) of the state roots in
704-
/// the queue will be pruned. This allows state roots to remain in the queue for
705-
/// a period of time, on the chance that they are from a chain that has been
706-
/// abandoned and then re-chosen as the primary chain.
707-
struct StatePruneManager {
708-
// Contains the state root hashes slated for pruning
709-
state_root_prune_queue: VecDeque<String>,
710-
state_database: LmdbDatabase,
711-
}
712-
713-
impl StatePruneManager {
714-
fn new(state_database: LmdbDatabase) -> Self {
715-
StatePruneManager {
716-
state_root_prune_queue: VecDeque::new(),
717-
state_database,
718-
}
719-
}
720-
721-
/// Updates the pruning queue. Abandoned roots will be added to the queue.
722-
/// Added roots will be removed from the queue. This ensures that the state
723-
/// roots won't be removed, regardless of the chain state.
724-
fn update_queue(&mut self, added_roots: &[&str], _abandoned_roots: &[&str]) {
725-
// Remove any state root hashes from the pruning queue that we may have switched
726-
// back too from an alternate chain
727-
added_roots.iter().for_each(|state_root_hash| {
728-
self.state_root_prune_queue.retain(|hash| {
729-
if hash != state_root_hash {
730-
true
731-
} else {
732-
debug!("Removing {} from pruning queue", state_root_hash);
733-
false
734-
}
735-
})
736-
});
737-
}
738-
739-
/// Add a single state root to the pruning queue.
740-
fn add_to_queue(&mut self, state_root_hash: &str) {
741-
let state_root_hash = state_root_hash.into();
742-
if !self.state_root_prune_queue.contains(&state_root_hash) {
743-
debug!("Adding {} to pruning queue", state_root_hash);
744-
self.state_root_prune_queue.push_back(state_root_hash);
745-
}
746-
}
747-
748-
/// Remove the first ten percent (floored) of the prune queue.
749-
fn decimate(&mut self) {
750-
let prune_count = (self.state_root_prune_queue.len() as f64 / 10.0).floor() as usize;
751-
752-
let mut total_pruned_entries: usize = 0;
753-
for _ in 0..prune_count {
754-
if let Some(state_root) = self.state_root_prune_queue.pop_front() {
755-
match MerkleDatabase::prune(&self.state_database, &state_root) {
756-
Ok(removed_keys) => {
757-
total_pruned_entries += removed_keys.len();
758-
759-
let mut state_roots_pruned_count =
760-
COLLECTOR.counter("StatePruneManager.state_roots_pruned", None, None);
761-
state_roots_pruned_count.inc();
762-
763-
// the state root was not pruned (it is likely the root of a
764-
// fork), so push it back into the queue.
765-
if removed_keys.is_empty() {
766-
self.state_root_prune_queue.push_back(state_root);
767-
}
768-
}
769-
Err(err) => {
770-
error!("Unable to prune state root {}: {:?}", state_root, err);
771-
self.state_root_prune_queue.push_back(state_root);
772-
}
773-
}
774-
} else {
775-
break;
776-
}
777-
}
778-
779-
if total_pruned_entries > 0 {
780-
info!(
781-
"Pruned {} keys from the Global state Database",
782-
total_pruned_entries
783-
);
784-
}
785-
}
786-
}
787-
788699
#[cfg(tests)]
789700
mod tests {}

validator/src/journal/chain_ffi.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use journal::block_wrapper::BlockWrapper;
2222
use journal::chain::*;
2323
use py_ffi;
2424
use pylogger;
25+
use state::state_pruning_manager::StatePruningManager;
2526
use std::ffi::CStr;
2627
use std::os::raw::{c_char, c_void};
2728
use std::sync::mpsc::Sender;
@@ -109,6 +110,8 @@ pub extern "C" fn chain_controller_new(
109110

110111
let state_database = unsafe { (*(state_database as *const LmdbDatabase)).clone() };
111112

113+
let state_pruning_manager = StatePruningManager::new(state_database);
114+
112115
let chain_controller = ChainController::new(
113116
PyBlockCache::new(py_block_cache),
114117
PyBlockValidator::new(py_block_validator),
@@ -119,7 +122,7 @@ pub extern "C" fn chain_controller_new(
119122
Box::new(PyChainHeadUpdateObserver::new(py_on_chain_updated)),
120123
state_pruning_block_depth,
121124
observer_wrappers,
122-
state_database,
125+
state_pruning_manager,
123126
);
124127

125128
unsafe {

validator/src/state/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub mod identity_view;
2020
pub mod merkle;
2121
pub mod merkle_ffi;
2222
pub mod settings_view;
23+
pub mod state_pruning_manager;
2324

2425
use state::error::StateDatabaseError;
2526

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright 2018 Intel Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
* ------------------------------------------------------------------------------
16+
*/
17+
use std::collections::VecDeque;
18+
19+
use database::lmdb::LmdbDatabase;
20+
use metrics;
21+
use state::merkle::MerkleDatabase;
22+
23+
lazy_static! {
24+
static ref COLLECTOR: metrics::MetricsCollectorHandle =
25+
metrics::get_collector("sawtooth_validator.state");
26+
}
27+
28+
/// The StatePruneManager manages a collection of state root hashes that will be
29+
/// prune from the MerkleDatabase at intervals. Pruning will occur by decimating
30+
/// the state root hashes. I.e. ten percent (rounded down) of the state roots in
31+
/// the queue will be pruned. This allows state roots to remain in the queue for
32+
/// a period of time, on the chance that they are from a chain that has been
33+
/// abandoned and then re-chosen as the primary chain.
34+
pub struct StatePruningManager {
35+
// Contains the state root hashes slated for pruning
36+
state_root_prune_queue: VecDeque<String>,
37+
state_database: LmdbDatabase,
38+
}
39+
40+
impl StatePruningManager {
41+
pub fn new(state_database: LmdbDatabase) -> Self {
42+
StatePruningManager {
43+
state_root_prune_queue: VecDeque::new(),
44+
state_database,
45+
}
46+
}
47+
48+
/// Updates the pruning queue. Abandoned roots will be added to the queue.
49+
/// Added roots will be removed from the queue. This ensures that the state
50+
/// roots won't be removed, regardless of the chain state.
51+
pub fn update_queue(&mut self, added_roots: &[&str], _abandoned_roots: &[&str]) {
52+
// Remove any state root hashes from the pruning queue that we may have switched
53+
// back too from an alternate chain
54+
added_roots.iter().for_each(|state_root_hash| {
55+
self.state_root_prune_queue.retain(|hash| {
56+
if hash != state_root_hash {
57+
true
58+
} else {
59+
debug!("Removing {} from pruning queue", state_root_hash);
60+
false
61+
}
62+
})
63+
});
64+
}
65+
66+
/// Add a single state root to the pruning queue.
67+
pub fn add_to_queue(&mut self, state_root_hash: &str) {
68+
let state_root_hash = state_root_hash.into();
69+
if !self.state_root_prune_queue.contains(&state_root_hash) {
70+
debug!("Adding {} to pruning queue", state_root_hash);
71+
self.state_root_prune_queue.push_back(state_root_hash);
72+
}
73+
}
74+
75+
/// Remove the first ten percent (floored) of the prune queue.
76+
pub fn decimate(&mut self) {
77+
let prune_count = (self.state_root_prune_queue.len() as f64 / 10.0).floor() as usize;
78+
79+
let mut total_pruned_entries: usize = 0;
80+
for _ in 0..prune_count {
81+
if let Some(state_root) = self.state_root_prune_queue.pop_front() {
82+
match MerkleDatabase::prune(&self.state_database, &state_root) {
83+
Ok(removed_keys) => {
84+
total_pruned_entries += removed_keys.len();
85+
86+
let mut state_roots_pruned_count =
87+
COLLECTOR.counter("StatePruneManager.state_roots_pruned", None, None);
88+
state_roots_pruned_count.inc();
89+
90+
// the state root was not pruned (it is likely the root of a
91+
// fork), so push it back into the queue.
92+
if removed_keys.is_empty() {
93+
self.state_root_prune_queue.push_back(state_root);
94+
}
95+
}
96+
Err(err) => {
97+
error!("Unable to prune state root {}: {:?}", state_root, err);
98+
self.state_root_prune_queue.push_back(state_root);
99+
}
100+
}
101+
} else {
102+
break;
103+
}
104+
}
105+
106+
if total_pruned_entries > 0 {
107+
info!(
108+
"Pruned {} keys from the Global state Database",
109+
total_pruned_entries
110+
);
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)