Skip to content

Commit

Permalink
First implementation of benchmark for store_transactions
Browse files Browse the repository at this point in the history
This compare the behavior of 'store_transactions' with differents
chunks sizes and leaving the transactions 'collect()' after the insert
or not.
  • Loading branch information
dlachaume authored and sfauvel committed May 6, 2024
1 parent 204c7e4 commit c611e45
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions mithril-signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ homepage = { workspace = true }
license = { workspace = true }
repository = { workspace = true }

[[bench]]
name = "cardano_transactions"
harness = false

[dependencies]
anyhow = "1.0.79"
async-trait = "0.1.77"
Expand Down Expand Up @@ -42,6 +46,7 @@ tokio = { version = "1.37.0", features = ["full"] }
tikv-jemallocator = { version = "0.5.4", optional = true }

[dev-dependencies]
criterion = { version = "0.5.1", features = ["html_reports", "async_tokio"] }
httpmock = "0.7.0"
mithril-common = { path = "../mithril-common" }
mockall = "0.12.1"
Expand Down
95 changes: 95 additions & 0 deletions mithril-signer/benches/cardano_transactions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use std::{path::Path, sync::Arc};

use criterion::{criterion_group, criterion_main, Criterion};
use mithril_common::{entities::CardanoTransaction, StdResult};
use mithril_persistence::sqlite::ConnectionBuilder;
use mithril_signer::{database::repository::CardanoTransactionRepository, TransactionStore};
use sqlite::ConnectionThreadSafe;

fn cardano_tx_db_connection() -> StdResult<ConnectionThreadSafe> {
let db_path = Path::new("./cardano_tx.db");

if db_path.exists() {
std::fs::remove_file(db_path)?;
}

let connection = ConnectionBuilder::open_file(db_path)
.with_migrations(mithril_signer::database::cardano_transaction_migration::get_migrations())
.build()?;
Ok(connection)
}

fn generate_transactions(nb_transactions: usize) -> Vec<CardanoTransaction> {
(0..nb_transactions)
.map(|i| {
CardanoTransaction::new(
format!("tx_hash-{}", i),
i as u64,
i as u64 + 1,
format!("block_hash-{}", i),
i as u64 + 2,
)
})
.collect()
}

fn bench_store_transactions_transactions(c: &mut Criterion) {
const NB_CARDANO_TRANSACTIONS: usize = 100000;
let runtime = tokio::runtime::Runtime::new().unwrap();

let mut group = c.benchmark_group("Create transactions");

group.bench_function("store_transactions", |bencher| {
bencher.to_async(&runtime).iter(|| async {
let connection = Arc::new(cardano_tx_db_connection().unwrap());
let repository = CardanoTransactionRepository::new(connection);
repository
.store_transactions(generate_transactions(NB_CARDANO_TRANSACTIONS))
.await
});
});

for chunks_size in [10, 50, 100, 200] {
group.bench_function(
format!("store_transactions_with_chunks_size = {}", chunks_size),
|bencher| {
bencher.to_async(&runtime).iter(|| async {
let connection = Arc::new(cardano_tx_db_connection().unwrap());
let repository = CardanoTransactionRepository::new(connection.clone());
repository
.store_transactions_with_chunks_size(
generate_transactions(NB_CARDANO_TRANSACTIONS),
chunks_size,
)
.await
});
},
);
}

for chunks_size in [10, 50, 100, 200] {
group.bench_function(
format!(
"store_transactions_with_chunks_size_and_collect = {}",
chunks_size
),
|bencher| {
bencher.to_async(&runtime).iter(|| async {
let connection = Arc::new(cardano_tx_db_connection().unwrap());
let repository = CardanoTransactionRepository::new(connection.clone());
repository
.store_transactions_with_chunks_size_and_collect(
generate_transactions(NB_CARDANO_TRANSACTIONS),
chunks_size,
)
.await
});
},
);
}

group.finish();
}

criterion_group!(benches, bench_store_transactions_transactions);
criterion_main!(benches);
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ impl CardanoTransactionRepository {
let records: Vec<CardanoTransactionRecord> =
transactions.into_iter().map(|tx| tx.into()).collect();

let provider = InsertCardanoTransactionProvider::new(&self.connection);
let filters = provider.get_insert_many_condition(records)?;
provider.find(filters)?.next();

Ok(vec![])
}

/// Create new [CardanoTransactionRecord]s in the database.
pub async fn create_transactions_and_collect<T: Into<CardanoTransactionRecord>>(
&self,
transactions: Vec<T>,
) -> StdResult<Vec<CardanoTransactionRecord>> {
let records: Vec<CardanoTransactionRecord> =
transactions.into_iter().map(|tx| tx.into()).collect();

let provider = InsertCardanoTransactionProvider::new(&self.connection);
let filters = provider.get_insert_many_condition(records)?;
let cursor = provider.find(filters)?;
Expand All @@ -138,6 +153,34 @@ impl CardanoTransactionRepository {
Ok(cursor.collect())
}

pub async fn store_transactions_with_chunks_size(
&self,
transactions: Vec<CardanoTransaction>,
chunks_size: usize,
) -> StdResult<()> {
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
for transactions_in_chunk in transactions.chunks(chunks_size) {
self.create_transactions(transactions_in_chunk.to_vec())
.await
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
}
Ok(())
}

pub async fn store_transactions_with_chunks_size_and_collect(
&self,
transactions: Vec<CardanoTransaction>,
chunks_size: usize,
) -> StdResult<()> {
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
for transactions_in_chunk in transactions.chunks(chunks_size) {
self.create_transactions_and_collect(transactions_in_chunk.to_vec())
.await
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
}
Ok(())
}

// TODO: remove this function when the Cardano transaction signature is based on block number instead of immutable number
async fn get_highest_block_number_for_immutable_number(
&self,
Expand Down Expand Up @@ -238,7 +281,7 @@ impl TransactionStore for CardanoTransactionRepository {
async fn store_transactions(&self, transactions: Vec<CardanoTransaction>) -> StdResult<()> {
// Chunk transactions to avoid an error when we exceed sqlite binding limitations
for transactions_in_chunk in transactions.chunks(100) {
self.create_transactions(transactions_in_chunk.to_vec())
self.create_transactions_and_collect(transactions_in_chunk.to_vec())
.await
.with_context(|| "CardanoTransactionRepository can not store transactions")?;
}
Expand Down

0 comments on commit c611e45

Please sign in to comment.