Skip to content

Commit 6ac611e

Browse files
committed
chore(torture): address multiple left todos
+ more sophisticated new key generation + more sophisticated value generation + use the `max_rollback_blocks` cli argument as nomt option for `max_rollback_log_len`
1 parent b222b2c commit 6ac611e

File tree

5 files changed

+60
-27
lines changed

5 files changed

+60
-27
lines changed

torture/src/agent.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,12 @@ impl Agent {
234234
o.path(workdir.join("nomt_db"));
235235
o.bitbox_seed(init.bitbox_seed);
236236
o.hashtable_buckets(500_000);
237-
o.rollback(init.rollback);
237+
if let Some(n_commits) = init.rollback {
238+
o.rollback(true);
239+
o.max_rollback_log_len(n_commits);
240+
} else {
241+
o.rollback(false);
242+
}
238243
let nomt = Nomt::open(o)?;
239244
Ok(Self {
240245
workdir,

torture/src/message.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ pub struct InitPayload {
4747
/// Only used upon creation a new NOMT db.
4848
pub bitbox_seed: [u8; 16],
4949
/// Whether the agent is supposed to handle rollbacks.
50-
pub rollback: bool,
50+
/// If `Some`, the maximum amount of supported blocks in a single rollback is specified.
51+
pub rollback: Option<u32>,
5152
}
5253

5354
/// The parameters for the [`ToAgent::Commit`] message.

torture/src/supervisor/cli.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ pub struct WorkloadParams {
9999
///
100100
/// The effective number of commits used for each rollback is randomly generated in the range
101101
/// 0..max_rollback_commits.
102-
#[clap(default_value = "10")]
102+
#[clap(default_value = "100")]
103103
#[arg(long = "max-rollback-commits")]
104-
pub max_rollback_commits: usize,
104+
pub max_rollback_commits: u32,
105105

106106
/// Whether to ensure the correct application of the changest after every commit.
107107
#[clap(default_value = "false")]

torture/src/supervisor/controller.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl SpawnedAgentController {
3333
workdir: String,
3434
workload_id: u64,
3535
bitbox_seed: [u8; 16],
36-
rollback: bool,
36+
rollback: Option<u32>,
3737
) -> Result<()> {
3838
// Assign a unique ID to the agent.
3939
static AGENT_COUNT: AtomicUsize = AtomicUsize::new(0);

torture/src/supervisor/workload.rs

+49-22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ struct Biases {
2828
/// When generating a key, whether it should be one that was appeared somewhere or a brand new
2929
/// key.
3030
new_key: f64,
31+
/// Distribution used when generating a new key to decide how many bytes needs to be shared
32+
/// with an already existing key.
33+
new_key_distribution: WeightedIndex<usize>,
3134
/// When executing a workload iteration, this is the probability of executing a commit.
3235
commit: u8,
3336
/// When executing a workload iteration, this is the probability of executing a commit
@@ -53,10 +56,27 @@ impl Biases {
5356
panic!("Sum of `commit-crash`, `rollback` and `rollback-crash` must be lower than 100");
5457
};
5558

59+
// When generating a new key to be inserted in the database,
60+
// this distribution will generate the key.
61+
// There is a 25% chance that the key is completely random,
62+
// half of the 25% chance that the first byte will be shared with an existing key,
63+
// one third of the 25% chance that two bytes will be shared with an existing key,
64+
// and so on.
65+
//
66+
// There are:
67+
// + 25% probability of having a key with 0 shared bytes.
68+
// + 48% probability of having a key with 1 to 9 shared bytes.
69+
// + 27% probability of having a key with more than 10 shared bytes.
70+
//
71+
// UNWRAP: provided iterator is not empty, no item is lower than zero
72+
// and the total sum is greater than one.
73+
let new_key_distribution = WeightedIndex::new((1usize..33).map(|x| (32 * 32) / x)).unwrap();
74+
5675
Self {
5776
delete: (delete as f64) / 100.0,
5877
overflow: (overflow as f64) / 100.0,
5978
new_key: (new_key as f64) / 100.0,
79+
new_key_distribution,
6080
commit,
6181
commit_crash,
6282
rollback,
@@ -147,10 +167,8 @@ impl WorkloadState {
147167

148168
/// Returns a KeyValueChange with a new key, a deleted or a modified one.
149169
fn gen_key_value_change(&mut self) -> KeyValueChange {
150-
// TODO: sophisticated key generation.
151-
//
152-
// - Pick a key that was already generated before, but generate a key that shares some bits.
153170
let mut key = [0; 32];
171+
// Generate a Delete KeyValueChange
154172
if !self.committed.state.is_empty() && self.rng.gen_bool(self.biases.delete) {
155173
loop {
156174
self.rng.fill_bytes(&mut key);
@@ -160,15 +178,31 @@ impl WorkloadState {
160178
}
161179
}
162180

163-
if self.committed.state.is_empty() || self.rng.gen_bool(self.biases.new_key) {
181+
// Generate a new key KeyValueChange
182+
if self.committed.state.is_empty() {
183+
self.rng.fill_bytes(&mut key);
184+
return KeyValueChange::Insert(key, self.gen_value());
185+
}
186+
187+
if self.rng.gen_bool(self.biases.new_key) {
164188
loop {
165189
self.rng.fill_bytes(&mut key);
190+
191+
let Some(next_key) = self.committed.state.get_next(&key).map(|(k, _)| *k) else {
192+
continue;
193+
};
194+
195+
let common_bytes =
196+
self.rng.sample(self.biases.new_key_distribution.clone()) as usize;
197+
key[..common_bytes].copy_from_slice(&next_key[..common_bytes]);
198+
166199
if !self.committed.state.contains_key(&key) {
167200
return KeyValueChange::Insert(key, self.gen_value());
168201
}
169202
}
170203
}
171204

205+
// Generate an update KeyValueChange
172206
loop {
173207
self.rng.fill_bytes(&mut key);
174208
if let Some((next_key, _)) = self.committed.state.get_next(&key) {
@@ -178,14 +212,12 @@ impl WorkloadState {
178212
}
179213

180214
fn gen_value(&mut self) -> Vec<u8> {
181-
// TODO: sophisticated value generation.
182-
//
183-
// - Different power of two sizes.
184-
// - Change it to be a non-even.
215+
// MAX_LEAF_VALUE_SIZE is 1332,
216+
// thus every value size bigger than this will create an overflow value.
185217
let len = if self.rng.gen_bool(self.biases.overflow) {
186-
32 * 1024
218+
self.rng.gen_range(1333..32 * 1024)
187219
} else {
188-
32
220+
self.rng.gen_range(1..1333)
189221
};
190222
let mut value = vec![0; len];
191223
self.rng.fill_bytes(&mut value);
@@ -233,7 +265,7 @@ pub struct Workload {
233265
/// Whether to randomly sample the state after every crash or rollback.
234266
sample_snapshot: bool,
235267
/// The max number of commits involved in a rollback.
236-
max_rollback_commits: usize,
268+
max_rollback_commits: u32,
237269
/// If `Some` there are rollbacks waiting to be applied.
238270
scheduled_rollbacks: ScheduledRollbacks,
239271
}
@@ -455,16 +487,8 @@ impl Workload {
455487
Ok(())
456488
}
457489

458-
fn commits_to_rollback(&mut self) -> usize {
459-
// TODO: n_commits should also depend on the max rollback supported by NOMT.
460-
std::cmp::min(
461-
self.state.rng.gen_range(1..self.max_rollback_commits) as usize,
462-
self.state.committed.sync_seqn as usize,
463-
)
464-
}
465-
466490
async fn schedule_rollback(&mut self, should_crash: bool) -> anyhow::Result<()> {
467-
let n_commits_to_rollback = self.commits_to_rollback();
491+
let n_commits_to_rollback = self.state.rng.gen_range(1..self.max_rollback_commits) as usize;
468492
if n_commits_to_rollback == 0 {
469493
trace!("No available commits to perform rollback with");
470494
return Ok(());
@@ -593,7 +617,6 @@ impl Workload {
593617
let agent_died_or_timeout = timeout(TOLERANCE, agent.died()).await;
594618
self.agent.take().unwrap().teardown().await;
595619
if let Err(Elapsed { .. }) = agent_died_or_timeout {
596-
// TODO: flag for investigation.
597620
return Err(anyhow::anyhow!("agent did not die"));
598621
}
599622

@@ -740,7 +763,11 @@ impl Workload {
740763
assert!(self.agent.is_none());
741764
controller::spawn_agent_into(&mut self.agent).await?;
742765
let workdir = self.workdir.path().display().to_string();
743-
let rollback = self.state.biases.rollback > 0;
766+
let rollback = if self.state.biases.rollback > 0 {
767+
Some(self.max_rollback_commits)
768+
} else {
769+
None
770+
};
744771
self.agent
745772
.as_mut()
746773
.unwrap()

0 commit comments

Comments
 (0)