Skip to content

Commit 20ba253

Browse files
abnegateclaude
andcommitted
fix: uniform orphan recovery and rollback across all table modes
- DuplicateException with table missing: do orphan recovery (drop + recreate) in all modes, not just per-tenant - Track whether we created the physical table; only rollback on metadata failure if we own the table, regardless of shared-tables mode - Removes mode-specific branching in the rollback path Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 10cf13d commit 20ba253

1 file changed

Lines changed: 8 additions & 9 deletions

File tree

src/Database/Database.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,17 +1790,17 @@ public function createCollection(string $id, array $attributes = [], array $inde
17901790
}
17911791
}
17921792

1793+
$createdPhysicalTable = false;
1794+
17931795
try {
17941796
$this->adapter->createCollection($id, $attributes, $indexes);
1797+
$createdPhysicalTable = true;
17951798
} catch (DuplicateException $e) {
1796-
if ($this->adapter->getSharedTables()) {
1799+
if ($this->adapter->getSharedTables()
1800+
&& ($id === self::METADATA || $this->adapter->exists($this->adapter->getDatabase(), $id))) {
17971801
// In shared-tables mode the physical table is reused across
17981802
// tenants. A DuplicateException simply means the table already
1799-
// exists for another tenant — not an orphan. Verify the table
1800-
// is actually present before writing tenant metadata.
1801-
if ($id !== self::METADATA && !$this->adapter->exists($this->adapter->getDatabase(), $id)) {
1802-
throw $e;
1803-
}
1803+
// exists for another tenant — not an orphan.
18041804
} else {
18051805
// Metadata check (above) already verified collection is absent
18061806
// from metadata. A DuplicateException from the adapter means
@@ -1813,6 +1813,7 @@ public function createCollection(string $id, array $attributes = [], array $inde
18131813
// Already removed by a concurrent reconciler.
18141814
}
18151815
$this->adapter->createCollection($id, $attributes, $indexes);
1816+
$createdPhysicalTable = true;
18161817
}
18171818
}
18181819

@@ -1823,14 +1824,12 @@ public function createCollection(string $id, array $attributes = [], array $inde
18231824
try {
18241825
$createdCollection = $this->silent(fn () => $this->createDocument(self::METADATA, $collection));
18251826
} catch (\Throwable $e) {
1826-
if (!$this->adapter->getSharedTables()) {
1827+
if ($createdPhysicalTable) {
18271828
try {
18281829
$this->cleanupCollection($id);
18291830
} catch (\Throwable $e) {
18301831
Console::error("Failed to rollback collection '{$id}': " . $e->getMessage());
18311832
}
1832-
} else {
1833-
Console::warning("createCollection '{$id}' metadata failed in shared-tables mode; physical table retained. Metadata document must be re-created.");
18341833
}
18351834
throw new DatabaseException("Failed to create collection metadata for '{$id}': " . $e->getMessage(), previous: $e);
18361835
}

0 commit comments

Comments
 (0)