Skip to content

Commit 532b02f

Browse files
authored
Merge pull request #24 from Conflux-Chain/refactor/optimize-snapshot-memory
Refactor: reduce snapshot allocation overhead by reference sharing
2 parents a823e01 + 34f505b commit 532b02f

File tree

4 files changed

+67
-44
lines changed

4 files changed

+67
-44
lines changed

src/middlewares/versioned_flat_key_value/manager_impl.rs

+57-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{borrow::Borrow, collections::BTreeMap};
1+
use std::borrow::Borrow;
22

33
use crate::{
44
backends::TableReader,
@@ -7,25 +7,30 @@ use crate::{
77
traits::{
88
IsCompleted, KeyValueStoreBulksTrait, KeyValueStoreManager, KeyValueStoreRead, NeedNext,
99
},
10-
types::ValueEntry,
1110
StorageError,
1211
};
1312

1413
use super::{
1514
get_versioned_key,
15+
pending_part::{pending_schema::PendingKeyValueConfig, VersionedMap},
1616
table_schema::{HistoryChangeTable, HistoryIndicesTable, VersionedKeyValueSchema},
1717
HistoryIndexKey, PendingError, VersionedStore,
1818
};
1919

20-
pub struct SnapshotView<'db, T: VersionedKeyValueSchema> {
21-
pending_updates: Option<BTreeMap<T::Key, ValueEntry<T::Value>>>,
20+
#[cfg(test)]
21+
use crate::types::ValueEntry;
22+
#[cfg(test)]
23+
use std::collections::BTreeMap;
24+
25+
pub struct SnapshotView<'cache, 'db, T: VersionedKeyValueSchema> {
26+
pending_updates: Option<SnapshotPending<'cache, T>>,
2227
history: Option<SnapshotHistorical<'db, T>>,
2328
}
2429

2530
#[cfg(test)]
2631
const MIN_HISTORY_NUMBER_MINUS_ONE: u64 = 0;
2732

28-
impl<'db, T: VersionedKeyValueSchema> SnapshotView<'db, T> {
33+
impl<'cache, 'db, T: VersionedKeyValueSchema> SnapshotView<'cache, 'db, T> {
2934
#[cfg(test)]
3035
fn iter_history(&self) -> Result<BTreeMap<T::Key, ValueEntry<T::Value>>> {
3136
if let Some(ref history) = self.history {
@@ -94,7 +99,10 @@ impl<'db, T: VersionedKeyValueSchema> SnapshotView<'db, T> {
9499
pub fn iter(&self) -> Result<impl Iterator<Item = (T::Key, ValueEntry<T::Value>)>> {
95100
let mut map = self.iter_history()?;
96101

97-
if let Some(ref pending_map) = self.pending_updates {
102+
if let Some(ref pending_updates) = self.pending_updates {
103+
let pending_map = pending_updates
104+
.inner
105+
.get_versioned_store(pending_updates.commit_id)?;
98106
for (k, v) in pending_map {
99107
map.insert(k.clone(), v.clone());
100108
}
@@ -104,16 +112,28 @@ impl<'db, T: VersionedKeyValueSchema> SnapshotView<'db, T> {
104112
}
105113
}
106114

115+
struct SnapshotPending<'cache, T: VersionedKeyValueSchema> {
116+
commit_id: CommitID,
117+
inner: &'cache VersionedMap<PendingKeyValueConfig<T, CommitID>>,
118+
}
119+
107120
pub struct SnapshotHistorical<'db, T: VersionedKeyValueSchema> {
108121
history_number: HistoryNumber,
109122
history_index_table: TableReader<'db, HistoryIndicesTable<T>>,
110123
change_history_table: KeyValueStoreBulks<'db, HistoryChangeTable<T>>,
111124
}
112125

113-
impl<'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value> for SnapshotView<'db, T> {
126+
impl<'cache, 'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value>
127+
for SnapshotView<'cache, 'db, T>
128+
{
114129
fn get(&self, key: &T::Key) -> Result<Option<T::Value>> {
115-
if let Some(opt_v) = self.pending_updates.as_ref().and_then(|u| u.get(key)) {
116-
return Ok(opt_v.to_option());
130+
if let Some(pending_updates) = &self.pending_updates {
131+
let pending_optv = pending_updates
132+
.inner
133+
.get_versioned_key(&pending_updates.commit_id, key)?;
134+
if let Some(pending_v) = pending_optv {
135+
return Ok(pending_v.into_option());
136+
}
117137
}
118138

119139
if let Some(history) = &self.history {
@@ -129,8 +149,8 @@ impl<'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value> for Sn
129149
}
130150
}
131151

132-
impl<'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value>
133-
for Option<SnapshotView<'db, T>>
152+
impl<'cache, 'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value>
153+
for Option<SnapshotView<'cache, 'db, T>>
134154
{
135155
fn get(&self, key: &T::Key) -> Result<Option<T::Value>> {
136156
if let Some(view) = self {
@@ -144,38 +164,35 @@ impl<'db, T: VersionedKeyValueSchema> KeyValueStoreRead<T::Key, T::Value>
144164
impl<'cache, 'db, T: VersionedKeyValueSchema> KeyValueStoreManager<T::Key, T::Value, CommitID>
145165
for VersionedStore<'cache, 'db, T>
146166
{
147-
type Store = SnapshotView<'db, T>;
148-
fn get_versioned_store(&self, commit: &CommitID) -> Result<Self::Store> {
149-
let pending_res = self.pending_part.get_versioned_store(*commit);
150-
match pending_res {
151-
Ok(pending_map) => {
152-
let history = if let Some(history_commit) = self.pending_part.get_parent_of_root() {
153-
Some(SnapshotHistorical {
154-
history_number: self.get_history_number_by_commit_id(history_commit)?,
155-
history_index_table: self.history_index_table.clone(),
156-
change_history_table: self.change_history_table.clone(),
157-
})
158-
} else {
159-
None
160-
};
161-
Ok(SnapshotView {
162-
pending_updates: Some(pending_map),
163-
history,
164-
})
165-
}
166-
Err(PendingError::CommitIDNotFound(target_commit_id)) => {
167-
assert_eq!(target_commit_id, *commit);
168-
let history = SnapshotHistorical {
169-
history_number: self.get_history_number_by_commit_id(*commit)?,
167+
type Store<'a> = SnapshotView<'a, 'db, T> where Self: 'a;
168+
fn get_versioned_store<'a>(&'a self, commit: &CommitID) -> Result<Self::Store<'a>> {
169+
if self.pending_part.contains_commit_id(commit) {
170+
let history = if let Some(history_commit) = self.pending_part.get_parent_of_root() {
171+
Some(SnapshotHistorical {
172+
history_number: self.get_history_number_by_commit_id(history_commit)?,
170173
history_index_table: self.history_index_table.clone(),
171174
change_history_table: self.change_history_table.clone(),
172-
};
173-
Ok(SnapshotView {
174-
pending_updates: None,
175-
history: Some(history),
176175
})
177-
}
178-
Err(other_err) => Err(StorageError::PendingError(other_err)),
176+
} else {
177+
None
178+
};
179+
Ok(SnapshotView {
180+
pending_updates: Some(SnapshotPending {
181+
commit_id: *commit,
182+
inner: &*self.pending_part,
183+
}),
184+
history,
185+
})
186+
} else {
187+
let history = SnapshotHistorical {
188+
history_number: self.get_history_number_by_commit_id(*commit)?,
189+
history_index_table: self.history_index_table.clone(),
190+
change_history_table: self.change_history_table.clone(),
191+
};
192+
Ok(SnapshotView {
193+
pending_updates: None,
194+
history: Some(history),
195+
})
179196
}
180197
}
181198

src/middlewares/versioned_flat_key_value/pending_part/versioned_map.rs

+4
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ impl<S: PendingKeyValueSchema> VersionedMap<S> {
195195
}
196196
}
197197

198+
pub fn contains_commit_id(&self, commit_id: &S::CommitId) -> bool {
199+
self.tree.contains_commit_id(commit_id)
200+
}
201+
198202
pub fn get_versioned_store(&self, commit_id: S::CommitId) -> PendResult<KeyValueMap<S>, S> {
199203
// let query node to be self.current
200204
let mut guard = self.current.write();

src/middlewares/versioned_flat_key_value/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,9 @@ struct MockNode<T: VersionedKeyValueSchema> {
167167
impl<T: VersionedKeyValueSchema> KeyValueStoreManager<T::Key, T::Value, CommitID>
168168
for MockVersionedStore<T>
169169
{
170-
type Store = MockOneStore<T::Key, T::Value>;
170+
type Store<'a> = MockOneStore<T::Key, T::Value> where Self: 'a;
171171

172-
fn get_versioned_store(&self, commit: &CommitID) -> Result<Self::Store> {
172+
fn get_versioned_store<'a>(&'a self, commit: &CommitID) -> Result<Self::Store<'a>> {
173173
if let Some(pending_res) = self.pending.tree.get(commit) {
174174
Ok(MockOneStore::from_mock_map(&pending_res.store))
175175
} else if let Some((_, history_res)) = self.history.get(commit) {

src/traits.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ where
2525
V: 'static,
2626
C: 'static,
2727
{
28-
type Store: KeyValueStoreRead<K, V>;
28+
type Store<'a>: KeyValueStoreRead<K, V>
29+
where
30+
Self: 'a;
2931

3032
/// Get the key value store after the commit of given id
31-
fn get_versioned_store(&self, commit: &C) -> Result<Self::Store>;
33+
fn get_versioned_store<'a>(&'a self, commit: &C) -> Result<Self::Store<'a>>;
3234

3335
/// Start from the given commit, and iter changes backforward
3436
#[allow(clippy::type_complexity)]

0 commit comments

Comments
 (0)