Skip to content

Commit a3a2012

Browse files
SeungMin Leesgkim126
authored andcommitted
Add a cache to reduce DB operations
The address-value pair is stored in the cache when the are written and read in the DB. As cache added, we can find the value in the cache. Therefore, the overhead derived from DB operations will be reduced.
1 parent a4400e9 commit a3a2012

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rand = "0.6.1"
1414
rlp = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.4" }
1515
rlp_derive = { git = "https://github.com/CodeChain-io/rlp.git", version = "0.2" }
1616
snap = "0.2"
17+
lru-cache = "0.1.2"
1718

1819
[dev-dependencies]
1920
kvdb = "0.1"

src/triedb.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use crate::node::Node as RlpNode;
1919
use crate::{Trie, TrieError};
2020
use ccrypto::{blake256, BLAKE_NULL_RLP};
2121
use cdb::HashDB;
22+
use lru_cache::LruCache;
2223
use primitives::H256;
24+
use std::cell::RefCell;
2325

2426
/// A `Trie` implementation using a generic `HashDB` backing database.
2527
///
@@ -43,6 +45,7 @@ use primitives::H256;
4345
pub(crate) struct TrieDB<'db> {
4446
db: &'db dyn HashDB,
4547
root: &'db H256,
48+
cache: RefCell<LruCache<H256, Vec<u8>>>,
4649
}
4750

4851
/// Description of what kind of query will be made to the trie.
@@ -52,12 +55,14 @@ impl<'db> TrieDB<'db> {
5255
/// Create a new trie with the backing database `db` and `root`
5356
/// Returns an error if `root` does not exist
5457
pub fn try_new(db: &'db dyn HashDB, root: &'db H256) -> crate::Result<Self> {
58+
let cache: RefCell<LruCache<H256, Vec<u8>>> = RefCell::new(LruCache::new(3000));
5559
if !db.contains(root) {
5660
Err(TrieError::InvalidStateRoot(*root))
5761
} else {
5862
Ok(TrieDB {
5963
db,
6064
root,
65+
cache,
6166
})
6267
}
6368
}
@@ -71,9 +76,19 @@ impl<'db> TrieDB<'db> {
7176
) -> crate::Result<Option<T>> {
7277
match cur_node_hash {
7378
Some(hash) => {
74-
let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?;
75-
76-
match RlpNode::decoded(&node_rlp) {
79+
// FIXME: Refactoring is required to reduce access to the cache.
80+
// the current code queries the cache twice when the data is cached.
81+
let node_rlp;
82+
let decoded_rlp = if self.cache.borrow_mut().contains_key(&hash) {
83+
node_rlp = self.cache.borrow_mut().get_mut(&hash).unwrap().to_vec();
84+
RlpNode::decoded(&node_rlp)
85+
} else {
86+
node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?;
87+
self.cache.borrow_mut().insert(hash, (&*node_rlp).to_vec());
88+
RlpNode::decoded(&node_rlp)
89+
};
90+
91+
match decoded_rlp {
7792
Some(RlpNode::Leaf(partial, value)) => {
7893
if &partial == path {
7994
Ok(Some(query(value)))

src/triedbmut.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::triedb::TrieDB;
2020
use crate::{Trie, TrieError, TrieMut};
2121
use ccrypto::{blake256, BLAKE_NULL_RLP};
2222
use cdb::{DBValue, HashDB};
23+
use lru_cache::LruCache;
2324
use primitives::H256;
2425
use std::fmt;
2526

@@ -31,16 +32,19 @@ pub(crate) struct TrieDBMut<'a> {
3132
db: &'a mut dyn HashDB,
3233
// When Trie is empty, root has None.
3334
root: &'a mut H256,
35+
cache: LruCache<H256, Vec<u8>>,
3436
}
3537

3638
impl<'a> TrieDBMut<'a> {
3739
/// Create a new trie with backing database `db` and empty `root`.
3840
pub fn new(db: &'a mut dyn HashDB, root: &'a mut H256) -> Self {
3941
*root = BLAKE_NULL_RLP;
4042

43+
let cache: LruCache<H256, Vec<u8>> = LruCache::new(3000);
4144
TrieDBMut {
4245
db,
4346
root,
47+
cache,
4448
}
4549
}
4650

@@ -51,9 +55,11 @@ impl<'a> TrieDBMut<'a> {
5155
return Err(TrieError::InvalidStateRoot(*root))
5256
}
5357

58+
let cache: LruCache<H256, Vec<u8>> = LruCache::new(3000);
5459
Ok(TrieDBMut {
5560
db,
5661
root,
62+
cache,
5763
})
5864
}
5965

@@ -67,16 +73,27 @@ impl<'a> TrieDBMut<'a> {
6773
) -> crate::Result<H256> {
6874
match cur_node_hash {
6975
Some(hash) => {
70-
let node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?;
71-
72-
match RlpNode::decoded(&node_rlp) {
76+
// FIXME: Refactoring is required to reduce access to the cache.
77+
// the current code queries the cache twice when the data is cached.
78+
let node_rlp;
79+
let decoded_rlp = if self.cache.contains_key(&hash) {
80+
node_rlp = self.cache.get_mut(&hash).unwrap().to_vec();
81+
RlpNode::decoded(&node_rlp)
82+
} else {
83+
node_rlp = self.db.get(&hash).ok_or_else(|| TrieError::IncompleteDatabase(hash))?;
84+
self.cache.insert(hash, (&*node_rlp).to_vec());
85+
RlpNode::decoded(&node_rlp)
86+
};
87+
88+
match decoded_rlp {
7389
Some(RlpNode::Leaf(partial, value)) => {
7490
// Renew the Leaf
7591
if partial == path {
7692
let node = RlpNode::Leaf(path, insert_value);
7793
let node_rlp = RlpNode::encoded(node);
7894
let hash = self.db.insert(&node_rlp);
7995

96+
self.cache.insert(hash, node_rlp);
8097
*old_val = Some(value.to_vec());
8198

8299
Ok(hash)
@@ -102,6 +119,7 @@ impl<'a> TrieDBMut<'a> {
102119

103120
let node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common);
104121
let hash = self.db.insert(&node_rlp);
122+
self.cache.insert(hash, node_rlp);
105123

106124
Ok(hash)
107125
}
@@ -118,6 +136,7 @@ impl<'a> TrieDBMut<'a> {
118136

119137
let mut node_rlp = RlpNode::encoded(o_branch);
120138
let b_hash = self.db.insert(&node_rlp);
139+
self.cache.insert(b_hash, node_rlp);
121140

122141
new_child[new_partial.at(0) as usize] = Some(b_hash);
123142
new_child[new_path.at(0) as usize] = Some(self.insert_aux(
@@ -129,6 +148,7 @@ impl<'a> TrieDBMut<'a> {
129148

130149
node_rlp = RlpNode::encoded_until(RlpNode::Branch(partial, new_child.into()), common);
131150
let hash = self.db.insert(&node_rlp);
151+
self.cache.insert(hash, node_rlp);
132152

133153
Ok(hash)
134154
} else {
@@ -145,6 +165,7 @@ impl<'a> TrieDBMut<'a> {
145165
let new_branch = RlpNode::Branch(partial, children);
146166
let node_rlp = RlpNode::encoded(new_branch);
147167
let hash = self.db.insert(&node_rlp);
168+
self.cache.insert(hash, node_rlp);
148169

149170
Ok(hash)
150171
}
@@ -153,6 +174,7 @@ impl<'a> TrieDBMut<'a> {
153174
let node = RlpNode::Leaf(path, insert_value);
154175
let node_rlp = RlpNode::encoded(node);
155176
let hash = self.db.insert(&node_rlp);
177+
self.cache.insert(hash, node_rlp);
156178

157179
Ok(hash)
158180
}
@@ -162,6 +184,7 @@ impl<'a> TrieDBMut<'a> {
162184
let node = RlpNode::Leaf(path, insert_value);
163185
let node_rlp = RlpNode::encoded(node);
164186
let hash = self.db.insert(&node_rlp);
187+
self.cache.insert(hash, node_rlp);
165188

166189
Ok(hash)
167190
}

0 commit comments

Comments
 (0)