Skip to content

concurrent calls to .clear() and the ingestion API causes crash and corruption #287

Description

@svix-jbrown

Describe the bug
Given the following program:

use anyhow::Context;

fn main() -> anyhow::Result<()> {
    env_logger::init();

    let db = fjall::Database::builder("./db")
        .max_journaling_size(67108864)
        .open()
        .context("opening database")?;

    std::thread::scope(|spawner| {
        let keyspace = db
            .keyspace("keyspace1", fjall::KeyspaceCreateOptions::default)
            .unwrap();

        spawner.spawn({
            let keyspace = keyspace.clone();
            move || -> anyhow::Result<()> {
                for _ in 0..1000 {
                    log::debug!("clearing");
                    keyspace.clear()?;
                    std::thread::sleep(std::time::Duration::from_millis(10));
                }
                Ok(())
            }
        });

        spawner.spawn({
            let keyspace = keyspace.clone();
            move || -> anyhow::Result<()> {
                for _ in 0..1000 {
                    let mut igst = keyspace.start_ingestion()?;
                    for i in 0..=10240 {
                        igst.write(format!("key{i:09}"), [(i % 256) as u8; 256])?;
                    }
                    igst.finish()?;
                }
                Ok(())
            }
        });
    });
    Ok(())
}

If run for a while, it will eventually crash with

thread 'fjall:worker' (8070867) panicked at /Users/jbrown/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/lsm-tree-3.1.4/src/version/mod.rs:572:9:
assertion `left == right` failed: invalid table IDs
  left: 0
 right: 1
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

At this point, the database seems to be mildly corrupted; subsequent startups will hang for ~20s logging nothing and then proceed normally, but will leak thousands of versions in to the db/keyspaces/1/ directory (which will all be truncated on the next startup).

I've attached a database that's in this state, in case that's helpful for debugging.

db_invalid.tar.gz

For whatever reason, the crash seems to occur much faster if you set manual_journal_persist(true) on the KeyspaceCreateOptions, but it does still happen eventually even with default journal persistence.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is needed

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions