@@ -28,6 +28,9 @@ struct Biases {
28
28
/// When generating a key, whether it should be one that was appeared somewhere or a brand new
29
29
/// key.
30
30
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 > ,
31
34
/// When executing a workload iteration, this is the probability of executing a commit.
32
35
commit : u8 ,
33
36
/// When executing a workload iteration, this is the probability of executing a commit
@@ -53,10 +56,27 @@ impl Biases {
53
56
panic ! ( "Sum of `commit-crash`, `rollback` and `rollback-crash` must be lower than 100" ) ;
54
57
} ;
55
58
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
+
56
75
Self {
57
76
delete : ( delete as f64 ) / 100.0 ,
58
77
overflow : ( overflow as f64 ) / 100.0 ,
59
78
new_key : ( new_key as f64 ) / 100.0 ,
79
+ new_key_distribution,
60
80
commit,
61
81
commit_crash,
62
82
rollback,
@@ -147,10 +167,8 @@ impl WorkloadState {
147
167
148
168
/// Returns a KeyValueChange with a new key, a deleted or a modified one.
149
169
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.
153
170
let mut key = [ 0 ; 32 ] ;
171
+ // Generate a Delete KeyValueChange
154
172
if !self . committed . state . is_empty ( ) && self . rng . gen_bool ( self . biases . delete ) {
155
173
loop {
156
174
self . rng . fill_bytes ( & mut key) ;
@@ -160,15 +178,31 @@ impl WorkloadState {
160
178
}
161
179
}
162
180
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 ) {
164
188
loop {
165
189
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
+
166
199
if !self . committed . state . contains_key ( & key) {
167
200
return KeyValueChange :: Insert ( key, self . gen_value ( ) ) ;
168
201
}
169
202
}
170
203
}
171
204
205
+ // Generate an update KeyValueChange
172
206
loop {
173
207
self . rng . fill_bytes ( & mut key) ;
174
208
if let Some ( ( next_key, _) ) = self . committed . state . get_next ( & key) {
@@ -178,14 +212,12 @@ impl WorkloadState {
178
212
}
179
213
180
214
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.
185
217
let len = if self . rng . gen_bool ( self . biases . overflow ) {
186
- 32 * 1024
218
+ self . rng . gen_range ( 1333 .. 32 * 1024 )
187
219
} else {
188
- 32
220
+ self . rng . gen_range ( 1 .. 1333 )
189
221
} ;
190
222
let mut value = vec ! [ 0 ; len] ;
191
223
self . rng . fill_bytes ( & mut value) ;
@@ -233,7 +265,7 @@ pub struct Workload {
233
265
/// Whether to randomly sample the state after every crash or rollback.
234
266
sample_snapshot : bool ,
235
267
/// The max number of commits involved in a rollback.
236
- max_rollback_commits : usize ,
268
+ max_rollback_commits : u32 ,
237
269
/// If `Some` there are rollbacks waiting to be applied.
238
270
scheduled_rollbacks : ScheduledRollbacks ,
239
271
}
@@ -455,16 +487,8 @@ impl Workload {
455
487
Ok ( ( ) )
456
488
}
457
489
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
-
466
490
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 ;
468
492
if n_commits_to_rollback == 0 {
469
493
trace ! ( "No available commits to perform rollback with" ) ;
470
494
return Ok ( ( ) ) ;
@@ -593,7 +617,6 @@ impl Workload {
593
617
let agent_died_or_timeout = timeout ( TOLERANCE , agent. died ( ) ) . await ;
594
618
self . agent . take ( ) . unwrap ( ) . teardown ( ) . await ;
595
619
if let Err ( Elapsed { .. } ) = agent_died_or_timeout {
596
- // TODO: flag for investigation.
597
620
return Err ( anyhow:: anyhow!( "agent did not die" ) ) ;
598
621
}
599
622
@@ -740,7 +763,11 @@ impl Workload {
740
763
assert ! ( self . agent. is_none( ) ) ;
741
764
controller:: spawn_agent_into ( & mut self . agent ) . await ?;
742
765
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
+ } ;
744
771
self . agent
745
772
. as_mut ( )
746
773
. unwrap ( )
0 commit comments