-
Notifications
You must be signed in to change notification settings - Fork 55
feat(database): use cache lease in getDocument to fix read-after-write staleness #904
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -32,6 +32,12 @@ | |
| "check": "./vendor/bin/phpstan analyse --level 7 src tests --memory-limit 2G", | ||
| "coverage": "./vendor/bin/coverage-check ./tmp/clover.xml 90" | ||
| }, | ||
| "repositories": [ | ||
| { | ||
| "type": "vcs", | ||
| "url": "https://github.com/utopia-php/cache" | ||
| } | ||
| ], | ||
| "require": { | ||
| "php": ">=8.4", | ||
| "ext-pdo": "*", | ||
|
|
@@ -40,7 +46,7 @@ | |
| "ext-redis": "*", | ||
| "utopia-php/validators": "0.2.*", | ||
| "utopia-php/console": "0.1.*", | ||
| "utopia-php/cache": "^3.0", | ||
| "utopia-php/cache": "dev-feat/leasable-cache as 3.1.0", | ||
|
Contributor
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "Current constraint in composer.json:"
jq -r '.require["utopia-php/cache"]' composer.json
echo
echo "Check if stable 3.1 versions are available on Packagist:"
curl -s https://repo.packagist.org/p2/utopia-php/cache.json \
| jq -r '.packages["utopia-php/cache"][].version' \
| grep -E '^3\.1(\.|$)' || true
echo
echo "If no stable 3.1 appears above, keep temporary branch but pin an explicit commit SHA."Repository: utopia-php/database Length of output: 278 Pin this dependency to a commit hash until Line 49 references a moving branch ( - "utopia-php/cache": "dev-feat/leasable-cache as 3.1.0",
+ "utopia-php/cache": "dev-feat/leasable-cache#<commit-sha> as 3.1.0",Switch to 🤖 Prompt for AI Agents |
||
| "utopia-php/pools": "1.*", | ||
| "utopia-php/mongo": "1.*" | ||
| }, | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4879,6 +4879,12 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||||||||||||||||||||
| return $document; | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Capture the cache generation BEFORE reading the row. If a concurrent | ||||||||||||||||||||||||||||||||||||
| // updateDocument purges (and so advances the generation) while we read, | ||||||||||||||||||||||||||||||||||||
| // saveWithLease() below rejects this now-stale value instead of | ||||||||||||||||||||||||||||||||||||
| // re-poisoning the cache. See Cache\Feature\Leasable. | ||||||||||||||||||||||||||||||||||||
| $generation = $forUpdate ? '0' : $this->cache->getGeneration($documentKey); | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4882
to
+4886
Contributor
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. 🧩 Analysis chain🏁 Script executed: # First, let's check the file structure and locate the specific lines
wc -l src/Database/Database.phpRepository: utopia-php/database Length of output: 95 🏁 Script executed: # Read the lines mentioned in the review: 4882-4887 for the generation capture
sed -n '4880,4890p' src/Database/Database.phpRepository: utopia-php/database Length of output: 547 🏁 Script executed: # Read the load() error handling section: 4848-4852
sed -n '4845,4860p' src/Database/Database.phpRepository: utopia-php/database Length of output: 802 🏁 Script executed: # Read the saveWithLease() section: around line 4940
sed -n '4930,4950p' src/Database/Database.phpRepository: utopia-php/database Length of output: 996 🏁 Script executed: # Also check the broader context to understand $forUpdate and the full flow
sed -n '4840,4860p' src/Database/Database.phpRepository: utopia-php/database Length of output: 995 🏁 Script executed: # Find the Cache class and examine getGeneration() method
fd -t f 'Cache\.php' src/Repository: utopia-php/database Length of output: 45 🏁 Script executed: # Search for getGeneration method definition
rg 'function getGeneration' -A 10 src/Repository: utopia-php/database Length of output: 45 🏁 Script executed: # Also check if there's a Leasable feature that might affect this
fd -t f 'Leasable' src/Repository: utopia-php/database Length of output: 45 🏁 Script executed: # Search for Cache class definition
rg 'class Cache' src/Repository: utopia-php/database Length of output: 45 🏁 Script executed: # Look for the Leasable feature mentioned in the comment
rg 'Leasable' src/ -A 5 -B 5Repository: utopia-php/database Length of output: 833 🏁 Script executed: # Search for getGeneration more broadly
rg 'getGeneration' src/ -B 3 -A 3Repository: utopia-php/database Length of output: 621 🏁 Script executed: # Get a broader view of the cache save logic and how $generation is used
sed -n '4930,4950p' src/Database/Database.phpRepository: utopia-php/database Length of output: 996 🏁 Script executed: # Check if there's a composer.json to see the cache dependency
cat composer.json 2>/dev/null || echo "No composer.json in root"Repository: utopia-php/database Length of output: 2491 🏁 Script executed: # Look at the full function signature around the generation capture
sed -n '4820,4895p' src/Database/Database.phpRepository: utopia-php/database Length of output: 3187 🏁 Script executed: # Look at the function name and any other cache initialization
sed -n '4700,4750p' src/Database/Database.php | head -40Repository: utopia-php/database Length of output: 1330 🏁 Script executed: # Search for the function definition to understand the signature
rg 'public function getDocument' -A 15 src/Database/Database.php | head -30Repository: utopia-php/database Length of output: 932 🏁 Script executed: # Verify the composer.json shows cache dependency and version
grep -A 1 "utopia-php/cache" composer.jsonRepository: utopia-php/database Length of output: 232 Wrap Line 4886 calls Gate the cache save on successful generation capture by wrapping the call in try/catch and initializing to Proposed fix- $generation = $forUpdate ? '0' : $this->cache->getGeneration($documentKey);
+ $generation = null;
+ if (!$forUpdate) {
+ try {
+ $generation = $this->cache->getGeneration($documentKey);
+ } catch (Exception $e) {
+ Console::warning('Warning: Failed to get document cache generation: ' . $e->getMessage());
+ }
+ }Then gate the later save: - if (!$forUpdate && empty($relationships)) {
+ if (!$forUpdate && empty($relationships) && $generation !== null) {🤖 Prompt for AI Agents
Comment on lines
+4882
to
+4886
Contributor
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| $document = $this->adapter->getDocument( | ||||||||||||||||||||||||||||||||||||
| $collection, | ||||||||||||||||||||||||||||||||||||
| $id, | ||||||||||||||||||||||||||||||||||||
|
|
@@ -4931,7 +4937,7 @@ public function getDocument(string $collection, string $id, array $queries = [], | |||||||||||||||||||||||||||||||||||
| // caching the pre-commit row would poison the cache for other readers. | ||||||||||||||||||||||||||||||||||||
| if (!$forUpdate && empty($relationships)) { | ||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||
| $this->cache->save($documentKey, $document->getArrayCopy(), $hashKey); | ||||||||||||||||||||||||||||||||||||
| $this->cache->saveWithLease($documentKey, $document->getArrayCopy(), $hashKey, $generation); | ||||||||||||||||||||||||||||||||||||
| $this->cache->save($collectionKey, 'empty', $documentKey); | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4940
to
4941
Contributor
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.
Suggested change
|
||||||||||||||||||||||||||||||||||||
| } catch (Exception $e) { | ||||||||||||||||||||||||||||||||||||
| Console::warning('Failed to save document to cache: ' . $e->getMessage()); | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
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.
main—composer.jsonstill points atdev-feat/leasable-cache as 3.1.0. As noted in the PR description, this needs to be reverted to^3.1(or whatever tag utopia-php/cache#75 ships as) before this PR can merge, otherwise any environment runningcomposer installwill pull from an unversioned feature branch rather than a stable release.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!