Skip to content

Commit e646377

Browse files
committed
wip: implement a resource pool
1 parent d525625 commit e646377

File tree

3 files changed

+74
-11
lines changed

3 files changed

+74
-11
lines changed

Diff for: mithril-aggregator/src/services/prover.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ use std::{
44
collections::{BTreeMap, BTreeSet, HashMap},
55
sync::Arc,
66
};
7-
use tokio::sync::Mutex;
87

98
use mithril_common::{
109
crypto_helper::{MKMap, MKMapNode, MKTree},
1110
entities::{
1211
BlockRange, CardanoDbBeacon, CardanoTransaction, CardanoTransactionsSetProof,
1312
TransactionHash,
1413
},
14+
resource_pool::ResourcePool,
1515
signable_builder::BlockRangeRootRetriever,
1616
StdResult,
1717
};
@@ -62,7 +62,7 @@ pub trait TransactionsRetriever: Sync + Send {
6262
pub struct MithrilProverService {
6363
transaction_retriever: Arc<dyn TransactionsRetriever>,
6464
block_range_root_retriever: Arc<dyn BlockRangeRootRetriever>,
65-
mk_map_cache: Mutex<Option<MKMap<BlockRange, MKMapNode<BlockRange>>>>,
65+
mk_map_cache: ResourcePool<MKMap<BlockRange, MKMapNode<BlockRange>>>,
6666
}
6767

6868
impl MithrilProverService {
@@ -74,7 +74,7 @@ impl MithrilProverService {
7474
Self {
7575
transaction_retriever,
7676
block_range_root_retriever,
77-
mk_map_cache: Mutex::new(None),
77+
mk_map_cache: ResourcePool::new(vec![]),
7878
}
7979
}
8080

@@ -139,9 +139,9 @@ impl ProverService for MithrilProverService {
139139
let mk_trees = BTreeMap::from_iter(mk_trees?);
140140

141141
// 3 - Compute block range roots Merkle map
142+
// TODO: the cache computation should be done in the state machine only when new artifact is produced and at node startup
142143
self.compute_cache(up_to).await?;
143-
let mut mk_map = self.mk_map_cache.lock().await;
144-
let mk_map = mk_map.as_mut().unwrap();
144+
let mut mk_map = self.mk_map_cache.acquire_resource().await;
145145

146146
// 4 - Enrich the Merkle map with the block ranges Merkle trees
147147
for (block_range, mk_tree) in mk_trees {
@@ -150,6 +150,8 @@ impl ProverService for MithrilProverService {
150150

151151
// 5 - Compute the proof for all transactions
152152
if let Ok(mk_proof) = mk_map.compute_proof(transaction_hashes) {
153+
self.mk_map_cache.return_resource(mk_map).await;
154+
153155
let transaction_hashes_certified: Vec<TransactionHash> = transaction_hashes
154156
.iter()
155157
.filter(|hash| mk_proof.contains(&hash.as_str().into()).is_ok())
@@ -166,22 +168,27 @@ impl ProverService for MithrilProverService {
166168
}
167169

168170
async fn compute_cache(&self, up_to: &CardanoDbBeacon) -> StdResult<()> {
169-
let mut mk_map = self.mk_map_cache.lock().await;
170-
if mk_map.is_none() {
171-
println!("Computing Merkle map from block range roots");
171+
if self.mk_map_cache.count().await == 0 {
172+
println!("Computing Merkle map cache from block range roots");
172173
let mk_map_cache = self
173174
.block_range_root_retriever
174175
.compute_merkle_map_from_block_range_roots(up_to.immutable_file_number)
175176
.await?;
176-
mk_map.replace(mk_map_cache);
177+
for i in 0..100 {
178+
println!("Computing Merkle map cache from block range roots: {}", i);
179+
self.mk_map_cache
180+
.return_resource(mk_map_cache.clone())
181+
.await;
182+
}
183+
self.mk_map_cache.return_resource(mk_map_cache).await;
184+
println!("Done computing Merkle map cache from block range roots");
177185
}
178186

179187
Ok(())
180188
}
181189

182190
async fn clear_cache(&self) -> StdResult<()> {
183-
let mut mk_map = self.mk_map_cache.lock().await;
184-
mk_map.take();
191+
self.mk_map_cache.drain().await;
185192

186193
Ok(())
187194
}

Diff for: mithril-common/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub mod entities;
5959
pub mod era;
6060
pub mod messages;
6161
pub mod protocol;
62+
pub mod resource_pool;
6263
pub mod signable_builder;
6364

6465
cfg_test_tools! {

Diff for: mithril-common/src/resource_pool.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! Resource pool implementation
2+
// TODO: automatic return resource to the pool with Guard and Drop
3+
// TODO: avoid returning stale resources
4+
// TODO: add tests
5+
use std::{
6+
collections::VecDeque,
7+
sync::{Condvar, Mutex},
8+
};
9+
10+
/// Resource pool
11+
pub struct ResourcePool<T: Send + Sync> {
12+
resources: Mutex<VecDeque<T>>,
13+
not_empty: Condvar,
14+
}
15+
16+
impl<T: Send + Sync> ResourcePool<T> {
17+
/// Create a new resource pool
18+
pub fn new(resources: Vec<T>) -> Self {
19+
Self {
20+
resources: Mutex::new(resources.into()),
21+
not_empty: Condvar::new(),
22+
}
23+
}
24+
25+
/// Acquire a resource from the pool
26+
pub async fn acquire_resource(&self) -> T {
27+
let mut resources = self.resources.lock().unwrap();
28+
while resources.is_empty() {
29+
resources = self.not_empty.wait(resources).unwrap();
30+
}
31+
resources.pop_front().unwrap()
32+
}
33+
34+
/// Return a resource to the pool
35+
// TODO: automatic return resource to the pool with Guard and Drop
36+
pub async fn return_resource(&self, resource: T) {
37+
let mut resources = self.resources.lock().unwrap();
38+
resources.push_back(resource);
39+
self.not_empty.notify_one();
40+
}
41+
42+
/// Drain the pool
43+
pub async fn drain(&self) {
44+
let mut resources = self.resources.lock().unwrap();
45+
let _ = resources.drain(..).collect::<Vec<_>>();
46+
}
47+
48+
/// Count the resources in the pool
49+
pub async fn count(&self) -> usize {
50+
self.resources.lock().unwrap().len()
51+
}
52+
}
53+
54+
#[cfg(test)]
55+
mod tests {}

0 commit comments

Comments
 (0)