Repository navigation
fix(mongo): inherit virtual/autoInc from legacy _fields entries - #145
Closed
undefined-moe wants to merge 1 commit into
Closed
undefined-moe wants to merge 1 commit into
undefined-moe wants to merge 1 commit into
Conversation
When migrating from the pre-3.7.0 `_fields` format (per-table entries
keyed by `{ table, field }` with ObjectId `_id`), the new-format
initialization in `_createFields` only persisted the `fields` list and
silently dropped the `virtual` and `autoInc` markers.
Consequences after upgrading:
- `_migratePrimary` no longer short-circuits on the stored `autoInc`
and rescans the table on every startup. If rows were ever deleted,
the recalculated counter reuses ids of deleted rows, silently
corrupting references from other tables.
- With a stale/lost `virtual` marker, `_migrateVirtual` may consider
the table shape mismatched and run its destructive full-table
rewrite ($out to `_migrate_` + drop + rename), which can destroy
primary-key columns when the actual data does not match the
recorded flag.
Fix: when initializing a new-format entry, look up the legacy entry
for the same table and inherit `virtual` / `autoInc` if present.
Contributor
|
Legacy |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background
While upgrading
@minatojs/driver-mongo3.6.1 → 3.7.0 on a production deployment, we hit a chain of failures that all trace back to one root cause in the_fieldsmeta migration.Root cause
_createFieldsinitializes new-format_fieldsentries (keyed by_id: table) like this:For an existing deployment, the legacy (< 3.7.0)
_fieldscollection contains per-table entries keyed by{ table, field }with an ObjectId_id, carryingvirtualandautoIncmarkers. When the new-format entry is created, onlyfieldsis persisted —virtualandautoIncare silently dropped.Observed consequences
autoIncloss → id reuse._migratePrimaryno longer short-circuits (if (!isNullable(found?.autoInc)) return) and rescans the table on every startup. If rows with the highest ids were ever deleted, the recalculated counter (max(remaining ids)) makes the next insert reuse the id of a deleted row, silently corrupting references from other tables. On our deployment (81k user rows) this causedE11000 duplicate keyerrors on thebindingtable on every message.Startup deadlock. The rescanned
_migratePrimaryruns insideprepare(), and every query awaitsdatabase.prepared()(selection.ts). With theusertable carryinglogin-addedmigration hooks, the hook's own queries deadlocked the whole prepare chain in our case — every database query in the process hung forever, with zero log output.virtualloss → destructive full-table rewrite. If the recordedvirtualflag disagrees with the table shape,_migrateVirtualrebuilds the entire collection via$out+ drop + rename, with no validation against the actual data. In our incident this rewrote the numericidcolumn of 81k rows into ObjectIds (we recovered from backup + oplog, but avirtual/autoIncmarker loss should never be able to trigger this path in the first place).Fix
When initializing a new-format
_fieldsentry, look up the legacy entry for the same table and inheritvirtual/autoIncif present:Note:
_migratePrimaryreadsautoIncregardless of thefieldvalue stored in the legacy entry, so inheriting by table lookup (with the primary field as query key) matches existing semantics.Tests
Added
packages/mongo/tests/meta-migration.spec.ts:_fieldsentry (with a deleted max-id row), restarts the driver, and assertsvirtual/autoIncare inherited and the deleted row's id is not reused. Fails on master (expected 2 to equal 3), passes with the fix._fieldsentirely and asserts the existing inference-from-data behavior still works.Full mongo suite: 268 passed (266 existing + 2 new).