11#![ allow( clippy:: arc_with_non_send_sync, dead_code) ]
22use clap:: Parser ;
3+ use core:: panic;
4+ use generation:: pick_index;
35use generation:: plan:: { Interaction , InteractionPlan , ResultSet } ;
4- use generation:: { pick_index, ArbitraryFrom } ;
5- use limbo_core:: { Database , Result } ;
6+ use limbo_core:: { Database , LimboError , Result } ;
67use model:: table:: Value ;
78use rand:: prelude:: * ;
89use rand_chacha:: ChaCha8Rng ;
@@ -36,10 +37,12 @@ fn main() {
3637
3738 let db_path = output_dir. join ( "simulator.db" ) ;
3839 let plan_path = output_dir. join ( "simulator.plan" ) ;
40+ let history_path = output_dir. join ( "simulator.history" ) ;
3941
4042 // Print the seed, the locations of the database and the plan file
4143 log:: info!( "database path: {:?}" , db_path) ;
4244 log:: info!( "simulator plan path: {:?}" , plan_path) ;
45+ log:: info!( "simulator history path: {:?}" , history_path) ;
4346 log:: info!( "seed: {}" , seed) ;
4447
4548 std:: panic:: set_hook ( Box :: new ( move |info| {
@@ -73,28 +76,34 @@ fn main() {
7376 std:: panic:: catch_unwind ( || run_simulation ( seed, & cli_opts, & db_path, & plan_path) ) ;
7477
7578 match ( result, result2) {
76- ( Ok ( Ok ( _ ) ) , Err ( _) ) => {
79+ ( Ok ( ExecutionResult { error : None , .. } ) , Err ( _) ) => {
7780 log:: error!( "doublecheck failed! first run succeeded, but second run panicked." ) ;
7881 }
79- ( Ok ( Err ( _) ) , Err ( _) ) => {
82+ ( Ok ( ExecutionResult { error : Some ( _) , .. } ) , Err ( _) ) => {
8083 log:: error!(
8184 "doublecheck failed! first run failed assertion, but second run panicked."
8285 ) ;
8386 }
84- ( Err ( _) , Ok ( Ok ( _ ) ) ) => {
87+ ( Err ( _) , Ok ( ExecutionResult { error : None , .. } ) ) => {
8588 log:: error!( "doublecheck failed! first run panicked, but second run succeeded." ) ;
8689 }
87- ( Err ( _) , Ok ( Err ( _) ) ) => {
90+ ( Err ( _) , Ok ( ExecutionResult { error : Some ( _) , .. } ) ) => {
8891 log:: error!(
8992 "doublecheck failed! first run panicked, but second run failed assertion."
9093 ) ;
9194 }
92- ( Ok ( Ok ( _) ) , Ok ( Err ( _) ) ) => {
95+ (
96+ Ok ( ExecutionResult { error : None , .. } ) ,
97+ Ok ( ExecutionResult { error : Some ( _) , .. } ) ,
98+ ) => {
9399 log:: error!(
94100 "doublecheck failed! first run succeeded, but second run failed assertion."
95101 ) ;
96102 }
97- ( Ok ( Err ( _) ) , Ok ( Ok ( _) ) ) => {
103+ (
104+ Ok ( ExecutionResult { error : Some ( _) , .. } ) ,
105+ Ok ( ExecutionResult { error : None , .. } ) ,
106+ ) => {
98107 log:: error!(
99108 "doublecheck failed! first run failed assertion, but second run succeeded."
100109 ) ;
@@ -122,18 +131,32 @@ fn main() {
122131 std:: fs:: rename ( & old_db_path, & db_path) . unwrap ( ) ;
123132 std:: fs:: rename ( & old_plan_path, & plan_path) . unwrap ( ) ;
124133 } else if let Ok ( result) = result {
125- match result {
126- Ok ( _) => {
134+ // No panic occurred, so write the history to a file
135+ let f = std:: fs:: File :: create ( & history_path) . unwrap ( ) ;
136+ let mut f = std:: io:: BufWriter :: new ( f) ;
137+ for execution in result. history . history . iter ( ) {
138+ writeln ! (
139+ f,
140+ "{} {} {}" ,
141+ execution. connection_index, execution. interaction_index, execution. secondary_index
142+ )
143+ . unwrap ( ) ;
144+ }
145+
146+ match result. error {
147+ None => {
127148 log:: info!( "simulation completed successfully" ) ;
128149 }
129- Err ( e) => {
150+ Some ( e) => {
130151 log:: error!( "simulation failed: {:?}" , e) ;
131152 }
132153 }
133154 }
155+
134156 // Print the seed, the locations of the database and the plan file at the end again for easily accessing them.
135157 println ! ( "database path: {:?}" , db_path) ;
136158 println ! ( "simulator plan path: {:?}" , plan_path) ;
159+ println ! ( "simulator history path: {:?}" , history_path) ;
137160 println ! ( "seed: {}" , seed) ;
138161}
139162
@@ -142,7 +165,7 @@ fn run_simulation(
142165 cli_opts : & SimulatorCLI ,
143166 db_path : & Path ,
144167 plan_path : & Path ,
145- ) -> Result < ( ) > {
168+ ) -> ExecutionResult {
146169 let mut rng = ChaCha8Rng :: seed_from_u64 ( seed) ;
147170
148171 let ( create_percent, read_percent, write_percent, delete_percent) = {
@@ -160,21 +183,15 @@ fn run_simulation(
160183 } ;
161184
162185 if cli_opts. minimum_size < 1 {
163- return Err ( limbo_core:: LimboError :: InternalError (
164- "minimum size must be at least 1" . to_string ( ) ,
165- ) ) ;
186+ panic ! ( "minimum size must be at least 1" ) ;
166187 }
167188
168189 if cli_opts. maximum_size < 1 {
169- return Err ( limbo_core:: LimboError :: InternalError (
170- "maximum size must be at least 1" . to_string ( ) ,
171- ) ) ;
190+ panic ! ( "maximum size must be at least 1" ) ;
172191 }
173192
174193 if cli_opts. maximum_size < cli_opts. minimum_size {
175- return Err ( limbo_core:: LimboError :: InternalError (
176- "maximum size must be greater than or equal to minimum size" . to_string ( ) ,
177- ) ) ;
194+ panic ! ( "maximum size must be greater than or equal to minimum size" ) ;
178195 }
179196
180197 let opts = SimulatorOpts {
@@ -212,7 +229,7 @@ fn run_simulation(
212229
213230 log:: info!( "Generating database interaction plan..." ) ;
214231 let mut plans = ( 1 ..=env. opts . max_connections )
215- . map ( |_| InteractionPlan :: arbitrary_from ( & mut env. rng . clone ( ) , & env) )
232+ . map ( |_| InteractionPlan :: arbitrary_from ( & mut env. rng . clone ( ) , & mut env) )
216233 . collect :: < Vec < _ > > ( ) ;
217234
218235 let mut f = std:: fs:: File :: create ( plan_path) . unwrap ( ) ;
@@ -224,9 +241,6 @@ fn run_simulation(
224241 log:: info!( "Executing database interaction plan..." ) ;
225242
226243 let result = execute_plans ( & mut env, & mut plans) ;
227- if result. is_err ( ) {
228- log:: error!( "error executing plans: {:?}" , result. as_ref( ) . err( ) ) ;
229- }
230244
231245 env. io . print_stats ( ) ;
232246
@@ -235,23 +249,76 @@ fn run_simulation(
235249 result
236250}
237251
238- fn execute_plans ( env : & mut SimulatorEnv , plans : & mut [ InteractionPlan ] ) -> Result < ( ) > {
252+ struct Execution {
253+ connection_index : usize ,
254+ interaction_index : usize ,
255+ secondary_index : usize ,
256+ }
257+
258+ impl Execution {
259+ fn new ( connection_index : usize , interaction_index : usize , secondary_index : usize ) -> Self {
260+ Self {
261+ connection_index,
262+ interaction_index,
263+ secondary_index,
264+ }
265+ }
266+ }
267+
268+ struct ExecutionHistory {
269+ history : Vec < Execution > ,
270+ }
271+
272+ impl ExecutionHistory {
273+ fn new ( ) -> Self {
274+ Self {
275+ history : Vec :: new ( ) ,
276+ }
277+ }
278+ }
279+
280+ struct ExecutionResult {
281+ history : ExecutionHistory ,
282+ error : Option < limbo_core:: LimboError > ,
283+ }
284+
285+ impl ExecutionResult {
286+ fn new ( history : ExecutionHistory , error : Option < LimboError > ) -> Self {
287+ Self { history, error }
288+ }
289+ }
290+
291+ fn execute_plans ( env : & mut SimulatorEnv , plans : & mut [ InteractionPlan ] ) -> ExecutionResult {
292+ let mut history = ExecutionHistory :: new ( ) ;
239293 let now = std:: time:: Instant :: now ( ) ;
240294 // todo: add history here by recording which interaction was executed at which tick
241295 for _tick in 0 ..env. opts . ticks {
242296 // Pick the connection to interact with
243297 let connection_index = pick_index ( env. connections . len ( ) , & mut env. rng ) ;
298+ history. history . push ( Execution :: new (
299+ connection_index,
300+ plans[ connection_index] . interaction_pointer ,
301+ plans[ connection_index] . secondary_pointer ,
302+ ) ) ;
244303 // Execute the interaction for the selected connection
245- execute_plan ( env, connection_index, plans) ?;
304+ match execute_plan ( env, connection_index, plans) {
305+ Ok ( _) => { }
306+ Err ( err) => {
307+ return ExecutionResult :: new ( history, Some ( err) ) ;
308+ }
309+ }
246310 // Check if the maximum time for the simulation has been reached
247311 if now. elapsed ( ) . as_secs ( ) >= env. opts . max_time_simulation as u64 {
248- return Err ( limbo_core:: LimboError :: InternalError (
249- "maximum time for simulation reached" . into ( ) ,
250- ) ) ;
312+ return ExecutionResult :: new (
313+ history,
314+ Some ( limbo_core:: LimboError :: InternalError (
315+ "maximum time for simulation reached" . into ( ) ,
316+ ) ) ,
317+ ) ;
251318 }
252319 }
253320
254- Ok ( ( ) )
321+ ExecutionResult :: new ( history , None )
255322}
256323
257324fn execute_plan (
0 commit comments