Repository navigation
feat: sync indexes with what the vaults declare, opt-in - #81
Merged
Merged
Conversation
MigrateOptions.SyncIndexes makes the indexes and search indexes of every collection the migrated vaults declare exactly what the registered vaults declare of it, once every vault's migrations have run. Off by default. Beside creating what's missing and changing in place what MongoDB can: - a plain index declared unique is made unique in place (collMod prepareUnique, then unique); while documents share its keys that fails, and prepareUnique is put back, so the index is left as it was; - one that differs in what MongoDB can't change in place (keys, unique to plain, sparse, partial filter, collation, an expiry it shouldn't have), or the declared keys and options under another name, is dropped and created as declared; - indexes no vault declares are dropped, last, after every other change, so a failure before leaves them; _id_ and Queryable Encryption's __safeContent__ index are kept, as are the indexes of collections no vault declares, such as the migrations' history; - a search index of the other type is dropped, waited for until it's no longer listed, and created anew; one no vault declares is dropped. Every collection is planned before any is changed. Two vaults declaring an index of one name otherwise fail it, as does dropping the only index on a sharded collection's shard key, which MongoDB 8.2 drops on a hashed key; sharding is read with $listClusterCatalog (MongoDB 8.0.10+). A collection several vaults map is synced against all their declarations, so migrating one vault drops nothing another declares. Each drop is logged (IndexDropped, under MongoFlow.Indexes and MongoFlow.Search) with the index as the server listed it, and traced as dropped or recreated. Tested on the real servers: mongo 8.2 (indexes, Queryable Encryption), Atlas Local and mongodb-community-search 1.70.1 (search indexes), and a new sharded cluster fixture (config shard and mongos) for the shard key. Closes #80 Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Closes #80.
MigrateOptions.SyncIndexes, off by default, makes the server's indexes and search indexes exactly what the code declares:What it does
Once every vault's migrations have run, the migrator syncs each collection a migrated vault declares against what every registered vault declares of it. In addition to creating what's missing and changing in place what MongoDB can, as today:
collModprepareUniqueand thenunique. If documents share its keys, the second step fails withCannotConvertIndexToUnique. MongoFlow then setsprepareUniqueback to false, so the index is left exactly as it was. (prepareUniquealone already rejects new duplicates.)collModrefusesunique: false), sparse, partial filter, collation, or an expiry it shouldn't have. It's dropped and created as declared._id_and Queryable Encryption's__safeContent__index are never dropped.Planning before changing
Every collection is planned before any is changed. The sync fails, changing nothing, when:
Scope
MigrateAsync<TVault>syncs TVault's collections against every registered vault's declarations, so it never drops another vault's indexes, and creates them where they're missing.Logs and spans
InformationasIndexDropped(27_002_013 underMongoFlow.Indexes, 27_008_009 underMongoFlow.Search), with the index as the server listed it, so it can be created again by hand. A recreate also logsIndexRecreated, and a unique conversionIndexUpdatedwith{ "unique" : true }.MongoFlow.IndexandMongoFlow.SearchIndexspans are taggedrecreatedordropped.Server behavior I checked first
CannotDropShardKeyIndex), but MongoDB 8.2 drops a hashed shard key's index without complaint. So the plan-time guard is what protects core's 34AgentId_hashed…indexes on prod.$listClusterCatalog. It works for a plainreadWriteuser, whileconfig.collectionsis Unauthorized for that user. It needs MongoDB 8.0.10+. On an older server the sync fails, saying so, rather than guessing.uniqueorsparse. So a declared index can be created before the undeclared one it replaces is dropped. Only a rename, where both have the same identity, has to drop first.Tests
All on real servers, in CI:
IndexTests.Sync.cs:MigrateAsyncof one vault sets up both vaults' indexes;failCommandfailpoint throws, and its span is marked failed;SearchTests.Migrations.cs, every test on both servers): an undeclared search index dropped; one of the other type recreated, after which vector search works; a second synced run changes nothing; two vaults declaring one differently fail.__safeContent___1. Without the exclusion, the server lets the sync drop it.ShardedClusterFixture, a config server that is also a shard plus mongos):PlanSyncfor each outcome;Undeclared;Backs; the search drop waiting until the index is gone;$listClusterCatalogmissing; search listing errors; a failed search-index drop.QueryAsync_JoinOn*tests, which fail only on my machine because of a local driver fork;Not in this PR
MongoFlow.Migratespans, not under a parent span of their own.🤖 Generated with Claude Code