mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
fix: readers lock read-only instead of skipping, one path per sync
Final Codex (gpt-6.1-sol, xhigh) pass over c65982f confirmed every
earlier item fixed and found:
- high: readers skipped the lock on any error, so a lock file owned by
another user (who can still sync) let a reader run unlocked. Readers
now open an existing lock file read-only for the shared lock, and read
unlocked only when no lock file exists and none can be created.
- low: sync resolved the symlinked path for the install target and the
lock separately; it now resolves once and passes that path to the
lock callback, so both always name the same database.
Verified live: a reader with a read-only lock file waits for an
exclusive holder; install waits for readers; a symlinked path keeps its
link. CLI goldens unchanged; live A/B vs 0.2.4: 15 passed, screen hit a
transient MSN 408 on the old build only (retries pass), discover hits
the IDX 403 on both (exit 4 vs 1, intended).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c65982f407
commit
db59744976
2 changed files with 59 additions and 29 deletions
|
|
@ -144,14 +144,15 @@ pub fn parse_manifest(raw: &str) -> Result<OwnershipSnapshotManifest, IdxError>
|
|||
Ok(manifest)
|
||||
}
|
||||
|
||||
/// `lock(exclusive)` takes the database's lock: shared while inspecting the
|
||||
/// local database, exclusive while rechecking and installing, and never held
|
||||
/// during the downloads.
|
||||
/// `lock(resolved_db_path, exclusive)` takes the database's lock: shared
|
||||
/// while inspecting the local database, exclusive while rechecking and
|
||||
/// installing, and never held during the downloads. The path is resolved
|
||||
/// once, so the lock and the replaced file are always the same database.
|
||||
pub fn sync_snapshot<L>(
|
||||
manifest_source: &str,
|
||||
db_path: &Path,
|
||||
force: bool,
|
||||
lock: impl Fn(bool) -> Result<L, IdxError>,
|
||||
lock: impl Fn(&Path, bool) -> Result<L, IdxError>,
|
||||
) -> Result<OwnershipSyncResult, IdxError> {
|
||||
// Results report the configured path; files are read and replaced at the
|
||||
// resolved one, so a symlinked path updates its target instead of being
|
||||
|
|
@ -161,7 +162,7 @@ pub fn sync_snapshot<L>(
|
|||
let db_path = resolved_db_path.as_path();
|
||||
let manifest = fetch_manifest(manifest_source)?;
|
||||
let local_state = {
|
||||
let _shared = lock(false)?;
|
||||
let _shared = lock(db_path, false)?;
|
||||
inspect_local_db(db_path)?
|
||||
};
|
||||
let decision = build_sync_decision(local_state.as_ref(), &manifest.snapshot, force);
|
||||
|
|
@ -215,7 +216,7 @@ pub fn sync_snapshot<L>(
|
|||
|
||||
let install_result = (|| -> Result<(), IdxError> {
|
||||
validate_snapshot_db(&temp_path, &manifest.snapshot)?;
|
||||
let _lock = lock(true)?;
|
||||
let _lock = lock(db_path, true)?;
|
||||
// The decision was made before the download; an import or edit that
|
||||
// landed since must not be overwritten without --force.
|
||||
if !force && !same_local_state(local_state.as_ref(), inspect_local_db(db_path)?.as_ref()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue