Repository: risingwavelabs/risingwave
File: src/tests/simulation/src/slt.rs (Rust)

Code before:
        T: sqllogictest::ColumnType,
    {
        for i in 0usize.. {
            let delay = Duration::from_secs(1 << i);
            if let Err(err) = tester
                .run_async(record.clone())
                .timed(|_res, elapsed| {
                    tracing::debug!("Record {:?} finished in {:?}", record, elapsed)
                })
                .await
            {
                let err_string = err.to_string();
                // cluster could be still under recovering if killed before, retry if
                // meets `no reader for dml in table with id {}`.
                let allowed_errs = [
                    "no reader for dml in table",
                    "error reading a body from connection: broken pipe",
                    "failed to inject barrier",
                    "get error from control stream",
                    "cluster is under recovering",
                ];
                let should_retry = i < MAX_RETRY
                    && allowed_errs
                        .iter()
                        .any(|allowed_err| err_string.contains(allowed_err));
                if !should_retry {
                    panic!("{}", err);
                }
                tracing::error!("failed to run test: {err}\nretry after {delay:?}");
            } else {
                break;
            }
            tokio::time::sleep(delay).await;
        }
    }
}

/// Run the sqllogictest files in `glob`.
pub async fn run_slt_task(cluster: Arc<Cluster>, glob: &str, opts: Opts) {
    let env = slt_env::Env::new(opts);
    tracing::info!("background_ddl_rate: {}", env.background_ddl_rate());
    let mut rng = Env::get_rng();
    let files = glob::glob(glob).expect("failed to read glob pattern");
    for file in files {
        // use a session per file
        let mut tester =
            sqllogictest::Runner::new(|| RisingWave::connect("frontend".into(), "dev".into()));
        tester.add_label("madsim");
        tester.set_var(well_known::DATABASE.to_owned(), "dev".to_owned());

        let file = file.unwrap();

Review comment (suggestion):
The `to_ascii_lowercase()` is called on each `allowed_err` string for every iteration in the loop. Since `allowed_errs` is a constant array and `err_string` is already lowercased on line 422, the `allowed_err` strings should be stored as lowercase constants to avoid redundant conversions. Either define `allowed_errs` with lowercase strings, or remove the `.to_ascii_lowercase()` call here since `err_string` is already lowercase.
```suggestion
                        .any(|allowed_err| err_string.contains(allowed_err));
```

Code after:
        T: sqllogictest::ColumnType,
    {
        for i in 0usize.. {
            let delay = Duration::from_secs(1 << i);
            if let Err(err) = tester
                .run_async(record.clone())
                .timed(|_res, elapsed| {
                    tracing::debug!("Record {:?} finished in {:?}", record, elapsed)
                })
                .await
            {
                let err_string = err.to_string().to_ascii_lowercase();
                // cluster could be still under recovering if killed before, retry if
                // meets `no reader for dml in table with id {}`.
                let allowed_errs = [
                    "no reader for dml in table",
                    "error reading a body from connection: broken pipe",
                    "failed to inject barrier",
                    "get error from control stream",
                    "cluster is under recovering",
                    "streaming vnode mapping has not been initialized",
                ];
                let should_retry = i < MAX_RETRY
                    && allowed_errs
                        .iter()
                        .any(|allowed_err| err_string.contains(&allowed_err.to_ascii_lowercase()));
                if !should_retry {
                    panic!("{}", err);
                }
                tracing::error!("failed to run test: {err}\nretry after {delay:?}");
            } else {
                break;
            }
            tokio::time::sleep(delay).await;
        }
    }
}

/// Run the sqllogictest files in `glob`.
pub async fn run_slt_task(cluster: Arc<Cluster>, glob: &str, opts: Opts) {
    let env = slt_env::Env::new(opts);
    tracing::info!("background_ddl_rate: {}", env.background_ddl_rate());
    let mut rng = Env::get_rng();
    let files = glob::glob(glob).expect("failed to read glob pattern");
    for file in files {
        // use a session per file
        let mut tester =
            sqllogictest::Runner::new(|| RisingWave::connect("frontend".into(), "dev".into()));
        tester.add_label("madsim");
        tester.set_var(well_known::DATABASE.to_owned(), "dev".to_owned());