Skip to content

Commit 055744e

Browse files
author
Robert Stam
committed
Implemented CSHARP-426 and CSHARP-427. MongoGridFSStream now only updates the GridFS file metadata if the file was actually modified (see the new _fileIsDirty flag). Added UpdateMD5 and VerifyMD5 flags to MongoGridFSSettings (deprecating UpdateMD5 on MongoGridFSStream). Both default to true. If UpdateMD5 is true then the MD5 hash is updated at the server when a file is uploaded or modified. If VerifyMD5 is true then the MD5 hash is verified when a file is uploaded or downloaded (this is CPU intensive).
1 parent 018d7da commit 055744e

File tree

6 files changed

+136
-44
lines changed

6 files changed

+136
-44
lines changed

Driver/GridFS/MongoGridFS.cs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,17 @@ public void Download(Stream stream, IMongoQuery query, int version)
254254
/// <param name="fileInfo">The GridFS file.</param>
255255
public void Download(Stream stream, MongoGridFSFileInfo fileInfo)
256256
{
257+
if (_settings.VerifyMD5 && fileInfo.MD5 == null)
258+
{
259+
throw new MongoGridFSException("VerifyMD5 is true and file being downloaded has no MD5 hash.");
260+
}
261+
257262
using (_database.RequestStart(_database.Settings.SlaveOk))
258263
{
259264
EnsureIndexes();
260265

261-
string md5Client;
262-
using (var md5Algorithm = MD5.Create())
266+
string md5Client = null;
267+
using (var md5Algorithm = _settings.VerifyMD5 ? MD5.Create() : null)
263268
{
264269
var numberOfChunks = (fileInfo.Length + fileInfo.ChunkSize - 1) / fileInfo.ChunkSize;
265270
for (int n = 0; n < numberOfChunks; n++)
@@ -282,14 +287,20 @@ public void Download(Stream stream, MongoGridFSFileInfo fileInfo)
282287
}
283288
}
284289
stream.Write(data.Bytes, 0, data.Bytes.Length);
285-
md5Algorithm.TransformBlock(data.Bytes, 0, data.Bytes.Length, null, 0);
290+
if (_settings.VerifyMD5)
291+
{
292+
md5Algorithm.TransformBlock(data.Bytes, 0, data.Bytes.Length, null, 0);
293+
}
286294
}
287295

288-
md5Algorithm.TransformFinalBlock(new byte[0], 0, 0);
289-
md5Client = BsonUtils.ToHexString(md5Algorithm.Hash);
296+
if (_settings.VerifyMD5)
297+
{
298+
md5Algorithm.TransformFinalBlock(new byte[0], 0, 0);
299+
md5Client = BsonUtils.ToHexString(md5Algorithm.Hash);
300+
}
290301
}
291302

292-
if (!md5Client.Equals(fileInfo.MD5, StringComparison.OrdinalIgnoreCase))
303+
if (_settings.VerifyMD5 && !md5Client.Equals(fileInfo.MD5, StringComparison.OrdinalIgnoreCase))
293304
{
294305
throw new MongoGridFSException("Download client and server MD5 hashes are not equal.");
295306
}
@@ -775,8 +786,8 @@ public MongoGridFSFileInfo Upload(
775786
var buffer = new byte[chunkSize];
776787

777788
var length = 0;
778-
string md5Client;
779-
using (var md5Algorithm = MD5.Create())
789+
string md5Client = null;
790+
using (var md5Algorithm = _settings.VerifyMD5 ? MD5.Create() : null)
780791
{
781792
for (int n = 0; true; n++)
782793
{
@@ -815,27 +826,37 @@ public MongoGridFSFileInfo Upload(
815826
};
816827
_chunks.Insert(chunk, _settings.SafeMode);
817828

818-
md5Algorithm.TransformBlock(data, 0, data.Length, null, 0);
829+
if (_settings.VerifyMD5)
830+
{
831+
md5Algorithm.TransformBlock(data, 0, data.Length, null, 0);
832+
}
819833

820834
if (bytesRead < chunkSize)
821835
{
822836
break; // EOF after partial chunk
823837
}
824838
}
825839

826-
md5Algorithm.TransformFinalBlock(new byte[0], 0, 0);
827-
md5Client = BsonUtils.ToHexString(md5Algorithm.Hash);
840+
if (_settings.VerifyMD5)
841+
{
842+
md5Algorithm.TransformFinalBlock(new byte[0], 0, 0);
843+
md5Client = BsonUtils.ToHexString(md5Algorithm.Hash);
844+
}
828845
}
829846

830-
var md5Command = new CommandDocument
847+
string md5Server = null;
848+
if (_settings.UpdateMD5 || _settings.VerifyMD5)
831849
{
832-
{ "filemd5", files_id },
833-
{ "root", _settings.Root }
834-
};
835-
var md5Result = _database.RunCommand(md5Command);
836-
var md5Server = md5Result.Response["md5"].AsString;
850+
var md5Command = new CommandDocument
851+
{
852+
{ "filemd5", files_id },
853+
{ "root", _settings.Root }
854+
};
855+
var md5Result = _database.RunCommand(md5Command);
856+
md5Server = md5Result.Response["md5"].AsString;
857+
}
837858

838-
if (!md5Client.Equals(md5Server, StringComparison.OrdinalIgnoreCase))
859+
if ( _settings.VerifyMD5 && !md5Client.Equals(md5Server, StringComparison.OrdinalIgnoreCase))
839860
{
840861
throw new MongoGridFSException("Upload client and server MD5 hashes are not equal.");
841862
}
@@ -848,7 +869,7 @@ public MongoGridFSFileInfo Upload(
848869
{ "length", length },
849870
{ "chunkSize", chunkSize },
850871
{ "uploadDate", uploadDate },
851-
{ "md5", md5Server },
872+
{ "md5", (md5Server == null) ? (BsonValue)BsonNull.Value : new BsonString(md5Server) },
852873
{ "contentType", createOptions.ContentType }, // optional
853874
{ "aliases", BsonArray.Create(createOptions.Aliases) }, // optional
854875
{ "metadata", createOptions.Metadata } // optional

Driver/GridFS/MongoGridFSFileInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ private void CacheFileInfo(BsonDocument fileInfo)
531531
_id = fileInfo["_id"];
532532
_length = fileInfo["length"].ToInt64();
533533
var md5Value = fileInfo["md5", null];
534-
if (md5Value != null && !md5Value.IsBsonNull)
534+
if (md5Value != null && md5Value.IsString)
535535
{
536536
_md5 = md5Value.AsString;
537537
}

Driver/GridFS/MongoGridFSSettings.cs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public class MongoGridFSSettings : IEquatable<MongoGridFSSettings>
3535
private string _filesCollectionName = "fs.files";
3636
private string _root = "fs";
3737
private SafeMode _safeMode = SafeMode.False;
38+
private bool _updateMD5 = true;
39+
private bool _verifyMD5 = true;
3840
private bool _isFrozen;
3941
private int _frozenHashCode;
4042

@@ -146,6 +148,30 @@ public SafeMode SafeMode
146148
}
147149
}
148150

151+
/// <summary>
152+
/// Gets or sets whether to udpate the MD5 hash on the server when a file is uploaded or modified.
153+
/// </summary>
154+
public bool UpdateMD5
155+
{
156+
get { return _updateMD5; }
157+
set {
158+
if (_isFrozen) { ThrowFrozen(); }
159+
_updateMD5 = value;
160+
}
161+
}
162+
163+
/// <summary>
164+
/// Gets or sets whether to verify the MD5 hash when a file is uploaded or downloaded.
165+
/// </summary>
166+
public bool VerifyMD5
167+
{
168+
get { return _verifyMD5; }
169+
set {
170+
if (_isFrozen) { ThrowFrozen(); }
171+
_verifyMD5 = value;
172+
}
173+
}
174+
149175
// public operators
150176
/// <summary>
151177
/// Compares two MongoGridFSSettings.
@@ -176,7 +202,13 @@ public SafeMode SafeMode
176202
/// <returns>A clone of the settings.</returns>
177203
public MongoGridFSSettings Clone()
178204
{
179-
return new MongoGridFSSettings(_chunkSize, _root, _safeMode);
205+
var clone = new MongoGridFSSettings();
206+
clone._chunkSize = _chunkSize;
207+
clone._root = _root;
208+
clone._safeMode = _safeMode;
209+
clone._updateMD5 = _updateMD5;
210+
clone._verifyMD5 = _verifyMD5;
211+
return clone;
180212
}
181213

182214
/// <summary>
@@ -190,7 +222,9 @@ public bool Equals(MongoGridFSSettings rhs)
190222
return
191223
_chunkSize == rhs._chunkSize &&
192224
_root == rhs._root &&
193-
_safeMode == rhs._safeMode;
225+
_safeMode == rhs._safeMode &&
226+
_updateMD5 == rhs._updateMD5 &&
227+
_verifyMD5 == rhs._verifyMD5;
194228
}
195229

196230
/// <summary>
@@ -250,6 +284,8 @@ public override int GetHashCode()
250284
hash = 37 * hash + _chunkSize.GetHashCode();
251285
hash = 37 * hash + _root.GetHashCode();
252286
hash = 37 * hash + _safeMode.GetHashCode();
287+
hash = 37 * hash + _updateMD5.GetHashCode();
288+
hash = 37 * hash + _verifyMD5.GetHashCode();
253289
return hash;
254290
}
255291

Driver/GridFS/MongoGridFSStream.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public class MongoGridFSStream : Stream
4343
private int _chunkIndex = -1; // -1 means no chunk is loaded
4444
private BsonValue _chunkId;
4545
private bool _chunkIsDirty;
46-
private bool _updateMD5 = true;
46+
private bool _fileIsDirty;
47+
private bool _updateMD5; // will eventually be removed, for now initialize from settings
4748

4849
// constructors
4950
/// <summary>
@@ -68,6 +69,7 @@ public MongoGridFSStream(MongoGridFSFileInfo fileInfo, FileMode mode, FileAccess
6869
_fileInfo = fileInfo;
6970
_mode = mode;
7071
_access = access;
72+
_updateMD5 = _gridFS.Settings.UpdateMD5;
7173

7274
var exists = fileInfo.Exists;
7375
string message;
@@ -217,6 +219,7 @@ public override long Position
217219
/// <summary>
218220
/// Gets or sets whether to compute and update the MD5 hash for the file when the stream is closed.
219221
/// </summary>
222+
[Obsolete("Use UpdateMD5 on MongoGridFSSettings instead.")]
220223
public bool UpdateMD5
221224
{
222225
get { return _updateMD5; }
@@ -323,6 +326,7 @@ public override void SetLength(long value)
323326
{
324327
_position = _length;
325328
}
329+
_fileIsDirty = true;
326330

327331
var lastChunkIndex = (int)((_length + _fileInfo.ChunkSize - 1) / _fileInfo.ChunkSize) - 1;
328332
if (_chunkIndex == lastChunkIndex)
@@ -368,6 +372,7 @@ public override void Write(byte[] buffer, int offset, int count)
368372
if (partialCount > count) { partialCount = count; }
369373
Buffer.BlockCopy(buffer, offset, _chunk, chunkOffset, partialCount);
370374
_chunkIsDirty = true;
375+
_fileIsDirty = true;
371376

372377
_position += partialCount;
373378
if (_length < _position)
@@ -401,6 +406,7 @@ public override void WriteByte(byte value)
401406
}
402407
_chunk[chunkOffset] = value;
403408
_chunkIsDirty = true;
409+
_fileIsDirty = true;
404410
_position += 1;
405411
if (_length < _position)
406412
{
@@ -421,9 +427,12 @@ protected override void Dispose(bool disposing)
421427
{
422428
if (disposing)
423429
{
424-
Flush();
425-
AddMissingChunks(); // also removes extra chunks
426-
UpdateMetadata();
430+
if (_fileIsDirty)
431+
{
432+
Flush();
433+
AddMissingChunks(); // also removes extra chunks
434+
UpdateMetadata();
435+
}
427436
}
428437
_disposed = true;
429438
}
@@ -551,6 +560,7 @@ private void OpenAppend()
551560

552561
private void OpenCreate()
553562
{
563+
_fileIsDirty = true;
554564
if (_fileInfo.Id == null)
555565
{
556566
_fileInfo.SetId(ObjectId.GenerateNewId());
@@ -581,6 +591,7 @@ private void OpenExisting()
581591

582592
private void OpenTruncate()
583593
{
594+
_fileIsDirty = true;
584595
// existing chunks will be overwritten as needed and extra chunks will be removed on Close
585596
_length = 0;
586597
_position = 0;

DriverUnitTests/GridFS/MongoGridFSSettingsTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ public void TestCloneAndEquals()
6464
{
6565
ChunkSize = 64 * 1024,
6666
Root = "root",
67-
SafeMode = SafeMode.True
67+
SafeMode = SafeMode.True,
68+
UpdateMD5 = false,
69+
VerifyMD5 = false
6870
};
6971
var clone = settings.Clone();
7072
Assert.IsTrue(settings == clone);

0 commit comments

Comments
 (0)