141 lines
3.7 KiB
Rust
141 lines
3.7 KiB
Rust
use aws_sdk_dynamodb::{types::AttributeValue, Client};
|
|
use log::{error, info};
|
|
use rand::{
|
|
rngs::{OsRng, StdRng},
|
|
Rng, SeedableRng,
|
|
};
|
|
|
|
use crate::{models::DynamoDbSimulationMetrics, time};
|
|
|
|
mod assertions;
|
|
mod operations;
|
|
mod utils;
|
|
|
|
pub struct Simulator<'a> {
|
|
dynamodb_client: &'a Client,
|
|
table_name: String,
|
|
attributes: u32,
|
|
partition_keys_vec: &'a [String],
|
|
rng: StdRng,
|
|
}
|
|
|
|
impl<'a> Simulator<'a> {
|
|
pub fn new(
|
|
dynamodb_client: &'a Client,
|
|
table_name: String,
|
|
attributes: u32,
|
|
partition_keys_vec: &'a [String],
|
|
) -> Simulator<'a> {
|
|
Simulator {
|
|
dynamodb_client,
|
|
table_name,
|
|
attributes,
|
|
partition_keys_vec,
|
|
rng: StdRng::from_seed(OsRng.gen()),
|
|
}
|
|
}
|
|
|
|
pub async fn simulate_read_operation(
|
|
&mut self,
|
|
metrics: &mut DynamoDbSimulationMetrics,
|
|
) -> anyhow::Result<()> {
|
|
info!("Performing READ Operation...");
|
|
let partition_key =
|
|
self.partition_keys_vec[self.rng.gen_range(0..self.partition_keys_vec.len())].clone();
|
|
let id = AttributeValue::S(partition_key.clone());
|
|
|
|
for i in 0..10 {
|
|
info!("Attempt {i}: Fetching existing item with partition key: {partition_key}");
|
|
|
|
match self.read_item(id.clone(), metrics, true).await? {
|
|
Some(_) => {
|
|
info!("Successfully read existing item with partition key: {partition_key}");
|
|
break;
|
|
}
|
|
None => {
|
|
error!("Unable to find existing item with partition key: {partition_key}");
|
|
if i == 9 {
|
|
error!(
|
|
"All attempts to fetch the existing item with partition key: {partition_key} failed!"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn simulate_write_operation(
|
|
&mut self,
|
|
metrics: &mut DynamoDbSimulationMetrics,
|
|
) -> anyhow::Result<()> {
|
|
info!("Performing WRITE operation...");
|
|
let benchmarking_item = self.put_item(metrics).await?;
|
|
let id = benchmarking_item.get_id();
|
|
|
|
self.assert_item_was_created(id.clone(), metrics).await?;
|
|
|
|
self.delete_item(id.clone(), metrics).await?;
|
|
|
|
self.assert_item_was_deleted(id, metrics).await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn simulate_update_operation(
|
|
&mut self,
|
|
metrics: &mut DynamoDbSimulationMetrics,
|
|
) -> anyhow::Result<()> {
|
|
info!("Performing UPDATE operation...");
|
|
let new_item = self.put_item(metrics).await?;
|
|
let id = new_item.get_id();
|
|
let partition_key = utils::extract_partition_key(id.clone());
|
|
let mut attempts_exhausted = false;
|
|
|
|
self.assert_item_was_created(id.clone(), metrics).await?;
|
|
self.update_item(id.clone(), metrics).await?;
|
|
|
|
let update_confirmation_time = time!(for i in 0..10 {
|
|
info!("Attempt {i}: Fetching updated item for partition key: {partition_key}...");
|
|
|
|
let updated_item = self.read_item(id.clone(), metrics, false).await?.unwrap();
|
|
|
|
let new_item_attribute_value = new_item
|
|
.get("1")
|
|
.cloned()
|
|
.unwrap()
|
|
.as_n()
|
|
.unwrap()
|
|
.to_string();
|
|
let updated_item_attribute_value = updated_item
|
|
.get("1")
|
|
.cloned()
|
|
.unwrap()
|
|
.as_n()
|
|
.unwrap()
|
|
.to_string();
|
|
|
|
if new_item_attribute_value != updated_item_attribute_value {
|
|
info!("Confirmed update for partition key: {partition_key}");
|
|
break;
|
|
} else {
|
|
error!("Update for partition key {partition_key} failed! Values are still equal!");
|
|
if i == 9 {
|
|
error!("Exhausted attempts to fetch updated item!");
|
|
attempts_exhausted = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
if !attempts_exhausted {
|
|
metrics.update_item_confirmation_time = Some(update_confirmation_time);
|
|
}
|
|
|
|
self.delete_item(id.clone(), metrics).await?;
|
|
self.assert_item_was_deleted(id, metrics).await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|