Storage pools key on non-canonicalized PathBuf — two spellings of one file produce two Database::create calls and a redb lock error
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 4.5k
- Forks
- 603
- Avg merge
- 23h 32m
- Merged PRs (30d)
- 59
Description
Defect
Both redb connection pools — ruvector-core/src/storage.rs and ruvector-graph/src/storage.rs (the latter now on the Weak+Drop shape after #907) — key their pool map on a PathBuf that is absolutized (joined onto cwd when relative) but never canonicalized. Two spellings of the same file resolve to two slots:
a/b/../b/x.dbvsa/b/x.db- a symlinked directory vs its target
- on macOS, differing case on a case-insensitive filesystem
Each slot independently calls Database::create against the same underlying file; the second open fails with redb's "Database already open. Cannot acquire lock" — the exact error the pool exists to prevent.
This was noted in #907's tail ("Related, pre-existing in both pools") and is split out here so it survives #907 closing. It predates #902 in ruvector-core as well.
Suggested fix
Canonicalize before keying, in both pools:
- The parent directory always exists by the time the key is formed (both pools
create_dir_allit first), sopath.parent().canonicalize()?.join(file_name)is total for the create-if-absent case —Path::canonicalizeon the full path fails when the DB file doesn't exist yet, so canonicalize the parent, not the file. - Keep the traversal check on the user-supplied path (it exists to reject intent, and canonicalizing first would erase the evidence), and use the canonical form only as the pool key +
Database::createargument. - Regression tests, same in both crates: open via
dir/x.dbanddir/sub/../x.dbconcurrently — must share oneDatabase(no lock error, both handles see each other's writes); open via a symlinked dir and the real dir — same assertion.
Since the two pools are intentionally copies of one reference shape (ADR-340 invariant 3), fix them in the same PR so they don't drift again — or better, extract the pool into a small shared module both crates use, which #907 stopped short of doing.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading ruvector-core/src/storage.rs and ruvector-graph/src/storage.rs, including their directory creation, traversal checks, pool-key construction, and the Weak+Drop shape noted for the graph pool. Run the existing storage tests, then add the issue’s concurrent equivalent-path and symlink-path regression cases in both crates. Done means both spellings share one Database, see each other’s writes, and do not produce a redb lock error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100