blob: be87d3c8af17df411f144ee3ddd51df453b3d956 [file]
use crate::args::kind::BenchmarkKindCommand;
use crate::{args::common::IggyBenchArgs, utils::client_factory::create_client_factory};
use async_trait::async_trait;
use futures::Future;
use iggy::client::{StreamClient, TopicClient};
use iggy::clients::client::IggyClient;
use iggy::compression::compression_algorithm::CompressionAlgorithm;
use iggy::error::IggyError;
use iggy::utils::expiry::IggyExpiry;
use iggy::utils::topic_size::MaxTopicSize;
use iggy_bench_report::benchmark_kind::BenchmarkKind;
use iggy_bench_report::individual_metrics::BenchmarkIndividualMetrics;
use integration::test_server::{login_root, ClientFactory};
use std::{pin::Pin, sync::Arc};
use tracing::info;
use super::consumer_benchmark::ConsumerBenchmark;
use super::consumer_group_benchmark::ConsumerGroupBenchmark;
use super::producer_and_consumer_benchmark::ProducerAndConsumerBenchmark;
use super::producer_and_consumer_group_benchmark::ProducerAndConsumerGroupBenchmark;
use super::producer_benchmark::ProducerBenchmark;
use super::producing_consumer_benchmark::EndToEndProducingConsumerBenchmark;
use super::producing_consumer_group_benchmark::EndToEndProducingConsumerGroupBenchmark;
pub type BenchmarkFutures = Result<
Vec<Pin<Box<dyn Future<Output = Result<BenchmarkIndividualMetrics, IggyError>> + Send>>>,
IggyError,
>;
impl From<IggyBenchArgs> for Box<dyn Benchmarkable> {
fn from(args: IggyBenchArgs) -> Self {
let client_factory = create_client_factory(&args);
match args.benchmark_kind {
BenchmarkKindCommand::PinnedProducer(_) => {
Box::new(ProducerBenchmark::new(Arc::new(args), client_factory))
}
BenchmarkKindCommand::PinnedConsumer(_) => {
Box::new(ConsumerBenchmark::new(Arc::new(args), client_factory))
}
BenchmarkKindCommand::PinnedProducerAndConsumer(_) => Box::new(
ProducerAndConsumerBenchmark::new(Arc::new(args), client_factory),
),
BenchmarkKindCommand::BalancedProducer(_) => {
Box::new(ProducerBenchmark::new(Arc::new(args), client_factory))
}
BenchmarkKindCommand::BalancedConsumerGroup(_) => {
Box::new(ConsumerGroupBenchmark::new(Arc::new(args), client_factory))
}
BenchmarkKindCommand::BalancedProducerAndConsumerGroup(_) => Box::new(
ProducerAndConsumerGroupBenchmark::new(Arc::new(args), client_factory),
),
BenchmarkKindCommand::EndToEndProducingConsumer(_) => Box::new(
EndToEndProducingConsumerBenchmark::new(Arc::new(args), client_factory),
),
BenchmarkKindCommand::EndToEndProducingConsumerGroup(_) => Box::new(
EndToEndProducingConsumerGroupBenchmark::new(Arc::new(args), client_factory),
),
_ => todo!(),
}
}
}
#[async_trait]
pub trait Benchmarkable {
async fn run(&mut self) -> BenchmarkFutures;
fn kind(&self) -> BenchmarkKind;
fn args(&self) -> &IggyBenchArgs;
fn client_factory(&self) -> &Arc<dyn ClientFactory>;
/// Below methods have common implementation for all benchmarks.
/// Initializes the streams and topics for the benchmark.
/// This method is called before the benchmark is executed.
async fn init_streams(&self) -> Result<(), IggyError> {
let start_stream_id = self.args().start_stream_id();
let number_of_streams = self.args().streams();
let topic_id: u32 = 1;
let partitions_count: u32 = self.args().number_of_partitions();
let client = self.client_factory().create_client().await;
let client = IggyClient::create(client, None, None);
login_root(&client).await;
let streams = client.get_streams().await?;
for i in 1..=number_of_streams {
let stream_id = start_stream_id + i;
if streams.iter().all(|s| s.id != stream_id) {
info!("Creating the test stream {}", stream_id);
let name = format!("stream {}", stream_id);
client.create_stream(&name, Some(stream_id)).await?;
let name = format!("topic {}", topic_id);
let max_topic_size = match self.args().max_topic_size() {
Some(size) => MaxTopicSize::Custom(size),
None => MaxTopicSize::Unlimited,
};
info!(
"Creating the test topic {} for stream {} with max topic size: {:?}",
topic_id, stream_id, max_topic_size
);
client
.create_topic(
&stream_id.try_into()?,
&name,
partitions_count,
CompressionAlgorithm::default(),
None,
None,
IggyExpiry::NeverExpire,
max_topic_size,
)
.await?;
}
}
Ok(())
}
async fn check_streams(&self) -> Result<(), IggyError> {
let start_stream_id = self.args().start_stream_id();
let number_of_streams = self.args().streams();
let client = self.client_factory().create_client().await;
let client = IggyClient::create(client, None, None);
login_root(&client).await;
let streams = client.get_streams().await?;
for i in 1..=number_of_streams {
let stream_id = start_stream_id + i;
if streams.iter().all(|s| s.id != stream_id) {
return Err(IggyError::ResourceNotFound(format!(
"Streams for testing are not properly initialized. Stream with id: {} is missing.",
stream_id
)));
}
}
Ok(())
}
/// Returns the total number of messages that will be sent or polled by the benchmark.
fn total_messages(&self) -> u64 {
let messages_per_batch = self.args().messages_per_batch();
let message_batches = self.args().message_batches();
let streams = self.args().streams();
(messages_per_batch * message_batches * streams) as u64
}
}