persistcli/
maelstrom.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! An adaptor to Jepsen Maelstrom's txn-list-append workload
11
12use mz_ore::{task::RuntimeExt, url::SensitiveUrl};
13use tokio::runtime::Handle;
14use tracing::Span;
15
16use crate::maelstrom::node::Service;
17pub mod api;
18pub mod node;
19pub mod services;
20pub mod txn_list_append_multi;
21pub mod txn_list_append_single;
22
23/// An adaptor to Jepsen Maelstrom's txn-list-append workload
24///
25/// Example usage:
26///
27///     cargo build --example persistcli && java -jar /path/to/maelstrom.jar test -w txn-list-append --bin ./target/debug/examples/persistcli maelstrom
28///
29/// The [Maelstrom docs] are a great place to start for an understanding of
30/// the specifics of what's going on here.
31///
32/// [maelstrom docs]: https://github.com/jepsen-io/maelstrom/tree/v0.2.1#documentation
33#[derive(Debug, Clone, clap::Parser)]
34pub struct Args {
35    /// Blob to use, defaults to Maelstrom lin-kv service
36    #[clap(long)]
37    blob_uri: Option<SensitiveUrl>,
38
39    /// Consensus to use, defaults to Maelstrom lin-kv service
40    #[clap(long)]
41    consensus_uri: Option<SensitiveUrl>,
42
43    /// How much unreliability to inject into Blob and Consensus usage
44    ///
45    /// This value must be in [0, 1]. 0 means no-op, 1 means complete
46    /// unreliability.
47    #[clap(long, default_value_t = 0.05)]
48    unreliability: f64,
49}
50
51pub async fn run<S: Service + 'static>(args: Args) -> Result<(), anyhow::Error> {
52    // Persist internally has a bunch of sanity check assertions. If
53    // maelstrom tickles one of these, we very much want to bubble this
54    // up into a process exit with non-0 status. It's surprisingly
55    // tricky to be confident that we're not accidentally swallowing
56    // panics in async tasks (in fact there was a bug that did exactly
57    // this at one point), so abort on any panics to be extra sure.
58    mz_ore::panic::install_enhanced_handler();
59
60    // Run the maelstrom stuff in a spawn_blocking because it internally
61    // spawns tasks, so the runtime needs to be in the TLC.
62    Handle::current()
63        .spawn_blocking_named(
64            || "maelstrom::run",
65            move || {
66                Span::current().in_scope(|| {
67                    let read = std::io::stdin();
68                    let write = std::io::stdout();
69                    crate::maelstrom::node::run::<_, _, S>(args, read.lock(), write)
70                })
71            },
72        )
73        .await
74        .expect("task failed")
75}