Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 58
Cache empty getDocument results#924
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
538e2280085de2b1203dd34b6b9c6968bd0File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Uh oh!
There was an error while loading. Please reload this page.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -179,6 +179,9 @@ class Database | ||
| // Cache | ||
| public const TTL = 60 * 60 * 24; // 24 hours | ||
| // Cache "Not Found" results | ||
| private const CACHE_EMPTY_MARKER = '$empty'; | ||
| // Events | ||
| public const EVENT_ALL = '*'; | ||
| @@ -4875,6 +4878,11 @@ public function getDocument(string $collection, string $id, array $queries = [], | ||
| } | ||
| } | ||
| // Negative cache hit | ||
| if (\is_array($cached) && isset($cached[self::CACHE_EMPTY_MARKER])) { | ||
| return $this->createDocumentInstance($collection->getId(), []); | ||
| } | ||
| if ($cached) { | ||
| $document = $this->createDocumentInstance($collection->getId(), $cached); | ||
| @@ -4921,6 +4929,18 @@ public function getDocument(string $collection, string $id, array $queries = [], | ||
| ); | ||
| if ($document->isEmpty()) { | ||
| if (!$forUpdate && empty($relationships)) { | ||
| try { | ||
| $marker = [self::CACHE_EMPTY_MARKER => true]; | ||
| if ($this->cache->saveWithLease($documentKey, $marker, $hashKey, $generation) !== false) { | ||
| $this->cache->save($collectionKey, 'empty', $documentKey); | ||
| } | ||
| } catch (Exception $e) { | ||
| Console::warning('Failed to save empty document to cache: ' . $e->getMessage()); | ||
| } | ||
| } | ||
| return $this->createDocumentInstance($collection->getId(), []); | ||
| } | ||
| @@ -5700,6 +5720,10 @@ public function createDocument(string $collection, Document $document): Document | ||
| return $this->adapter->createDocument($collection, $document); | ||
| }); | ||
| // Clear any negative-cache entry for this id: a prior read may have | ||
| // recorded it as missing before this insert committed. | ||
| $this->withDocumentTenant($document, fn () => $this->purgeCachedDocumentInternal($collection->getId(), $document->getId())); | ||
| if (!$this->inBatchRelationshipPopulation && $this->resolveRelationships) { | ||
| // Use the write stack depth for proper MAX_DEPTH enforcement during creation | ||
| $fetchDepth = count($this->relationshipWriteStack); | ||
| @@ -5826,6 +5850,9 @@ public function createDocuments( | ||
| $document = $this->casting($collection, $document); | ||
| $document = $this->decode($collection, $document); | ||
| // Clear any negative-cache entry recorded before this insert. | ||
| $this->withDocumentTenant($document, fn () => $this->purgeCachedDocumentInternal($collection->getId(), $document->getId())); | ||
| try { | ||
| $onNext && $onNext($document); | ||
| } catch (\Throwable $e) { | ||
| @@ -7528,13 +7555,7 @@ public function upsertDocumentsWithIncrease( | ||
| $doc = $this->decode($collection, $doc); | ||
| } | ||
| if ($this->getSharedTables() && $this->getTenantPerDocument()) { | ||
| $this->withTenant($doc->getTenant(), function () use ($collection, $doc) { | ||
| $this->purgeCachedDocument($collection->getId(), $doc->getId()); | ||
| }); | ||
| } else { | ||
| $this->purgeCachedDocument($collection->getId(), $doc->getId()); | ||
| } | ||
| $this->withDocumentTenant($doc, fn () => $this->purgeCachedDocument($collection->getId(), $doc->getId())); | ||
| $old = $chunk[$index]->getOld(); | ||
| @@ -8350,13 +8371,7 @@ public function deleteDocuments( | ||
| }); | ||
| foreach ($batch as $index => $document) { | ||
| if ($this->getSharedTables() && $this->getTenantPerDocument()) { | ||
| $this->withTenant($document->getTenant(), function () use ($collection, $document) { | ||
| $this->purgeCachedDocument($collection->getId(), $document->getId()); | ||
| }); | ||
| } else { | ||
| $this->purgeCachedDocument($collection->getId(), $document->getId()); | ||
| } | ||
| $this->withDocumentTenant($document, fn () => $this->purgeCachedDocument($collection->getId(), $document->getId())); | ||
| try { | ||
| $onNext && $onNext($document, $old[$index]); | ||
| } catch (Throwable $th) { | ||
| @@ -8427,6 +8442,27 @@ protected function purgeCachedDocumentInternal(string $collectionId, ?string $id | ||
| return true; | ||
| } | ||
| /** | ||
| * Run a per-document cache operation under the document's own tenant. | ||
| * | ||
| * With tenant-per-document, cache keys are scoped by the adapter's current | ||
| * tenant, so a document's purge must run under that document's tenant to | ||
| * target the right key; otherwise the callback runs as-is. | ||
| * | ||
| * @param Document $document | ||
| * @param callable():mixed $callback | ||
| * @return void | ||
| * @throws Exception | ||
| */ | ||
| private function withDocumentTenant(Document $document, callable $callback): void | ||
| { | ||
| if ($this->getSharedTables() && $this->getTenantPerDocument()) { | ||
| $this->withTenant($document->getTenant(), $callback); | ||
| } else { | ||
| $callback(); | ||
| } | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /** | ||
| * Cleans a specific document from cache and triggers EVENT_DOCUMENT_PURGE. | ||
| * And related document reference in the collection cache. | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.