persistcli/
maelstrom.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright Materialize, Inc. and contributors. All rights reserved.
//
// Use of this software is governed by the Business Source License
// included in the LICENSE file.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0.

//! An adaptor to Jepsen Maelstrom's txn-list-append workload

use mz_ore::{task::RuntimeExt, url::SensitiveUrl};
use tokio::runtime::Handle;
use tracing::Span;

use crate::maelstrom::node::Service;
pub mod api;
pub mod node;
pub mod services;
pub mod txn_list_append_multi;
pub mod txn_list_append_single;

/// An adaptor to Jepsen Maelstrom's txn-list-append workload
///
/// Example usage:
///
///     cargo build --example persistcli && java -jar /path/to/maelstrom.jar test -w txn-list-append --bin ./target/debug/examples/persistcli maelstrom
///
/// The [Maelstrom docs] are a great place to start for an understanding of
/// the specifics of what's going on here.
///
/// [maelstrom docs]: https://github.com/jepsen-io/maelstrom/tree/v0.2.1#documentation
#[derive(Debug, Clone, clap::Parser)]
pub struct Args {
    /// Blob to use, defaults to Maelstrom lin-kv service
    #[clap(long)]
    blob_uri: Option<SensitiveUrl>,

    /// Consensus to use, defaults to Maelstrom lin-kv service
    #[clap(long)]
    consensus_uri: Option<SensitiveUrl>,

    /// How much unreliability to inject into Blob and Consensus usage
    ///
    /// This value must be in [0, 1]. 0 means no-op, 1 means complete
    /// unreliability.
    #[clap(long, default_value_t = 0.05)]
    unreliability: f64,
}

pub async fn run<S: Service + 'static>(args: Args) -> Result<(), anyhow::Error> {
    // Persist internally has a bunch of sanity check assertions. If
    // maelstrom tickles one of these, we very much want to bubble this
    // up into a process exit with non-0 status. It's surprisingly
    // tricky to be confident that we're not accidentally swallowing
    // panics in async tasks (in fact there was a bug that did exactly
    // this at one point), so abort on any panics to be extra sure.
    mz_ore::panic::install_enhanced_handler();

    // Run the maelstrom stuff in a spawn_blocking because it internally
    // spawns tasks, so the runtime needs to be in the TLC.
    Handle::current()
        .spawn_blocking_named(
            || "maelstrom::run",
            move || {
                Span::current().in_scope(|| {
                    let read = std::io::stdin();
                    let write = std::io::stdout();
                    crate::maelstrom::node::run::<_, _, S>(args, read.lock(), write)
                })
            },
        )
        .await
        .expect("task failed")
}