Skip to content
Open
Show file tree
Hide file tree
Changes from 5 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
10 changes: 10 additions & 0 deletions src/MongoDB.Driver/GridFS/GridFSBucket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,11 @@ private GridFSUploadStream<TFileId> CreateUploadStream(IReadWriteBindingHandle b

private void EnsureIndexes(OperationContext operationContext, IReadWriteBindingHandle binding)
{
if (_options.AssumeIndexesExist)
{
return;
}
Comment on lines +900 to +903

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.

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.


_ensureIndexesSemaphore.Wait(operationContext.RemainingTimeout, operationContext.CancellationToken);
try
{
Expand Down Expand Up @@ -926,6 +931,11 @@ private void EnsureIndexes(OperationContext operationContext, IReadWriteBindingH

private async Task EnsureIndexesAsync(OperationContext operationContext, IReadWriteBindingHandle binding)
{
if (_options.AssumeIndexesExist)
{
return;
}
Comment on lines +934 to +937

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.

Same as the sync path.


await _ensureIndexesSemaphore.WaitAsync(operationContext.RemainingTimeout, operationContext.CancellationToken).ConfigureAwait(false);
try
{
Expand Down
34 changes: 34 additions & 0 deletions src/MongoDB.Driver/GridFS/GridFSBucketOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace MongoDB.Driver.GridFS
public class GridFSBucketOptions
{
// fields
private bool _assumeIndexesExist;
private string _bucketName;
private int _chunkSizeBytes;
private ReadConcern _readConcern;
Expand All @@ -46,6 +47,7 @@ public GridFSBucketOptions()
public GridFSBucketOptions(GridFSBucketOptions other)
{
Ensure.IsNotNull(other, nameof(other));
_assumeIndexesExist = other.AssumeIndexesExist;
_bucketName = other.BucketName;
_chunkSizeBytes = other.ChunkSizeBytes;
_readConcern = other.ReadConcern;
Expand All @@ -60,6 +62,7 @@ public GridFSBucketOptions(GridFSBucketOptions other)
public GridFSBucketOptions(ImmutableGridFSBucketOptions other)
{
Ensure.IsNotNull(other, nameof(other));
_assumeIndexesExist = other.AssumeIndexesExist;
_bucketName = other.BucketName;
_chunkSizeBytes = other.ChunkSizeBytes;
_readConcern = other.ReadConcern;
Expand All @@ -68,6 +71,21 @@ public GridFSBucketOptions(ImmutableGridFSBucketOptions other)
}

// properties
/// <summary>
/// Gets or sets whether to assume the GridFS indexes already exist, skipping the index check and creation before the first upload.
/// </summary>
Comment on lines +74 to +76
/// <remarks>
/// When <c>true</c>, the driver never verifies or creates the GridFS indexes, so the caller is responsible for ensuring they exist.
/// </remarks>
/// <value>
/// <c>true</c> if the GridFS indexes are assumed to exist; otherwise, <c>false</c>.
/// </value>
public bool AssumeIndexesExist
{
get { return _assumeIndexesExist; }
set { _assumeIndexesExist = value; }
}

/// <summary>
/// Gets or sets the bucket name.
/// </summary>
Expand Down Expand Up @@ -160,6 +178,7 @@ public static ImmutableGridFSBucketOptions Defaults
#endregion

// fields
private readonly bool _assumeIndexesExist;
private readonly string _bucketName;
private readonly int _chunkSizeBytes;
private readonly ReadConcern _readConcern;
Expand All @@ -183,6 +202,7 @@ public ImmutableGridFSBucketOptions()
public ImmutableGridFSBucketOptions(GridFSBucketOptions other)
{
Ensure.IsNotNull(other, nameof(other));
_assumeIndexesExist = other.AssumeIndexesExist;
_bucketName = other.BucketName;
_chunkSizeBytes = other.ChunkSizeBytes;
_readConcern = other.ReadConcern;
Expand All @@ -191,6 +211,20 @@ public ImmutableGridFSBucketOptions(GridFSBucketOptions other)
}

// properties
/// <summary>
/// Gets whether to assume the GridFS indexes already exist, skipping the index check and creation before the first upload.
/// </summary>
Comment on lines +214 to +216
/// <remarks>
/// When <c>true</c>, the driver never verifies or creates the GridFS indexes, so the caller is responsible for ensuring they exist.
/// </remarks>
/// <value>
/// <c>true</c> if the GridFS indexes are assumed to exist; otherwise, <c>false</c>.
/// </value>
public bool AssumeIndexesExist
{
get { return _assumeIndexesExist; }
}

/// <summary>
/// Gets the bucket name.
/// </summary>
Expand Down
52 changes: 49 additions & 3 deletions tests/MongoDB.Driver.Tests/GridFS/GridFSBucketOptionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ namespace MongoDB.Driver.Tests.GridFS
{
public class GridFSBucketOptionsTests
{
[Theory]
[ParameterAttributeData]
public void AssumeIndexesExist_get_should_return_expected_result(
[Values(false, true)]
bool value)
{
var subject = new GridFSBucketOptions { AssumeIndexesExist = value };

var result = subject.AssumeIndexesExist;

result.Should().Be(value);
}

[Theory]
[ParameterAttributeData]
public void AssumeIndexesExist_set_should_have_expected_result(
[Values(false, true)]
bool value)
{
var subject = new GridFSBucketOptions();

subject.AssumeIndexesExist = value;

subject.AssumeIndexesExist.Should().Be(value);
}

[Fact]
public void BucketName_get_should_return_expected_result()
{
Expand Down Expand Up @@ -103,11 +129,12 @@ public void ChunkSizeBytes_set_should_throw_when_value_is_invalid(
[Fact]
public void constructor_with_immutable_other_should_initialize_instance()
{
var mutable = new GridFSBucketOptions { BucketName = "bucket", ChunkSizeBytes = 123, ReadConcern = ReadConcern.Majority, ReadPreference = ReadPreference.Secondary, WriteConcern = WriteConcern.WMajority };
var mutable = new GridFSBucketOptions { AssumeIndexesExist = true, BucketName = "bucket", ChunkSizeBytes = 123, ReadConcern = ReadConcern.Majority, ReadPreference = ReadPreference.Secondary, WriteConcern = WriteConcern.WMajority };
var other = new ImmutableGridFSBucketOptions(mutable);

var result = new GridFSBucketOptions(other);

result.AssumeIndexesExist.Should().Be(other.AssumeIndexesExist);
result.BucketName.Should().Be(other.BucketName);
result.ChunkSizeBytes.Should().Be(other.ChunkSizeBytes);
result.ReadConcern.Should().Be(other.ReadConcern);
Expand All @@ -118,10 +145,11 @@ public void constructor_with_immutable_other_should_initialize_instance()
[Fact]
public void constructor_with_mutable_other_should_initialize_instance()
{
var other = new GridFSBucketOptions { BucketName = "bucket", ChunkSizeBytes = 123, ReadConcern = ReadConcern.Majority, ReadPreference = ReadPreference.Secondary, WriteConcern = WriteConcern.WMajority };
var other = new GridFSBucketOptions { AssumeIndexesExist = true, BucketName = "bucket", ChunkSizeBytes = 123, ReadConcern = ReadConcern.Majority, ReadPreference = ReadPreference.Secondary, WriteConcern = WriteConcern.WMajority };

var result = new GridFSBucketOptions(other);

result.AssumeIndexesExist.Should().Be(other.AssumeIndexesExist);
result.BucketName.Should().Be(other.BucketName);
result.ChunkSizeBytes.Should().Be(other.ChunkSizeBytes);
result.ReadConcern.Should().Be(other.ReadConcern);
Expand All @@ -134,6 +162,7 @@ public void constructor_with_no_arguments_should_initialize_instance_with_defaul
{
var result = new GridFSBucketOptions();

result.AssumeIndexesExist.Should().BeFalse();
result.BucketName.Should().Be("fs");
result.ChunkSizeBytes.Should().Be(255 * 1024);
result.ReadPreference.Should().BeNull();
Expand Down Expand Up @@ -203,6 +232,19 @@ public void WriteConcern_set_should_have_expected_result()

public class ImmutableGridFSBucketOptionsTests
{
[Theory]
[ParameterAttributeData]
public void AssumeIndexesExist_get_should_return_expected_result(
[Values(false, true)]
bool value)
{
var subject = new ImmutableGridFSBucketOptions(new GridFSBucketOptions { AssumeIndexesExist = value });

var result = subject.AssumeIndexesExist;

result.Should().Be(value);
}

[Fact]
public void BucketName_get_should_return_expected_result()
{
Expand All @@ -228,6 +270,7 @@ public void constructor_with_arguments_should_initialize_instance()
{
var mutable = new GridFSBucketOptions
{
AssumeIndexesExist = true,
BucketName = "bucket",
ChunkSizeBytes = 123,
ReadConcern = ReadConcern.Majority,
Expand All @@ -237,6 +280,7 @@ public void constructor_with_arguments_should_initialize_instance()

var result = new ImmutableGridFSBucketOptions(mutable);

result.AssumeIndexesExist.Should().BeTrue();
result.BucketName.Should().Be("bucket");
result.ChunkSizeBytes.Should().Be(123);
result.ReadConcern.Should().Be(ReadConcern.Majority);
Expand All @@ -247,8 +291,9 @@ public void constructor_with_arguments_should_initialize_instance()
[Fact]
public void constructor_with_no_arguments_should_initialize_instance_with_default_values()
{
var result = new GridFSBucketOptions();
var result = new ImmutableGridFSBucketOptions();

result.AssumeIndexesExist.Should().BeFalse();
Comment thread
papafe marked this conversation as resolved.
result.BucketName.Should().Be("fs");
result.ChunkSizeBytes.Should().Be(255 * 1024);
result.ReadConcern.Should().BeNull();
Expand All @@ -270,6 +315,7 @@ public void Defaults_get_should_return_expected_result()
{
var result = ImmutableGridFSBucketOptions.Defaults;

result.AssumeIndexesExist.Should().BeFalse();
result.BucketName.Should().Be("fs");
result.ChunkSizeBytes.Should().Be(255 * 1024);
result.ReadConcern.Should().BeNull();
Expand Down
83 changes: 83 additions & 0 deletions tests/MongoDB.Driver.Tests/GridFS/GridFSBucketTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,77 @@ public void GridFS_should_work_with_strict_stable_api(
}
}

[Theory]
[ParameterAttributeData]
[Trait("Category", "Integration")]
public void Upload_should_not_create_indexes_when_AssumeIndexesExist_is_true(
[Values(false, true)] bool async)
{
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);
DropBucket(subject, async);

try
{
if (async)
{
subject.UploadFromBytesAsync("filename", new byte[] { 0 }).GetAwaiter().GetResult();
Comment thread
sanych-sun marked this conversation as resolved.
Outdated
}
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");
}
finally
{
// restore shared state: without cleanup this test leaves fs.* non-empty and without the
// GridFS indexes, which would suppress index creation for later tests reusing the default bucket
DropBucket(subject, async);
}
}

[Theory]
[ParameterAttributeData]
[Trait("Category", "Integration")]
public void Upload_should_create_indexes_when_AssumeIndexesExist_is_false(
Comment thread
sanych-sun marked this conversation as resolved.
Outdated
[Values(false, true)] bool async)
{
RequireServer.Check();
var client = DriverTestConfiguration.Client;
var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName);
var subject = new GridFSBucket(database);
DropBucket(subject, async);

try
{
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");
}
finally
{
DropBucket(subject, async);
}
}

// private methods
private GridFSBucket CreateSubject(GridFSBucketOptions options = null)
{
Expand All @@ -723,5 +794,17 @@ private void EnsureBucketExists(IGridFSBucket bucket)
{
bucket.UploadFromBytes("filename", new byte[0]);
}

private void DropBucket(IGridFSBucket bucket, bool async)
{
if (async)
{
bucket.DropAsync().GetAwaiter().GetResult();
}
else
{
bucket.Drop();
}
}
}
}