-
Notifications
You must be signed in to change notification settings - Fork 0
chore: #1780 PROMOTE FORK: fork to new primary via the restore/PITR path #1920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 18 commits
bb54f81
552ab34
e09073b
9122a85
7138732
0abb978
9b42339
a0d10d6
ccb2102
a7bb790
82feaeb
97e2220
55785eb
548a92b
3cbf038
fcff34e
d45674f
8dd5901
af3e3e6
0918d00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1436,6 +1436,34 @@ impl RedDBRuntime { | |
| )) | ||
| } | ||
|
|
||
| pub fn execute_promote_fork( | ||
| &self, | ||
| raw_query: &str, | ||
| query: &PromoteForkQuery, | ||
| ) -> RedDBResult<RuntimeQueryResult> { | ||
| self.check_write(crate::runtime::write_gate::WriteKind::Ddl)?; | ||
| let path = self.inner.db.path().ok_or_else(|| { | ||
| RedDBError::Query("PROMOTE FORK requires a persistent store".to_string()) | ||
| })?; | ||
| self.flush()?; | ||
| let manifest = reddb_file::OperationalManifest::for_db_path(path); | ||
| let outcome = manifest | ||
| .promote_fork(&query.name) | ||
| .map_err(|err| RedDBError::Query(format!("failed to promote store fork: {err}")))?; | ||
| let outcome = | ||
| outcome.ok_or_else(|| RedDBError::NotFound(format!("store fork '{}'", query.name)))?; | ||
| Ok(RuntimeQueryResult::ok_message( | ||
| raw_query.to_string(), | ||
| &format!( | ||
| "store fork '{}' promoted at LSN {}; retired parent archived at {}", | ||
| outcome.name, | ||
| outcome.fork_lsn, | ||
| outcome.archived_parent.store_identity() | ||
| ), | ||
| "promote_fork", | ||
| )) | ||
| } | ||
|
|
||
|
Comment on lines
+1439
to
+1466
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Look for any reopen/reload of the store tied to fork/restore/PITR paths,
# and confirm whether restart is documented as required.
rg -n -i --type=rust -C3 '\breopen\b|\breload\b|restart' crates/reddb-server/src crates/reddb-file/src | rg -i 'fork|restore|pitr|promote'
rg -n --type=rust -C5 'fn flush\(' crates/reddb-server/src
rg -n --type=rust -B2 -A15 'fn recover_or_bootstrap' crates/reddb-file/src/operational_manifest.rsRepository: reddb-io/reddb Length of output: 12165 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Map the relevant files first.
ast-grep outline crates/reddb-server/src/runtime/impl_ddl.rs --view expanded
ast-grep outline crates/reddb-file/src/operational_manifest.rs --view expanded
# Read the specific sections around promote_fork and nearby mutating DDL paths.
sed -n '1400,1495p' crates/reddb-server/src/runtime/impl_ddl.rs
printf '\n---\n'
sed -n '620,760p' crates/reddb-file/src/operational_manifest.rs
printf '\n---\n'
sed -n '1,260p' crates/reddb-server/src/runtime/impl_lifecycle.rs
# Find any reopen/reload/invalidate behavior tied to DDL/catalog mutation.
rg -n -C3 'invalidate_result_cache|invalidate_plan_cache|reopen|reload|open\(|flush\(\)\?|promote_fork|restore|restart' crates/reddb-server/src/runtime crates/reddb-file/srcRepository: reddb-io/reddb Length of output: 50371 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Focus on the promotion implementation, its tests, and any explicit docs about restart/reopen.
sed -n '706,850p' crates/reddb-file/src/operational_manifest.rs
printf '\n---\n'
sed -n '1980,2035p' crates/reddb-file/src/operational_manifest.rs
printf '\n---\n'
sed -n '1439,1472p' crates/reddb-server/src/runtime/impl_ddl.rs
printf '\n---\n'
rg -n -C2 'PROMOTE FORK|promote_fork|restart|reopen|reload|invalidate_result_cache|invalidate_plan_cache' crates/reddb-file/src crates/reddb-server/src | head -n 200
printf '\n---\n'
rg -n -C2 'store_identity|db\.path\(|open_with_options|open\(' crates/reddb-server/src crates/reddb-file/src | head -n 200Repository: reddb-io/reddb Length of output: 39478 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the store's open/path semantics and how the runtime wraps it.
rg -n -C3 'pub fn path\(|struct RedDB|impl RedDB|open_with_options|open\(' crates/reddb-server/src/storage crates/reddb-server/src | head -n 200
printf '\n---\n'
ast-grep outline crates/reddb-server/src/storage/unified/store.rs --view expanded
printf '\n---\n'
sed -n '1,260p' crates/reddb-server/src/storage/unified/store.rs
printf '\n---\n'
sed -n '260,520p' crates/reddb-server/src/storage/unified/store.rsRepository: reddb-io/reddb Length of output: 34563
🤖 Prompt for AI Agents |
||
| /// Execute EXPLAIN ALTER FOR CREATE TABLE | ||
| /// | ||
| /// Pure read: computes the schema diff between the target table's | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift
🧩 Analysis chain
🌐 Web query:
Rust std::fs::rename atomicity crash safety multiple renames durability💡 Result:
In Rust, std::fs::rename provides an atomic operation to rename or replace a file [1][2]. However, "atomicity" and "durability" are distinct concepts in crash-consistent systems [3]. While std::fs::rename is generally atomic at the filesystem level, ensuring your data survives a system crash requires additional steps [3][4]. Atomicity On Unix-like platforms, rename(2) is defined by POSIX to be atomic [5][6]. If the destination path exists, it is replaced atomically, ensuring that other processes will never see the path in an incomplete state [5]. On Windows, Rust's implementation uses modern APIs (FileRenameInfoEx with POSIX semantics where available) to mimic this behavior [7]. Recent improvements in Rust have worked to resolve historical inconsistencies on Windows, such as access-denied errors during concurrent operations [8][7][9]. Durability and Crash Safety Atomicity does not guarantee that your data is written to stable storage; it only ensures the name switch is atomic [3][4]. To achieve a crash-consistent "atomic save" (where the file is replaced by new, fully-persisted content), you must follow this pattern [3][4]: 1. Write your data to a temporary file located on the same filesystem as the destination [3][4]. 2. Call sync_all (which invokes fsync) on the temporary file to ensure the data contents are persisted [3][4]. 3. Call std::fs::rename to move the temporary file to the final destination [3][4]. 4. Open the parent directory and call sync_all on it [3]. This is the critical, often-missed step that ensures the directory entry update (the rename itself) is persisted to stable storage [10][3][6]. Failure to sync the parent directory may result in the rename being reverted or lost after a power loss or kernel crash, even if the file content itself was successfully synced [10][3][6]. Note that "durability" is ultimately limited by the filesystem and hardware; on some systems, even these steps may not prevent data loss under extreme conditions, though this pattern is the standard for POSIX-compliant crash consistency [3][6].
Citations:
std::fs::renameif available rust-lang/rust#131072std::fs::renamesometimes fails on Windows due to missingFILE_RENAME_POSIX_SEMANTICSrust-lang/rust#123985Make
promote_forkrestartable across the rename sequenceA crash between
self.root -> *.retired-by-promote-*and*.promoting-* -> self.rootleaves no manifest at the live path, and the normal open path can treat that as a fresh store instead of resuming the in-flight promotion. Mirrordetach_fork’s resume logic here or add a promotion marker/sweep path so staged and archived siblings are recovered instead of orphaned.🤖 Prompt for AI Agents