CSHARP-2043: Add AssumeIndexesExist option to GridFSBucketOptions#2047
CSHARP-2043: Add AssumeIndexesExist option to GridFSBucketOptions#2047papafe wants to merge 6 commits into
Conversation
Lets users opt out of the automatic GridFS index check and creation on first upload. Useful for sharded clusters (where the empty-files check is broadcast to all shards and fails if any shard is down) and write-only users. Based on the original work by John Gibbons (jg11jg) in mongodb#294.
There was a problem hiding this comment.
Pull request overview
Adds a new AssumeIndexesExist option to GridFS bucket configuration so callers can opt out of the driver’s automatic GridFS index check/creation that normally occurs before the first upload.
Changes:
- Introduces
AssumeIndexesExistonGridFSBucketOptions/ImmutableGridFSBucketOptions. - Skips
EnsureIndexes/EnsureIndexesAsyncinGridFSBucketwhenAssumeIndexesExistis enabled. - Adds/updates unit + integration tests to validate option behavior and defaults.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs |
Adds AssumeIndexesExist to mutable/immutable options and copies it through constructors. |
src/MongoDB.Driver/GridFS/GridFSBucket.cs |
Early-returns from index ensure paths when AssumeIndexesExist is true. |
tests/MongoDB.Driver.Tests/GridFS/GridFSBucketTests.cs |
Adds integration coverage asserting index creation is skipped/enabled based on the option. |
tests/MongoDB.Driver.Tests/GridFS/GridFSBucketOptionsTests.cs |
Adds unit coverage for the new option and ensures it round-trips through constructors/defaults. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…tion - ImmutableGridFSBucketOptions defaults test now constructs the immutable type. - Assert GridFS index absence rather than OnlyContain(_id_) to avoid flakiness.
| RequireServer.Check(); | ||
| var client = DriverTestConfiguration.Client; | ||
| var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); | ||
| var options = new GridFSBucketOptions { AssumeIndexesExist = true }; | ||
| var subject = new GridFSBucket(database, options); | ||
| subject.Drop(); | ||
|
|
||
| if (async) | ||
| { | ||
| subject.UploadFromBytesAsync("filename", new byte[] { 0 }).GetAwaiter().GetResult(); | ||
| } | ||
| else | ||
| { | ||
| subject.UploadFromBytes("filename", new byte[] { 0 }); | ||
| } | ||
|
|
||
| var filesIndexes = database.GetCollection<BsonDocument>("fs.files").Indexes.List().ToList(); | ||
| filesIndexes.Should().NotContain(index => index["name"] == "filename_1_uploadDate_1"); | ||
| var chunksIndexes = database.GetCollection<BsonDocument>("fs.chunks").Indexes.List().ToList(); | ||
| chunksIndexes.Should().NotContain(index => index["name"] == "files_id_1_n_1"); | ||
| } |
| RequireServer.Check(); | ||
| var client = DriverTestConfiguration.Client; | ||
| var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); | ||
| var subject = new GridFSBucket(database); | ||
| subject.Drop(); | ||
|
|
||
| if (async) | ||
| { | ||
| subject.UploadFromBytesAsync("filename", new byte[] { 0 }).GetAwaiter().GetResult(); | ||
| } | ||
| else | ||
| { | ||
| subject.UploadFromBytes("filename", new byte[] { 0 }); | ||
| } | ||
|
|
||
| var filesIndexes = database.GetCollection<BsonDocument>("fs.files").Indexes.List().ToList(); | ||
| filesIndexes.Should().Contain(index => index["name"] == "filename_1_uploadDate_1"); | ||
| var chunksIndexes = database.GetCollection<BsonDocument>("fs.chunks").Indexes.List().ToList(); | ||
| chunksIndexes.Should().Contain(index => index["name"] == "files_id_1_n_1"); | ||
| } |
| /// <summary> | ||
| /// Gets or sets whether to assume the GridFS indexes already exist, skipping the index check and creation before the first upload. | ||
| /// </summary> |
| /// <summary> | ||
| /// Gets whether to assume the GridFS indexes already exist, skipping the index check and creation before the first upload. | ||
| /// </summary> |
Upload_should_not_create_indexes_when_AssumeIndexesExist_is_true left the
shared fs.files/fs.chunks non-empty without the GridFS indexes. A later test
sharing the same bucket (Upload_of_duplicate_file_should_not_invalidate_existing_data)
then found a non-empty files collection, so EnsureIndexes skipped index
creation, and the missing unique {files_id:1,n:1} index meant the expected
duplicate-key MongoBulkWriteException was never thrown. Drop the bucket at the
end of the test to leave the collections empty.
Wrap the AssumeIndexesExist integration tests in try/finally and drop the bucket in the finally block (async-aware via a DropBucket helper) so shared fs.* state is restored even if an assertion fails.
Add a remarks block warning that when true the driver never verifies or creates the GridFS indexes, so the caller must ensure they exist.
| if (_options.AssumeIndexesExist) | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
Not a bug: the binding is acquired via GetSingleServerReadWriteBinding(operationContext) before EnsureIndexes is reached, so server selection already observes the caller's token/deadline, and the upload's chunk/file inserts observe it downstream — the skipped semaphore-wait was only an incidental cancellation checkpoint, so cancellation is still surfaced.
| if (_options.AssumeIndexesExist) | ||
| { | ||
| return; | ||
| } |
…ync theory Per review feedback, merge the two index-behavior integration tests into a single async Task theory parameterized over assumeIndexesExist, using await instead of GetAwaiter().GetResult(). DropBucket helper is now async.
sanych-sun
left a comment
There was a problem hiding this comment.
LGTM + minor comment for your consideration.
| var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); | ||
| var options = new GridFSBucketOptions { AssumeIndexesExist = assumeIndexesExist }; | ||
| var subject = new GridFSBucket(database, options); | ||
| await DropBucketAsync(subject, async); |
There was a problem hiding this comment.
Minor: I would say we can use async api for setup/clean up. There is no perks in executing sync code for setup.
Adds a
AssumeIndexesExistoption toGridFSBucketOptionsthat lets users opt out of the automatic GridFS index check and creation on the first upload.Based on the original contribution by John Gibbons (@jg11jg) in #294, updated for the current
src/MongoDB.Driver/project layout and with added coverage. Supersedes #292 and #294.