Skip to content

Commit 08bb12b

Browse files
authored
Merge pull request #1666 from input-output-hk/ensemble/1656/use-sqlite-transactions-insert-ctx
Add benchmark tests for storing Cardano transactions
2 parents 204c7e4 + 55869cd commit 08bb12b

File tree

8 files changed

+107
-24
lines changed

8 files changed

+107
-24
lines changed

Cargo.lock

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/mithril-persistence/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-persistence"
3-
version = "0.1.8"
3+
version = "0.1.9"
44
description = "Common types, interfaces, and utilities to persist data for Mithril nodes."
55
authors = { workspace = true }
66
edition = { workspace = true }

internal/mithril-persistence/src/sqlite/condition.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,20 @@ impl WhereCondition {
7070

7171
/// Turn the condition into a SQL string representation.
7272
pub fn expand(self) -> (String, Vec<Value>) {
73-
let mut expression = self.condition.expand();
73+
let expression = self.condition.expand();
7474
let parameters = self.parameters;
75-
let mut param_index = 1;
7675
//
7776
// Replace parameters placeholders by numerated parameters.
78-
loop {
79-
if !expression.contains("?*") {
80-
break;
77+
let mut final_expression = "".to_string();
78+
for (param_index, sql_part) in expression.split("?*").enumerate() {
79+
if param_index > 0 {
80+
final_expression.push('?');
81+
final_expression.push_str(&param_index.to_string());
8182
}
82-
expression = expression.replacen("?*", &format!("?{param_index}"), 1);
83-
param_index += 1;
83+
final_expression.push_str(sql_part);
8484
}
8585

86-
(expression, parameters)
86+
(final_expression, parameters)
8787
}
8888

8989
/// Instanciate a condition with a `IN` statement.

mithril-aggregator/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-aggregator"
3-
version = "0.5.3"
3+
version = "0.5.4"
44
description = "A Mithril Aggregator server"
55
authors = { workspace = true }
66
edition = { workspace = true }
@@ -9,6 +9,10 @@ homepage = { workspace = true }
99
license = { workspace = true }
1010
repository = { workspace = true }
1111

12+
[[bench]]
13+
name = "cardano_transactions_import"
14+
harness = false
15+
1216
[dependencies]
1317
anyhow = "1.0.79"
1418
async-trait = "0.1.77"
@@ -50,6 +54,7 @@ zstd = { version = "0.13.0", features = ["zstdmt"] }
5054
tikv-jemallocator = { version = "0.5.4", optional = true }
5155

5256
[dev-dependencies]
57+
criterion = { version = "0.5.1", features = ["html_reports", "async_tokio"] }
5358
httpmock = "0.7.0"
5459
mithril-common = { path = "../mithril-common", features = [
5560
"allow_skip_signer_certification",
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use criterion::{criterion_group, criterion_main, Criterion};
2+
use sqlite::ConnectionThreadSafe;
3+
use std::sync::Arc;
4+
5+
use mithril_aggregator::{
6+
database::repository::CardanoTransactionRepository, services::TransactionStore,
7+
};
8+
use mithril_common::{entities::CardanoTransaction, test_utils::TempDir};
9+
use mithril_persistence::sqlite::ConnectionBuilder;
10+
11+
fn cardano_tx_db_connection() -> ConnectionThreadSafe {
12+
let db_path =
13+
TempDir::create("aggregator_benches", "bench_store_transactions").join("cardano_tx.db");
14+
15+
if db_path.exists() {
16+
std::fs::remove_file(db_path.clone()).unwrap();
17+
}
18+
19+
ConnectionBuilder::open_file(&db_path)
20+
.with_migrations(
21+
mithril_aggregator::database::cardano_transaction_migration::get_migrations(),
22+
)
23+
.build()
24+
.unwrap()
25+
}
26+
27+
fn generate_transactions(nb_transactions: usize) -> Vec<CardanoTransaction> {
28+
(0..nb_transactions)
29+
.map(|i| {
30+
CardanoTransaction::new(
31+
format!("tx_hash-{}", i),
32+
i as u64,
33+
i as u64 + 1,
34+
format!("block_hash-{}", i),
35+
i as u64 + 2,
36+
)
37+
})
38+
.collect()
39+
}
40+
41+
fn bench_store_transactions(c: &mut Criterion) {
42+
const NB_CARDANO_TRANSACTIONS: usize = 1_000_000;
43+
let runtime = tokio::runtime::Runtime::new().unwrap();
44+
let transactions = generate_transactions(NB_CARDANO_TRANSACTIONS);
45+
46+
let mut group = c.benchmark_group("Store transactions");
47+
group.bench_function("store_transactions", |bencher| {
48+
bencher.to_async(&runtime).iter(|| async {
49+
let connection = Arc::new(cardano_tx_db_connection());
50+
let repository = CardanoTransactionRepository::new(connection);
51+
repository.store_transactions(transactions.clone()).await
52+
});
53+
});
54+
55+
group.finish();
56+
}
57+
58+
criterion_group! {
59+
name = benches;
60+
config = Criterion::default().sample_size(10);
61+
targets = bench_store_transactions
62+
}
63+
criterion_main!(benches);

mithril-aggregator/src/database/repository/cardano_transaction_repository.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,18 @@ impl TransactionStore for CardanoTransactionRepository {
242242
}
243243

244244
async fn store_transactions(&self, transactions: Vec<CardanoTransaction>) -> StdResult<()> {
245-
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
246-
for transactions_in_chunk in transactions.chunks(100) {
247-
self.create_transactions(transactions_in_chunk.to_vec())
248-
.await
249-
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
245+
const DB_TRANSACTION_SIZE: usize = 100000;
246+
for transactions_in_db_transaction_chunk in transactions.chunks(DB_TRANSACTION_SIZE) {
247+
self.connection.execute("BEGIN TRANSACTION;")?;
248+
249+
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
250+
for transactions_in_chunk in transactions_in_db_transaction_chunk.chunks(100) {
251+
self.create_transactions(transactions_in_chunk.to_vec())
252+
.await
253+
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
254+
}
255+
256+
self.connection.execute("END TRANSACTION;")?;
250257
}
251258
Ok(())
252259
}

mithril-signer/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mithril-signer"
3-
version = "0.2.131"
3+
version = "0.2.132"
44
description = "A Mithril Signer"
55
authors = { workspace = true }
66
edition = { workspace = true }

mithril-signer/src/database/repository/cardano_transaction_repository.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,18 @@ impl TransactionStore for CardanoTransactionRepository {
236236
}
237237

238238
async fn store_transactions(&self, transactions: Vec<CardanoTransaction>) -> StdResult<()> {
239-
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
240-
for transactions_in_chunk in transactions.chunks(100) {
241-
self.create_transactions(transactions_in_chunk.to_vec())
242-
.await
243-
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
239+
const DB_TRANSACTION_SIZE: usize = 100000;
240+
for transactions_in_db_transaction_chunk in transactions.chunks(DB_TRANSACTION_SIZE) {
241+
self.connection.execute("BEGIN TRANSACTION;")?;
242+
243+
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
244+
for transactions_in_chunk in transactions_in_db_transaction_chunk.chunks(100) {
245+
self.create_transactions(transactions_in_chunk.to_vec())
246+
.await
247+
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
248+
}
249+
250+
self.connection.execute("END TRANSACTION;")?;
244251
}
245252
Ok(())
246253
}

0 commit comments

Comments
 (0)