Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Database/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -3813,6 +3813,14 @@ public function createRelationship(
throw new DatabaseException('Failed to create relationship: ' . $e->getMessage());
}

// updateDocument's purge ran inside this outer transaction (nested commits don't
// commit), so it fired pre-commit and a stale collection can stay cached. Re-purge
// after the real commit, else createIndex below re-reads it without the new column.
$this->withRetries(fn () => $this->purgeCachedCollection($collection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $collection->getId()));
$this->withRetries(fn () => $this->purgeCachedCollection($relatedCollection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $relatedCollection->getId()));
Comment on lines +3816 to +3822

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Put the post-commit purge inside the index-creation cleanup scope.

Line 3819 can throw after withRetries() exhausts, but this is before the try at Line 3828. That leaves committed relationship metadata/columns without creating the required indexes, and a retry will hit duplicate metadata instead of completing recovery.

Proposed fix
-            // updateDocument's purge ran inside this outer transaction (nested commits don't
-            // commit), so it fired pre-commit and a stale collection can stay cached. Re-purge
-            // after the real commit, else createIndex below re-reads it without the new column.
-            $this->withRetries(fn () => $this->purgeCachedCollection($collection->getId()));
-            $this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $collection->getId()));
-            $this->withRetries(fn () => $this->purgeCachedCollection($relatedCollection->getId()));
-            $this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $relatedCollection->getId()));
-
             $indexKey = '_index_' . $id;
             $twoWayIndexKey = '_index_' . $twoWayKey;
             $indexesCreated = [];
 
             try {
+                // updateDocument's purge ran inside this outer transaction (nested commits don't
+                // commit), so it fired pre-commit and a stale collection can stay cached. Re-purge
+                // after the real commit, else createIndex below re-reads it without the new column.
+                $this->withRetries(fn () => $this->purgeCachedCollection($collection->getId()));
+                $this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $collection->getId()));
+                $this->withRetries(fn () => $this->purgeCachedCollection($relatedCollection->getId()));
+                $this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $relatedCollection->getId()));
+
                 switch ($type) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// updateDocument's purge ran inside this outer transaction (nested commits don't
// commit), so it fired pre-commit and a stale collection can stay cached. Re-purge
// after the real commit, else createIndex below re-reads it without the new column.
$this->withRetries(fn () => $this->purgeCachedCollection($collection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $collection->getId()));
$this->withRetries(fn () => $this->purgeCachedCollection($relatedCollection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $relatedCollection->getId()));
$indexKey = '_index_' . $id;
$twoWayIndexKey = '_index_' . $twoWayKey;
$indexesCreated = [];
try {
// updateDocument's purge ran inside this outer transaction (nested commits don't
// commit), so it fired pre-commit and a stale collection can stay cached. Re-purge
// after the real commit, else createIndex below re-reads it without the new column.
$this->withRetries(fn () => $this->purgeCachedCollection($collection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $collection->getId()));
$this->withRetries(fn () => $this->purgeCachedCollection($relatedCollection->getId()));
$this->withRetries(fn () => $this->purgeCachedDocumentInternal(self::METADATA, $relatedCollection->getId()));
switch ($type) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Database/Database.php` around lines 3816 - 3822, The post-commit purge in
Database::updateDocument() is happening before the index-creation cleanup
try/catch, so a failure from withRetries() can leave committed metadata/columns
without the required indexes. Move the purge calls for the collection and
relatedCollection into the same cleanup scope as the createIndex recovery logic
(around the existing try near updateDocument) so any retry path can safely
complete after duplicate metadata is handled.


$indexKey = '_index_' . $id;
$twoWayIndexKey = '_index_' . $twoWayKey;
$indexesCreated = [];
Expand Down
Loading