Ladybug version
Rust crate: lbug = 0.16.1
What operating system are you using?
Ubuntu 24.04
What happened?
Creating a persistent FTS index on an empty node table succeeds, but after closing the process and reopening the
database from a new process, even a normal MATCH query fails with an internal assertion:
Assertion failed in file ".../lbug-src/src/storage/index/hash_index.cpp" on line 483:
hashIndexStorageInfo.overflowHeaderPage == INVALID_PAGE_IDX
This is different from #438: LOAD EXTENSION FTS succeeds when the Rust host binary is built with -rdynamic. The
failure happens after reopening a database that contains an FTS index created on an empty node table.
Are there known steps to reproduce?
Minimal Rust Reproduction
Cargo.toml:
[package]
name = "lbug_empty_fts_repro"
version = "0.1.0"
edition = "2021"
build = "build.rs"
[dependencies]
lbug = "0.16.1"
build.rs:
fn main() {
// Needed for LadybugDB dynamic extensions to resolve symbols from the Rust host binary.
println!("cargo:rustc-link-arg=-rdynamic");
}
src/main.rs:
use std::{env, process};
fn main() {
if let Err(err) = run() {
eprintln!("{err}");
process::exit(1);
}
}
fn run() -> Result<(), Box<dyn std::error::Error>> {
let mut args = env::args().skip(1);
let db_path = args.next().unwrap_or_else(|| "/tmp/lbug-empty-fts.db".to_string());
let mode = args.next().unwrap_or_else(|| "create-empty-index".to_string());
let db = lbug::Database::new(&db_path, lbug::SystemConfig::default())?;
let conn = lbug::Connection::new(&db)?;
match mode.as_str() {
"create-empty-index" => {
conn.query(
"CREATE NODE TABLE IF NOT EXISTS TestNode (
id STRING,
name STRING,
body STRING,
PRIMARY KEY(id)
);",
)?;
conn.query("INSTALL FTS;")?;
conn.query("LOAD EXTENSION FTS;")?;
conn.query(
"CALL CREATE_FTS_INDEX(
'TestNode',
'test_node_fts',
['name', 'body'],
stemmer := 'porter'
);",
)?;
conn.query("CHECKPOINT;")?;
println!("created FTS index on empty table");
}
"reopen-query" => {
conn.query("LOAD EXTENSION FTS;")?;
let result = conn.query("MATCH (n:TestNode) RETURN n.id LIMIT 5;")?;
println!("{result}");
}
"create-nonempty-index" => {
conn.query(
"CREATE NODE TABLE IF NOT EXISTS TestNode (
id STRING,
name STRING,
body STRING,
PRIMARY KEY(id)
);",
)?;
conn.query("CREATE (:TestNode {id: 'n1', name: 'hello', body: 'hello world'});")?;
conn.query("INSTALL FTS;")?;
conn.query("LOAD EXTENSION FTS;")?;
conn.query(
"CALL CREATE_FTS_INDEX(
'TestNode',
'test_node_fts',
['name', 'body'],
stemmer := 'porter'
);",
)?;
conn.query("CHECKPOINT;")?;
println!("created FTS index on non-empty table");
}
other => {
return Err(format!("unknown mode: {other}").into());
}
}
Ok(())
}
Steps to Reproduce
rm -f /tmp/lbug-empty-fts.db
cargo run -- /tmp/lbug-empty-fts.db create-empty-index
cargo run -- /tmp/lbug-empty-fts.db reopen-query
Actual Result
The second command fails with:
Assertion failed in file ".../lbug-src/src/storage/index/hash_index.cpp" on line 483:
hashIndexStorageInfo.overflowHeaderPage == INVALID_PAGE_IDX
Expected Result
Creating an FTS index on an empty table should either:
- be supported and reopen cleanly,
- fail gracefully when the index is created, or
- be ignored/deferred until rows exist.
It should not leave the database in a state that later triggers an internal assertion after reopen.
Control Case
If the table contains at least one row before creating the FTS index, reopening succeeds:
rm -f /tmp/lbug-empty-fts.db
cargo run -- /tmp/lbug-empty-fts.db create-nonempty-index
cargo run -- /tmp/lbug-empty-fts.db reopen-query
This suggests the issue is specific to persistent FTS indexes created on empty node tables.
Relation to #438
This is related to Rust embedding and FTS, but it is not the same failure mode:
Ladybug version
Rust crate:
lbug = 0.16.1What operating system are you using?
Ubuntu 24.04
What happened?
Creating a persistent FTS index on an empty node table succeeds, but after closing the process and reopening the
database from a new process, even a normal
MATCHquery fails with an internal assertion:This is different from #438:
LOAD EXTENSION FTSsucceeds when the Rust host binary is built with-rdynamic. Thefailure happens after reopening a database that contains an FTS index created on an empty node table.
Are there known steps to reproduce?
Minimal Rust Reproduction
Cargo.toml:build.rs:src/main.rs:Steps to Reproduce
Actual Result
The second command fails with:
Expected Result
Creating an FTS index on an empty table should either:
It should not leave the database in a state that later triggers an internal assertion after reopen.
Control Case
If the table contains at least one row before creating the FTS index, reopening succeeds:
This suggests the issue is specific to persistent FTS indexes created on empty node tables.
Relation to #438
This is related to Rust embedding and FTS, but it is not the same failure mode:
LOAD EXTENSION FTSfails because the host binary does not export LadybugDB symbols.LOAD EXTENSION FTSsucceeds with-rdynamic; the failure happens after creating a persistent FTSindex on an empty table and reopening the database.