Skip to content

Commit abd7b01

Browse files
author
rstam
committed
CSHARP-693: Be more precise about how errors are handled when ContinueOnError is true.
1 parent b5a8b3d commit abd7b01

File tree

2 files changed

+168
-10
lines changed

2 files changed

+168
-10
lines changed

MongoDB.Driver/Operations/InsertOperation.cs

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public InsertOperation(
5252

5353
public IEnumerable<WriteConcernResult> Execute(MongoConnection connection)
5454
{
55+
WriteConcernException finalException = null;
5556
List<WriteConcernResult> results = (WriteConcern.Enabled) ? new List<WriteConcernResult>() : null;
5657

5758
using (var bsonBuffer = new BsonBuffer(new MultiChunkBuffer(BsonChunkPool.Default), true))
@@ -61,6 +62,9 @@ public IEnumerable<WriteConcernResult> Execute(MongoConnection connection)
6162
var message = new MongoInsertMessage(writerSettings, CollectionFullName, _checkElementNames, _flags);
6263
message.WriteToBuffer(bsonBuffer); // must be called before AddDocument
6364

65+
var writeConcernEnabled = WriteConcern.Enabled;
66+
var continueOnError = (_flags & InsertFlags.ContinueOnError) != 0;
67+
6468
foreach (var document in _documents)
6569
{
6670
if (document == null)
@@ -93,14 +97,35 @@ public IEnumerable<WriteConcernResult> Execute(MongoConnection connection)
9397
{
9498
byte[] lastDocument = message.RemoveLastDocument(bsonBuffer);
9599

96-
if (WriteConcern.Enabled || (_flags & InsertFlags.ContinueOnError) != 0)
100+
if (writeConcernEnabled && !continueOnError)
97101
{
98-
var intermediateResult = SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern);
99-
if (WriteConcern.Enabled) { results.Add(intermediateResult); }
102+
try
103+
{
104+
var result = SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern);
105+
results.Add(result);
106+
}
107+
catch (WriteConcernException ex)
108+
{
109+
results.Add((WriteConcernResult)ex.CommandResult);
110+
ex.Data["results"] = results;
111+
throw ex;
112+
}
113+
}
114+
else if (writeConcernEnabled && continueOnError)
115+
{
116+
try
117+
{
118+
var result = SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern);
119+
results.Add(result);
120+
}
121+
catch (WriteConcernException ex)
122+
{
123+
finalException = ex;
124+
results.Add((WriteConcernResult)ex.CommandResult);
125+
}
100126
}
101-
else
127+
else if (!writeConcernEnabled && !continueOnError)
102128
{
103-
// if WriteConcern is disabled and ContinueOnError is false we have to check for errors and stop if sub-batch has error
104129
try
105130
{
106131
SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern.Acknowledged);
@@ -110,15 +135,41 @@ public IEnumerable<WriteConcernResult> Execute(MongoConnection connection)
110135
return null;
111136
}
112137
}
138+
else if (!writeConcernEnabled && continueOnError)
139+
{
140+
SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern.Unacknowledged);
141+
}
113142

114143
message.ResetBatch(bsonBuffer, lastDocument);
115144
}
116145
}
117146

118-
var finalResult = SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern);
119-
if (WriteConcern.Enabled) { results.Add(finalResult); }
147+
if (writeConcernEnabled)
148+
{
149+
try
150+
{
151+
var result = SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern);
152+
results.Add(result);
153+
}
154+
catch (WriteConcernException ex)
155+
{
156+
finalException = ex;
157+
results.Add((WriteConcernResult)ex.CommandResult);
158+
}
120159

121-
return results;
160+
if (finalException != null)
161+
{
162+
finalException.Data["results"] = results;
163+
throw finalException;
164+
}
165+
166+
return results;
167+
}
168+
else
169+
{
170+
SendMessageWithWriteConcern(connection, bsonBuffer, message.RequestId, readerSettings, writerSettings, WriteConcern.Unacknowledged);
171+
return null;
172+
}
122173
}
123174
}
124175
}

MongoDB.DriverUnitTests/MongoCollectionTests.cs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,8 +1141,9 @@ public void TestInsertBatchMultipleBatchesWriteConcernDisabledContinueOnErrorFal
11411141
};
11421142

11431143
var options = new MongoInsertOptions { Flags = InsertFlags.None }; // no ContinueOnError
1144-
collection.InsertBatch(documents, options);
1144+
var result = collection.InsertBatch(documents, options);
11451145

1146+
Assert.AreEqual(null, result);
11461147
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 1)));
11471148
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 2)));
11481149
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 3)));
@@ -1178,7 +1179,113 @@ public void TestInsertBatchMultipleBatchesWriteConcernDisabledContinueOnErrorTru
11781179
};
11791180

11801181
var options = new MongoInsertOptions { Flags = InsertFlags.ContinueOnError };
1181-
collection.InsertBatch(documents, options);
1182+
var result = collection.InsertBatch(documents, options);
1183+
1184+
Assert.AreEqual(null, result);
1185+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 1)));
1186+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 2)));
1187+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 3)));
1188+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 4)));
1189+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 5)));
1190+
}
1191+
}
1192+
1193+
[Test]
1194+
public void TestInsertBatchMultipleBatchesWriteConcernEnabledContinueOnErrorFalse()
1195+
{
1196+
var collectionName = Configuration.TestCollection.Name;
1197+
var collectionSettings = new MongoCollectionSettings { WriteConcern = WriteConcern.Acknowledged };
1198+
var collection = Configuration.TestDatabase.GetCollection<BsonDocument>(collectionName, collectionSettings);
1199+
if (collection.Exists()) { collection.Drop(); }
1200+
1201+
using (Configuration.TestDatabase.RequestStart())
1202+
{
1203+
var maxMessageLength = Configuration.TestServer.RequestConnection.ServerInstance.MaxMessageLength;
1204+
1205+
var filler = new string('x', maxMessageLength / 3); // after overhead results in two documents per sub-batch
1206+
var documents = new BsonDocument[]
1207+
{
1208+
// first sub-batch
1209+
new BsonDocument { { "_id", 1 }, { "filler", filler } },
1210+
new BsonDocument { { "_id", 2 }, { "filler", filler } },
1211+
// second sub-batch
1212+
new BsonDocument { { "_id", 3 }, { "filler", filler } },
1213+
new BsonDocument { { "_id", 3 }, { "filler", filler } }, // duplicate _id error
1214+
// third sub-batch
1215+
new BsonDocument { { "_id", 4 }, { "filler", filler } },
1216+
new BsonDocument { { "_id", 5 }, { "filler", filler } },
1217+
};
1218+
1219+
try
1220+
{
1221+
var options = new MongoInsertOptions { Flags = InsertFlags.None }; // no ContinueOnError
1222+
collection.InsertBatch(documents, options);
1223+
}
1224+
catch (WriteConcernException ex)
1225+
{
1226+
var results = (IEnumerable<WriteConcernResult>)ex.Data["results"];
1227+
Assert.AreEqual(2, results.Count());
1228+
1229+
var result1 = results.ElementAt(0);
1230+
Assert.AreEqual(false, result1.HasLastErrorMessage);
1231+
1232+
var result2 = results.ElementAt(1);
1233+
Assert.AreEqual(true, result2.HasLastErrorMessage);
1234+
}
1235+
1236+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 1)));
1237+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 2)));
1238+
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 3)));
1239+
Assert.AreEqual(0, collection.Count(Query.EQ("_id", 4)));
1240+
Assert.AreEqual(0, collection.Count(Query.EQ("_id", 5)));
1241+
}
1242+
}
1243+
1244+
[Test]
1245+
public void TestInsertBatchMultipleBatchesWriteConcernEnabledContinueOnErrorTrue()
1246+
{
1247+
var collectionName = Configuration.TestCollection.Name;
1248+
var collectionSettings = new MongoCollectionSettings { WriteConcern = WriteConcern.Acknowledged };
1249+
var collection = Configuration.TestDatabase.GetCollection<BsonDocument>(collectionName, collectionSettings);
1250+
if (collection.Exists()) { collection.Drop(); }
1251+
1252+
using (Configuration.TestDatabase.RequestStart())
1253+
{
1254+
var maxMessageLength = Configuration.TestServer.RequestConnection.ServerInstance.MaxMessageLength;
1255+
1256+
var filler = new string('x', maxMessageLength / 3); // after overhead results in two documents per sub-batch
1257+
var documents = new BsonDocument[]
1258+
{
1259+
// first sub-batch
1260+
new BsonDocument { { "_id", 1 }, { "filler", filler } },
1261+
new BsonDocument { { "_id", 2 }, { "filler", filler } },
1262+
// second sub-batch
1263+
new BsonDocument { { "_id", 3 }, { "filler", filler } },
1264+
new BsonDocument { { "_id", 3 }, { "filler", filler } }, // duplicate _id error
1265+
// third sub-batch
1266+
new BsonDocument { { "_id", 4 }, { "filler", filler } },
1267+
new BsonDocument { { "_id", 5 }, { "filler", filler } },
1268+
};
1269+
1270+
try
1271+
{
1272+
var options = new MongoInsertOptions { Flags = InsertFlags.ContinueOnError };
1273+
collection.InsertBatch(documents, options);
1274+
}
1275+
catch (WriteConcernException ex)
1276+
{
1277+
var results = (IEnumerable<WriteConcernResult>)ex.Data["results"];
1278+
Assert.AreEqual(3, results.Count());
1279+
1280+
var result1 = results.ElementAt(0);
1281+
Assert.AreEqual(false, result1.HasLastErrorMessage);
1282+
1283+
var result2 = results.ElementAt(1);
1284+
Assert.AreEqual(true, result2.HasLastErrorMessage);
1285+
1286+
var result3 = results.ElementAt(2);
1287+
Assert.AreEqual(false, result3.HasLastErrorMessage);
1288+
}
11821289

11831290
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 1)));
11841291
Assert.AreEqual(1, collection.Count(Query.EQ("_id", 2)));

0 commit comments

Comments
 (0)