using System; using System.IO; using System.Linq; using System.Threading.Tasks; using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.GridFS; using NUnit.Framework; namespace GridFSTests { [TestFixture] public class GridTest { [Test] public void CanDoIOInParallel() { const int fileCount = 1000; var server = MongoServer.Create(); var db = server.GetDatabase("test"); var grid = db.GridFS; // Clean existing files foreach (var n in Enumerable.Range(0, fileCount)) { var filename = String.Format("/tmp/parallel/file{0}", n); grid.Delete(filename); } // Create 10,000 files in parallel and see if we break var writeResult = Parallel.ForEach(Enumerable.Range(0, fileCount), new ParallelOptions() { MaxDegreeOfParallelism = 20 }, (n) => { MongoGridFSFileInfo fileInfo; // In my system I cannot guarantee that Touch and Write happen in the same thread. But it // should be easy to guarantee that a write cannot happen during a touch. using (var request = db.RequestStart()) { var filename = String.Format("/tmp/parallel/file{0}", n); fileInfo = TouchFile(grid, filename); Assert.IsFalse(server.GetLastError().HasLastErrorMessage); // Comment next three lines to do touch and write in same requeststart. } using (var request = db.RequestStart()) { using (var stream = fileInfo.OpenWrite()) { stream.Write((from b in Enumerable.Range(0, 50) select (byte) b).ToArray(), 0, 50); } Assert.IsFalse(server.GetLastError().HasLastErrorMessage); } }); Assert.IsTrue(writeResult.IsCompleted); // Ensure the files have the correct data. var readResult = Parallel.ForEach(Enumerable.Range(0, fileCount), new ParallelOptions() { MaxDegreeOfParallelism = 1 }, (n) => { var filename = String.Format("/tmp/parallel/file{0}", n); var fileInfo = TouchFile(grid, filename); using (var stream = fileInfo.OpenRead()) { var buffer = new byte[50]; stream.Read(buffer, 0, 50); for (var b = 0; b < 50; ++b) Assert.AreEqual((byte)b, buffer[b]); } }); Assert.IsTrue(readResult.IsCompleted); } private static MongoGridFSFileInfo TouchFile(MongoGridFS grid, string path) { var dir = Path.GetDirectoryName(path); // Uploads an empty file into the system marked as // a 'directory' var info = grid.Upload( new System.IO.MemoryStream(new byte[0]), path, new MongoGridFSCreateOptions() { Metadata = new BsonDocument() {{ "dirpath", BsonValue.Create(dir) }} }); return info; } } }