Skip to content

Commit 7ed17f8

Browse files
authored
CSHARP-4900: Uploading a duplicate file larger than the original one causes errors in downloading the original file (#1244)
1 parent ef3a6ea commit 7ed17f8

File tree

2 files changed

+94
-25
lines changed

2 files changed

+94
-25
lines changed

src/MongoDB.Driver.GridFS/GridFSForwardOnlyUploadStream.cs

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
using MongoDB.Bson.Serialization;
2424
using MongoDB.Driver.Core.Bindings;
2525
using MongoDB.Driver.Core.Operations;
26-
using MongoDB.Shared;
2726

2827
namespace MongoDB.Driver.GridFS
2928
{
@@ -374,6 +373,32 @@ protected override void Dispose(bool disposing)
374373
base.Dispose(disposing);
375374
}
376375

376+
private void ExecuteOrSetAbortedOnException(Action action)
377+
{
378+
try
379+
{
380+
action();
381+
}
382+
catch
383+
{
384+
_aborted = true;
385+
throw;
386+
}
387+
}
388+
389+
private async Task ExecuteOrSetAbortedOnExceptionAsync(Func<Task> action)
390+
{
391+
try
392+
{
393+
await action().ConfigureAwait(false);
394+
}
395+
catch
396+
{
397+
_aborted = true;
398+
throw;
399+
}
400+
}
401+
377402
private IMongoCollection<BsonDocument> GetChunksCollection()
378403
{
379404
return GetCollection("chunks");
@@ -476,34 +501,38 @@ private void TruncateFinalChunk()
476501
}
477502

478503
private void WriteBatch(CancellationToken cancellationToken)
479-
{
480-
var chunksCollection = GetChunksCollection();
481-
var chunkDocuments = CreateWriteBatchChunkDocuments();
482-
chunksCollection.InsertMany(chunkDocuments, cancellationToken: cancellationToken);
483-
_batch.Clear();
484-
}
504+
=> ExecuteOrSetAbortedOnException(() =>
505+
{
506+
var chunksCollection = GetChunksCollection();
507+
var chunkDocuments = CreateWriteBatchChunkDocuments();
508+
chunksCollection.InsertMany(chunkDocuments, cancellationToken: cancellationToken);
509+
_batch.Clear();
510+
});
485511

486-
private async Task WriteBatchAsync(CancellationToken cancellationToken)
487-
{
488-
var chunksCollection = GetChunksCollection();
489-
var chunkDocuments = CreateWriteBatchChunkDocuments();
490-
await chunksCollection.InsertManyAsync(chunkDocuments, cancellationToken: cancellationToken).ConfigureAwait(false);
491-
_batch.Clear();
492-
}
512+
private Task WriteBatchAsync(CancellationToken cancellationToken)
513+
=> ExecuteOrSetAbortedOnExceptionAsync(async () =>
514+
{
515+
var chunksCollection = GetChunksCollection();
516+
var chunkDocuments = CreateWriteBatchChunkDocuments();
517+
await chunksCollection.InsertManyAsync(chunkDocuments, cancellationToken: cancellationToken).ConfigureAwait(false);
518+
_batch.Clear();
519+
});
493520

494521
private void WriteFilesCollectionDocument(CancellationToken cancellationToken)
495-
{
496-
var filesCollection = GetFilesCollection();
497-
var filesCollectionDocument = CreateFilesCollectionDocument();
498-
filesCollection.InsertOne(filesCollectionDocument, cancellationToken: cancellationToken);
499-
}
522+
=> ExecuteOrSetAbortedOnException(() =>
523+
{
524+
var filesCollection = GetFilesCollection();
525+
var filesCollectionDocument = CreateFilesCollectionDocument();
526+
filesCollection.InsertOne(filesCollectionDocument, cancellationToken: cancellationToken);
527+
});
500528

501-
private async Task WriteFilesCollectionDocumentAsync(CancellationToken cancellationToken)
502-
{
503-
var filesCollection = GetFilesCollection();
504-
var filesCollectionDocument = CreateFilesCollectionDocument();
505-
await filesCollection.InsertOneAsync(filesCollectionDocument, cancellationToken: cancellationToken).ConfigureAwait(false);
506-
}
529+
private Task WriteFilesCollectionDocumentAsync(CancellationToken cancellationToken)
530+
=> ExecuteOrSetAbortedOnExceptionAsync(() =>
531+
{
532+
var filesCollection = GetFilesCollection();
533+
var filesCollectionDocument = CreateFilesCollectionDocument();
534+
return filesCollection.InsertOneAsync(filesCollectionDocument, cancellationToken: cancellationToken);
535+
});
507536

508537
private void WriteFinalBatch(CancellationToken cancellationToken)
509538
{

tests/MongoDB.Driver.GridFS.Tests/GridFSUploadStreamTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515

1616
using System;
1717
using System.IO;
18+
using System.Linq;
1819
using System.Threading;
20+
using System.Threading.Tasks;
1921
using FluentAssertions;
22+
using MongoDB.Bson;
2023
using MongoDB.TestHelpers.XunitExtensions;
2124
using MongoDB.Driver.Tests;
2225
using Xunit;
@@ -71,6 +74,43 @@ public void Flush_should_not_throw(
7174
action.ShouldNotThrow();
7275
}
7376

77+
[Theory]
78+
[ParameterAttributeData]
79+
public async Task Upload_of_duplicate_file_should_not_invalidate_existing_data(
80+
[Values(false, true)] bool async)
81+
{
82+
var content1 = Enumerable.Repeat((byte)1, 20).ToArray();
83+
var content2 = Enumerable.Repeat((byte)2, 100).ToArray();
84+
85+
var fileId = ObjectId.GenerateNewId();
86+
var fileName = "filename";
87+
var uploadOptions = new GridFSUploadOptions
88+
{
89+
ChunkSizeBytes = 10,
90+
BatchSize = 5,
91+
};
92+
93+
var bucket = CreateBucket();
94+
if (async)
95+
{
96+
await bucket.UploadFromBytesAsync(fileId, fileName, content1, uploadOptions);
97+
}
98+
else
99+
{
100+
bucket.UploadFromBytes(fileId, fileName, content1, uploadOptions);
101+
}
102+
103+
var exception = async
104+
? await Record.ExceptionAsync(() => bucket.UploadFromBytesAsync(fileId, fileName, content2, uploadOptions))
105+
: Record.Exception(() => bucket.UploadFromBytes(fileId, fileName, content2, uploadOptions));
106+
exception.Should().BeOfType<MongoBulkWriteException<BsonDocument>>();
107+
108+
var uploadedContent = async
109+
? await bucket.DownloadAsBytesAsync(fileId)
110+
: bucket.DownloadAsBytes(fileId);
111+
uploadedContent.Should().Equal(content1);
112+
}
113+
74114
// private methods
75115
private IGridFSBucket CreateBucket()
76116
{

0 commit comments

Comments
 (0)