Skip to content

Commit da3ba34

Browse files
kariyclaude
andcommitted
fix(test): regenerate corrupted database fixtures
Use a persistent database (SyncMode::Durable) instead of in-memory (SyncMode::UtterlyNoSync) for generating test DB snapshots, and properly stop the node before archiving. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2a76014 commit da3ba34

File tree

4 files changed

+27
-4
lines changed

4 files changed

+27
-4
lines changed

crates/utils/src/bin/generate_migration_db.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ fn copy_dir_all(src: &Path, dst: &Path) -> std::io::Result<()> {
3333
let dst_path = dst.join(entry.file_name());
3434
if entry.file_type()?.is_dir() {
3535
copy_dir_all(&entry.path(), &dst_path)?;
36-
} else {
36+
} else if entry.file_name() != "mdbx.lck" {
37+
// Skip mdbx.lck as it contains platform-specific data (pthread mutexes,
38+
// process IDs) that is not portable. MDBX creates a fresh lock file on open.
3739
std::fs::copy(entry.path(), dst_path)?;
3840
}
3941
}
@@ -82,8 +84,16 @@ fn create_tar_gz(db_dir: &Path, output: &Path) -> std::io::Result<()> {
8284
async fn main() {
8385
let args = Args::parse();
8486

85-
println!("Starting node with test_config()...");
86-
let node = TestNode::new_with_config(test_config()).await;
87+
// Use a persistent database directory with SyncMode::Durable instead of the default
88+
// in-memory database (which uses SyncMode::UtterlyNoSync). UtterlyNoSync doesn't
89+
// guarantee that committed data is flushed to disk, which can produce corrupted
90+
// snapshots when the database files are archived.
91+
let db_dir = tempfile::tempdir().expect("failed to create temp dir for database");
92+
let mut config = test_config();
93+
config.db.dir = Some(db_dir.path().to_path_buf());
94+
95+
println!("Starting node with persistent database at {}...", db_dir.path().display());
96+
let node = TestNode::new_with_config(config).await;
8797

8898
println!("Migrating example '{}'...", args.example);
8999
match args.example.as_str() {
@@ -99,9 +109,14 @@ async fn main() {
99109
}
100110
}
101111

102-
// Get the database path from the running node
112+
// Get the database path before stopping the node.
103113
let db_path = node.handle().node().db().path().to_path_buf();
104114

115+
// Stop the node to properly close the MDBX environment and ensure all writes are
116+
// flushed to disk before archiving.
117+
println!("Stopping node...");
118+
node.stop().await.expect("failed to stop node");
119+
105120
println!("Creating archive at {}...", args.output.display());
106121
let output_abs = std::env::current_dir().unwrap().join(&args.output);
107122
create_tar_gz(&db_path, &output_abs).expect("failed to create tar.gz archive");

crates/utils/src/node.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@ impl TestNode {
122122
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../tests/fixtures/db/simple");
123123
Self::new_from_db(&db_path).await
124124
}
125+
126+
/// Stops the node and releases all resources including the database.
127+
///
128+
/// This ensures the MDBX environment is properly closed and all pending writes are
129+
/// flushed. Must be called before archiving or copying database files.
130+
pub async fn stop(self) -> anyhow::Result<()> {
131+
self.node.stop().await
132+
}
125133
}
126134

127135
impl ForkTestNode {

tests/fixtures/db/simple.tar.gz

3.47 MB
Binary file not shown.
3.47 MB
Binary file not shown.

0 commit comments

Comments
 (0)