Repository navigation
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🟡 Changes recommended
Shared-user lock handling can block writes, and cleanup can delete unrelated hidden-directory contents.
2 open findings
What changed in this PR
Introduces atomic cache publication with in-file expiry metadata, safer garbage collection, and expanded verification and benchmarking.
Changes:
- Adds the
YFC1cache format and atomic temporary-file replacement. - Coordinates publication and GC while improving cleanup and batch-write behavior.
- Adds race tests, regression coverage, benchmarks, and upgrade documentation.
| File | Description |
|---|---|
src/FileCache.php |
Implements atomic records, locking, and cleanup. |
tests/TestCase.php |
Adds recursive test cleanup. |
tests/AtomicHeaderTest.php |
Tests format and atomic reads. |
tests/ConcurrencyTest.php |
Improves stress-test execution. |
tests/concurrency_test.php |
Adds concurrent reader/writer validation. |
tests/FileCacheTest.php |
Updates expiry and cleanup tests. |
tests/RaceConditionTest.php |
Tests filesystem races. |
tests/ReviewRegressionTest.php |
Adds regression scenarios. |
benchmarks/CacheFixture.php |
Provides benchmark fixtures. |
benchmarks/MaintenanceBench.php |
Benchmarks clear and GC. |
benchmarks/OperationsBench.php |
Benchmarks cache operations. |
benchmarks/WorkloadBench.php |
Benchmarks mixed workloads. |
benchmarks/README.md |
Documents benchmark methodology. |
phpbench.json.dist |
Configures PHPBench. |
composer.json |
Adds benchmark dependencies and scripts. |
composer-dependency-analyser.php |
Includes benchmark sources. |
.php-cs-fixer.dist.php |
Includes benchmark formatting. |
.github/workflows/rector-cs.yml |
Watches benchmark changes. |
.github/workflows/composer-dependency-analyser.yml |
Analyzes benchmark changes. |
.gitignore |
Ignores benchmark output. |
.gitattributes |
Exports the upgrade guide. |
README.md |
Documents compatibility and benchmarks. |
UPGRADE.md |
Adds deployment and rollback guidance. |
docs/internals.md |
Documents the new file format. |
CHANGELOG.md |
Records the behavioral changes. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix-dot-prefixed-keys #110 +/- ##
===========================================================
+ Coverage 98.82% 99.29% +0.47%
- Complexity 78 146 +68
===========================================================
Files 1 1
Lines 170 284 +114
===========================================================
+ Hits 168 282 +114
Misses 2 2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
vjik
left a comment
There was a problem hiding this comment.
A few thoughts:
-
Split independent fixes into separate PRs. Some fixes don't depend on the new format or atomic writes:
- write errors in
set(); - the
setMultiple()result; - GC and
clear()robustness under concurrency; - failed
filemtime()in GC; - keys starting with a dot.
They're easier to review separately and can go into a patch release.
- write errors in
-
Performance. File cache is usually chosen for small projects with low load. These users get
has(), overwrites and GC 2–4x slower with no noticeable benefit. -
The file format change breaks backward compatibility. It may not be needed for atomicity, though. We could write to a temporary file, set its expiry with
touch(), thenrename()it into place, sincerename()preservesmtime. On read, usefstat()on the opened handle. The format stays the same. What do you think about this approach?
|
|
As for performance, did mtime proof of concept and measured it:
|

Cache writes currently update an existing file and its expiry separately. Concurrent readers can observe a partially written value, mismatched expiry and contents, or a missing entry during replacement. A failed write can also destroy the previous value.
Write a complete entry to a temporary file in the destination directory, then rename it into place. Read the expiry and serialized value from the same open handle. Coordinate publication with GC so collection cannot delete a freshly replaced value, and coordinate readers with replacement on Windows. Keep the publication lock and active temporary files during cleanup.
The proposed
YFC1header stores expiry and serialized payload length. It also identifies dot-prefixed entries when the configured suffix is empty. Old entries remain readable, but mixed-version deployments and rollbacks require separate cache directories. See UPGRADE.md.The independent bug fixes have been extracted into separate PRs:
setMultiple()result;These form a review stack starting from
master, in the order listed above. This PR is based on #115, so its diff excludes the extracted fixes. The proposed file format remains unchanged by this split; the performance and format alternatives raised in review remain open for a separate revision.