Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
af6a8fd
init from other pr, have some code up to client (not client db),
cheme Sep 23, 2019
4db0a7f
Dumb state_db implementation, mostly boiler plate, but cannot work as
cheme Sep 24, 2019
19df6e9
TODO2 variant for in memory
cheme Sep 25, 2019
3989fea
traits in place, still need to parameterized with blocknb &| branchix
cheme Sep 25, 2019
6a6606d
passing block hash as state in a convoluted way
cheme Sep 25, 2019
934c800
passing block hash as state in a convoluted way
cheme Sep 25, 2019
5d3d47e
Recover previous branch index code without persistence.
cheme Sep 25, 2019
aeab064
let's remove branch range set of changed and removed in next commit
cheme Sep 26, 2019
57e862e
removed delta in branch (not needed if no persistence)
cheme Sep 26, 2019
4edbf27
Before using range instead of hash (we move range to upper client on
cheme Sep 26, 2019
91b87d7
use also block number for query (when not in statedb we need number).
cheme Sep 26, 2019
966a09f
Fixing finalize state algo.
cheme Sep 27, 2019
a37a32f
remove keys from commit set, this likely indicates broken code, will
cheme Sep 27, 2019
4714b70
put a client test, for rest of test reset_storage and genesis build
cheme Sep 27, 2019
5e90b20
Get needed component from branch history-data
cheme Oct 1, 2019
f6956b1
use history from utils
cheme Oct 1, 2019
9ba8057
Test issue is that query on remove hash do not work
cheme Oct 1, 2019
31c1ee3
test commit set
cheme Oct 2, 2019
6209f4d
fix unpin gc
cheme Oct 2, 2019
70f69b6
missing offstate prunnig handling
cheme Oct 2, 2019
6803c86
previous pruning did not make sense, switch to only storing touched key
cheme Oct 2, 2019
2497575
Figure out pruning (see prune_one/prune_two tests).
cheme Oct 3, 2019
e86fdd2
end fixing pruning test, remainings root lib tests to adjust
cheme Oct 3, 2019
e48cf43
fix gc call block index.
cheme Oct 4, 2019
0e3c65e
state_db tests passing.
cheme Oct 4, 2019
13ea088
fix underflow
cheme Oct 4, 2019
92c699c
before switching to absolute indexing (option<u64> to u64).
cheme Oct 4, 2019
bf79879
complete first test in client db, new todo.
cheme Oct 4, 2019
3913ba7
Merge branch 'master' into chain-aux-merge
cheme Oct 4, 2019
4dc2c8d
serialized with default
cheme Oct 7, 2019
03080c4
serialized with default is useless
cheme Oct 7, 2019
8eb5e07
few warning fix
cheme Oct 7, 2019
c89274d
simplify state machine offstate traits, TODO2 will be simple hashmap
cheme Oct 7, 2019
249770b
further simplify
cheme Oct 7, 2019
69fef43
Remove stub state machine implementation.
cheme Oct 7, 2019
a547560
init offstate for tests, but tests will only be interesting with chil…
cheme Oct 7, 2019
397d510
rem todos
cheme Oct 7, 2019
c133a0b
compact casts
cheme Oct 7, 2019
f197d7d
compact casts
cheme Oct 7, 2019
9846613
quick prune test
cheme Oct 7, 2019
d51e98f
break some lines
cheme Oct 7, 2019
fff7cb5
fix
cheme Oct 7, 2019
d55211a
split commit set to have offstate pruning only when needed.
cheme Oct 8, 2019
27ca685
Fix logic of pruning in client (prior it did not take account of last
cheme Oct 8, 2019
64b4102
No need for special revert unless we create archive mode with pruning
cheme Oct 8, 2019
5072f85
Do not keep deletion in branch storage.
cheme Oct 8, 2019
8f8ecc9
sed renaming of offstate to more generic and less incorect 'kv' (as key
cheme Oct 8, 2019
35bc11e
switch overlay transaction to the inner hashmap storage, only change to
cheme Oct 8, 2019
d111288
Remove commit kv from revert.
cheme Oct 9, 2019
dd9dddb
test db better handling
cheme Oct 9, 2019
df950a5
cleaning pass.
cheme Oct 9, 2019
0ca6530
starting using keyspace, storing in the overlay next to the child trie
cheme Oct 9, 2019
0dd36d0
it is tricky, but clearly getting rid of keyspace in overlayed change
cheme Oct 9, 2019
34cf138
wrong approach (the overlay db code for kv is not strictly needed),
cheme Oct 9, 2019
a732231
a todo
cheme Oct 10, 2019
ae180ed
Slight change to 'into_committed' proto, to allow resolving
cheme Oct 10, 2019
c39385b
Merge branch 'chain-aux2' into kv-keyspace
cheme Oct 10, 2019
d53dbba
boilerplate changes.
cheme Oct 10, 2019
9a3d762
Change trie crate from child_trie_soft_min
cheme Oct 10, 2019
da23a0c
prepare change
cheme Oct 10, 2019
3931280
fix proof test
cheme Oct 10, 2019
f6268ab
need a kv_storage function in backend.
cheme Oct 11, 2019
431f93d
add 'kv_store' to state machine backend
cheme Oct 11, 2019
9ccf87f
Merge branch 'chain-aux2' into kv-keyspace
cheme Oct 11, 2019
2b4dad9
state machine missing functions.
cheme Oct 11, 2019
fc16bae
fix other modules compilation.
cheme Oct 11, 2019
ec10b6d
revert into_committed and TODO for caching that is major (child root
cheme Oct 11, 2019
1209ac7
apply renaming
cheme Oct 11, 2019
0eed411
Get and modify previous transaction test.
cheme Oct 11, 2019
42bbd9d
revert into_committed to previous implementation
cheme Oct 11, 2019
b06ec1b
Merge branch 'chain-aux2' into kv-keyspace
cheme Oct 11, 2019
b0dce4a
Merge branch 'master' into chain-aux2
cheme Oct 11, 2019
03e47c2
Merge branch 'chain-aux2' into kv-keyspace
cheme Oct 11, 2019
899e151
Add a place holder for child trie deletion in journals.
cheme Oct 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Before using range instead of hash (we move range to upper client on
pin).
  • Loading branch information
cheme committed Sep 26, 2019
commit 4edbf27f11d0660ccf26cf65a169b44d71d7cbde
2 changes: 1 addition & 1 deletion core/client/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1582,7 +1582,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
match self.blockchain.header(block) {
Ok(Some(ref hdr)) => {
let hash = hdr.hash();
if let Ok(()) = self.storage.state_db.pin(&hash) {
if let Ok(Some(range)) = self.storage.state_db.pin(&hash) {
let root = H256::from_slice(hdr.state_root().as_ref());
//let block_number = hdr.number().clone();
//let db_state = DbState::new(self.storage.clone(), root, Arc::new(TODO::new(block_number)));
Expand Down
24 changes: 20 additions & 4 deletions core/state-db/src/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ pub struct LinearStatesRef {
/// unknown db value as `None`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RangeSet {
// TODO EMCH using a option value makes not sense when all in memory
storage: BTreeMap<u64, Option<LinearStates>>,
last_index: u64,
treshold: u64,
Expand Down Expand Up @@ -270,27 +271,42 @@ impl RangeSet {
} else {
let new_storage = self.storage.split_off(&(self.treshold));
self.storage = new_storage;
self.finalize_full(branch_index);
self.finalize_full(branch_index, None);
};
}

/// Apply a post finalize without considering treshold.
fn finalize_full(
/// TODO EMCH rename as it is also use to prepare a gc
/// without moving the treshould first.
pub fn finalize_full(
&mut self,
branch_index: u64,
linear_index: Option<u64>,
) {
// TODO EMCH consider working directly on ordered vec (should be fastest in most cases)
let mut finalize_branches_map: BTreeMap<_, _> = self.branch_ranges_from_cache(branch_index)
.into_iter().map(|r| (r.branch_index, r.state)).collect();

for (index, state) in self.storage.iter_mut() {
if let Some(final_state) = finalize_branches_map.remove(&index) {
// update for case where end of range differs (see `branch_ranges_from_cache`).
state.as_mut().map(|state| {
// update for case where end of range differs
// (see `branch_ranges_from_cache`).
if state.state != final_state {
state.state = final_state;
state.can_append = false;
}
if *index == branch_index {
if let Some(linear_index) = linear_index {
state.state.end = std::cmp::min(linear_index + 1, state.state.end);
}
// set this branch as non appendable (ensure it get gc
// at some point even if there is no branching).
// Also if gc and treshold happen after this call,
// ensure this branch can get remove.
state.can_append = false;
}

});
} else {
*state = None;
Expand All @@ -303,7 +319,7 @@ impl RangeSet {
&mut self,
branch_index: u64,
) {
self.finalize_full(branch_index);
self.finalize_full(branch_index, None);
}

/// Revert some ranges, without any way to revert.
Expand Down
9 changes: 5 additions & 4 deletions core/state-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use std::collections::{HashMap, hash_map::Entry};
use noncanonical::NonCanonicalOverlay;
use pruning::RefWindow;
use log::trace;
pub use branch::BranchRanges;

/// Database value type.
pub type DBValue = Vec<u8>;
Expand Down Expand Up @@ -322,9 +323,9 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
}
}

pub fn pin(&mut self, hash: &BlockHash) -> Result<(), PinError> {
pub fn pin(&mut self, hash: &BlockHash) -> Result<Option<BranchRanges>, PinError> {
match self.mode {
PruningMode::ArchiveAll => Ok(()),
PruningMode::ArchiveAll => Ok(self.non_canonical.get_branch_range(hash)),
PruningMode::ArchiveCanonical | PruningMode::Constrained(_) => {
if self.non_canonical.have_block(hash) ||
self.pruning.as_ref().map_or(false, |pruning| pruning.have_block(hash))
Expand All @@ -335,7 +336,7 @@ impl<BlockHash: Hash, Key: Hash> StateDbSync<BlockHash, Key> {
self.non_canonical.pin(hash);
}
*refs += 1;
Ok(())
Ok(self.non_canonical.get_branch_range(hash))
} else {
Err(PinError::InvalidBlock)
}
Expand Down Expand Up @@ -446,7 +447,7 @@ impl<BlockHash: Hash, Key: Hash> StateDb<BlockHash, Key> {
}

/// Prevents pruning of specified block and its descendants.
pub fn pin(&self, hash: &BlockHash) -> Result<(), PinError> {
pub fn pin(&self, hash: &BlockHash) -> Result<Option<BranchRanges>, PinError> {
self.db.write().pin(hash)
}

Expand Down
163 changes: 141 additions & 22 deletions core/state-db/src/noncanonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
//! `revert_pending`

use std::fmt;
use std::collections::{HashMap, VecDeque, hash_map::Entry};
use std::collections::{HashMap, VecDeque, hash_map::Entry, HashSet};
use super::{Error, DBValue, ChangeSet, CommitSet, MetaDb, Hash, to_meta_key, OffstateKey};
use codec::{Encode, Decode};
use log::trace;
use crate::branch::RangeSet;
use crate::branch::{RangeSet, BranchRanges};

const NON_CANONICAL_JOURNAL: &[u8] = b"noncanonical_journal";
const NON_CANONICAL_OFFSTATE_JOURNAL: &[u8] = b"offstate_noncanonical_journal";
Expand All @@ -49,9 +49,86 @@ pub struct NonCanonicalOverlay<BlockHash: Hash, Key: Hash> {
// TODO EMCH sense if pinning offstate? done while using state_at
// -> that is import processing (so we can revert) -> should be good
// to use on offstate too
pinned: HashMap<BlockHash, (HashMap<Key, DBValue>, HashMap<OffstateKey, DBValue>)>,
//
/// second value is offstate pinned index: used in order to determine if the pinned
/// thread should block garbage collection.
pinned: HashMap<BlockHash, (HashMap<Key, DBValue>, u64)>,
offstate_gc: OffstatePendingGC,
}

#[derive(Default)]
/// offstate gc only happen when all pinned threads that where
/// running at the time of cannonicalisation are finished.
struct OffstatePendingGC {
/// Keep trace of last cannonicalization branch index height.
/// All data in state are added after this value (branch is
/// set as non modifiable on canonicalisation).
pending_canonicalisation_query: Option<u64>,
/// keys to gc that got their journal removed.
keys_pending_gc: HashSet<OffstateKey>,
/// branch index that are not garbage collected.
/// Note that it can also contain branch index created after cannonicalisation
/// query.
keep_indexes: Vec<BranchRanges>,
}

impl OffstatePendingGC {
fn set_pending_gc(&mut self, branch_index: u64) {
self.pending_canonicalisation_query = Some(branch_index);
self.keep_indexes.clear();
}
fn try_gc<K, V>(
&mut self,
pinned: &HashMap<K, (V, u64)>,
) {
if let Some(pending) = self.pending_canonicalisation_query {
if pending < self.max_pinned_index(pinned) {

unimplemented!("TODO feed keepindexes with branch at pending then actual gc");

self.pending_canonicalisation_query = None;
self.keep_indexes.clear();
}
}
}
fn pin(&mut self, branch_index: u64, set: &RangeSet) -> BranchRanges {
let range = set.branch_ranges_from_cache(branch_index);
if let Some(pending) = self.pending_canonicalisation_query {
// pending is set non modifiable before setting pending gc.
debug_assert!(pending < branch_index);
self.keep_indexes.push(range.clone());
}
range
}
fn max_pinned_index<K, V>(
&self,
pinned: &HashMap<K, (V, u64)>,
) -> u64 {
let mut max = 0;
if let Some(pending) = self.pending_canonicalisation_query {
// max up to pending only
for (_, (_, index)) in pinned.iter() {
if *index > max && *index <= pending {
max = *index;
}
}
} else {
// global max
for (_, (_, index)) in pinned.iter() {
if *index > max {
max = *index;
}
}
}
max
}
}
struct OffstatePinnedThread {
/// index of branch which was pinned
branch_index: u64,


}
#[derive(Encode, Decode)]
struct JournalRecord<BlockHash: Hash, Key: Hash> {
hash: BlockHash,
Expand Down Expand Up @@ -98,6 +175,9 @@ fn discard_values<Key: Hash>(
inserted: Vec<Key>,
mut into: Option<&mut HashMap<Key, DBValue>>,
) {
if into.is_none() {
return;
}
for k in inserted {
match values.entry(k) {
Entry::Occupied(mut e) => {
Expand All @@ -117,13 +197,37 @@ fn discard_values<Key: Hash>(
}
}

fn discard_offset_values(
values: &mut HashMap<OffstateKey, (u32, DBValue)>,
inserted: Vec<OffstateKey>,
into: &mut OffstatePendingGC,
) {
for k in inserted {
match values.entry(k) {
Entry::Occupied(mut e) => {
let (ref mut counter, _) = e.get_mut();
*counter -= 1;
if *counter == 0 {
let (key, _) = e.remove_entry();
into.keys_pending_gc.insert(key);
}
},
Entry::Vacant(_) => {
debug_assert!(false, "Trying to discard missing value");
}
}
}
}


fn discard_descendants<BlockHash: Hash, Key: Hash>(
levels: &mut VecDeque<Vec<BlockOverlay<BlockHash, Key>>>,
mut values: &mut HashMap<Key, (u32, DBValue)>,
mut offstate_values: &mut HashMap<OffstateKey, (u32, DBValue)>,
index: usize,
parents: &mut HashMap<BlockHash, (BlockHash, u64)>,
pinned: &mut HashMap<BlockHash, (HashMap<Key, DBValue>, HashMap<OffstateKey, DBValue>)>,
pinned: &mut HashMap<BlockHash, (HashMap<Key, DBValue>, u64)>,
offstate_gc: &mut OffstatePendingGC,
hash: &BlockHash,
) {
let mut discarded = Vec::new();
Expand All @@ -135,10 +239,10 @@ fn discard_descendants<BlockHash: Hash, Key: Hash>(
discarded.push(overlay.hash);
let mut pinned = pinned.get_mut(hash);
discard_values(&mut values, overlay.inserted, pinned.as_mut().map(|p| &mut p.0));
discard_values(
discard_offset_values(
&mut offstate_values,
overlay.offstate_inserted,
pinned.as_mut().map(|p| &mut p.1),
offstate_gc,
);
None
} else {
Expand All @@ -147,7 +251,7 @@ fn discard_descendants<BlockHash: Hash, Key: Hash>(
}).collect();
}
for hash in discarded {
discard_descendants(levels, values, offstate_values, index + 1, parents, pinned, &hash);
discard_descendants(levels, values, offstate_values, index + 1, parents, pinned, offstate_gc, &hash);
}
}

Expand Down Expand Up @@ -250,6 +354,7 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
pinned: Default::default(),
values,
offstate_values,
offstate_gc: Default::default(),
branches,
})
}
Expand Down Expand Up @@ -445,12 +550,18 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
}

fn apply_canonicalizations(&mut self) {
let count = self.pending_canonicalizations.len() as u64;
let last_block_number = self.last_canonicalized.as_ref().map(|(_, n)| n + count).unwrap_or(count - 1);
let last = self.pending_canonicalizations.last().cloned();
if let Some((_, branch_index_cannonicalize)) = last.as_ref().and_then(|last| self.parents.get(last)) {
// using costy finalize
self.branches.update_finalize_treshold(*branch_index_cannonicalize, true);
if let Some(branch_index_cannonicalize) = last.as_ref().and_then(|last| self.parents.get(last))
.map(|(_, index)| *index) {
// set branch state synchronously
self.branches.finalize_full(branch_index_cannonicalize, Some(last_block_number));
self.offstate_gc.set_pending_gc(branch_index_cannonicalize);
// try to run the garbage collection (can run later if there is
// pinned process).
self.offstate_gc.try_gc(&self.pinned);
}
let count = self.pending_canonicalizations.len() as u64;
for hash in self.pending_canonicalizations.drain(..) {
trace!(target: "state-db", "Post canonicalizing {:?}", hash);
let level = self.levels.pop_front().expect("Hash validity is checked in `canonicalize`");
Expand All @@ -470,21 +581,22 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
0,
&mut self.parents,
&mut self.pinned,
&mut self.offstate_gc,
&overlay.hash,
);
}

let mut pinned = self.pinned.get_mut(&overlay.hash);
discard_values(&mut self.values, overlay.inserted, pinned.as_mut().map(|p| &mut p.0));
discard_values(
discard_offset_values(
&mut self.offstate_values,
overlay.offstate_inserted,
pinned.as_mut().map(|p| &mut p.1),
&mut self.offstate_gc,
);
}
}
if let Some(hash) = last {
let last_canonicalized = (hash, self.last_canonicalized.as_ref().map(|(_, n)| n + count).unwrap_or(count - 1));
let last_canonicalized = (hash, last_block_number);
self.last_canonicalized = Some(last_canonicalized);
}
}
Expand Down Expand Up @@ -515,11 +627,6 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
if let Some((_, value)) = self.offstate_values.get(key) {
return Some(value.clone());
}
for pinned in self.pinned.values() {
if let Some(value) = pinned.1.get(key) {
return Some(value.clone());
}
}
None
}

Expand All @@ -535,7 +642,9 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
let mut commit = CommitSet::default();
for overlay in level.into_iter() {
commit.meta.deleted.push(overlay.journal_key);
self.parents.remove(&overlay.hash);
if let Some((_, branch_index)) = self.parents.remove(&overlay.hash) {
self.branches.revert(branch_index);
}
discard_values(&mut self.values, overlay.inserted, None);
discard_values(&mut self.offstate_values, overlay.offstate_inserted, None);
}
Expand Down Expand Up @@ -576,8 +685,18 @@ impl<BlockHash: Hash, Key: Hash> NonCanonicalOverlay<BlockHash, Key> {
}

/// Pin state values in memory
pub fn pin(&mut self, hash: &BlockHash) {
self.pinned.insert(hash.clone(), Default::default());
pub fn pin(&mut self, hash: &BlockHash) -> Option<BranchRanges> {
self.parents.get(hash).map(|(_, branch_index)| *branch_index).map(|branch_index| {
self.pinned.insert(hash.clone(), (Default::default(), branch_index));
self.offstate_gc.pin(branch_index, &self.branches)
})
}

/// TODO EMCH aka get state for hash to query offstate storage.
pub fn get_branch_range(&self, hash: &BlockHash) -> Option<BranchRanges> {
self.parents.get(hash).map(|(_, branch_index)| *branch_index).map(|branch_index| {
self.branches.branch_ranges_from_cache(branch_index)
})
}

/// Discard pinned state
Expand Down