Skip to content

Commit d0f2482

Browse files
leosvelpereznx-cloud[bot]
authored andcommitted
fix(core): prevent DB corruption from concurrent initialization (#34861)
## Current Behavior When multiple processes call `connectToNxDb()` concurrently (plugin workers via `startAnalytics()`, daemon, main CLI), two bugs can corrupt the workspace database: **Bug 1: Lock file inode race.** `unlock_file()` deletes the lock file after unlocking, allowing a subsequent `File::create()` to produce a new file with a different inode. Two processes can hold "the lock" simultaneously on different file objects, breaking mutual exclusion. **Bug 2: Partial file cleanup on version mismatch/connection failure.** The `reason` arm and `Err` arm in `initialize_db` call `remove_file(db_path)` which only deletes `.db`, leaving stale `.db-wal` and `.db-shm` on disk. The recursive `initialize_db` creates a fresh `.db`, but SQLite detects the stale WAL (different inode salt) and deletes it — destroying all data that existed only in the WAL. Both bugs lead to: ``` Database file exists but has no metadata table. ``` ## Expected Behavior 1. Lock file persists across lock/unlock cycles — all processes serialize through the same inode 2. When DB recreation is needed, all auxiliary files (`.db`, `.db-wal`, `.db-shm`) are cleaned up together via `remove_all_database_files` --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
1 parent 2343537 commit d0f2482

File tree

1 file changed

+8
-20
lines changed

1 file changed

+8
-20
lines changed

packages/nx/src/native/db/initialize.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,11 @@ fn create_db_error(operation: &str, error: anyhow::Error) -> anyhow::Error {
123123
)
124124
}
125125

126-
pub(super) struct LockFile {
127-
file: File,
128-
path: PathBuf,
126+
pub(super) fn unlock_file(lock_file: &File) {
127+
fs4::fs_std::FileExt::unlock(lock_file).ok();
129128
}
130129

131-
pub(super) fn unlock_file(lock_file: &LockFile) {
132-
if lock_file.path.exists() {
133-
fs4::fs_std::FileExt::unlock(&lock_file.file)
134-
.and_then(|_| remove_file(&lock_file.path))
135-
.ok();
136-
}
137-
}
138-
139-
pub(super) fn create_lock_file(db_path: &Path) -> anyhow::Result<LockFile> {
130+
pub(super) fn create_lock_file(db_path: &Path) -> anyhow::Result<File> {
140131
let lock_file_path = db_path.with_extension("lock");
141132
trace!("Creating lock file at {:?}", lock_file_path);
142133
let lock_file = File::create(&lock_file_path)
@@ -146,10 +137,7 @@ pub(super) fn create_lock_file(db_path: &Path) -> anyhow::Result<LockFile> {
146137
fs4::fs_std::FileExt::lock_exclusive(&lock_file)
147138
.inspect(|_| trace!("Got lock on db lock file"))
148139
.map_err(|e| create_io_error("acquire exclusive lock", &lock_file_path, e))?;
149-
Ok(LockFile {
150-
file: lock_file,
151-
path: lock_file_path,
152-
})
140+
Ok(lock_file)
153141
}
154142

155143
pub(super) fn initialize_db(nx_version: String, db_path: &Path) -> anyhow::Result<NxDbConnection> {
@@ -222,8 +210,8 @@ pub(super) fn initialize_db(nx_version: String, db_path: &Path) -> anyhow::Resul
222210
trace!("Incompatible database because: {:?}", reason);
223211
trace!("Disconnecting from existing incompatible database");
224212
c.close()?;
225-
trace!("Removing existing incompatible database");
226-
remove_file(db_path)?;
213+
trace!("Removing existing incompatible database and auxiliary files");
214+
remove_all_database_files(db_path)?;
227215

228216
trace!("Initializing a new database");
229217
return initialize_db(nx_version, db_path);
@@ -237,8 +225,8 @@ pub(super) fn initialize_db(nx_version: String, db_path: &Path) -> anyhow::Resul
237225
"Unable to connect to existing database because: {:?}",
238226
reason
239227
);
240-
trace!("Removing existing incompatible database");
241-
remove_file(db_path)?;
228+
trace!("Removing existing database and auxiliary files");
229+
remove_all_database_files(db_path)?;
242230

243231
trace!("Initializing a new database");
244232
return initialize_db(nx_version, db_path);

0 commit comments

Comments
 (0)