Hi,
I’m trying to use mongodb to have a multi-process lock system. I use FindOneAndUpdate atomicity for that.
This is not to be use for high speed lock, I use this sometime in my code.
I’m using the latest C# driver from Github and mongodb for Windows version v3.6.10.
Sometime I get exception “E11000 duplicate key error collection”.
It’s quite easy to reproduce, run the process 2 or 3 time to get it.
Why is it possible to get this exception ?
How to fix this ?
Remi
Process 88 have the lock
Process 60 have the lock
One or more errors occurred.
Command findAndModify failed: E11000 duplicate key error collection: mq.lock index: id dup key: { : ObjectId(‘632d4d5ed0371a56dcdd187a’) }.
Average = 200,778591919192, Min = 59,0069, Max = 313,0022
Press return to exit.
static void Main(string[] args)
{
var cnx = new MongoClient();
var db = cnx.GetDatabase("mq");
db.DropCollection("lock");
var col = db.GetCollection<BsonDocument>("lock");
ObjectId id = ObjectId.GenerateNewId();
BsonDocument t = new BsonDocument().Add("hello", "world");
Random rnd = new Random();
var fb = Builders<BsonDocument>.Filter;
var ub = Builders<BsonDocument>.Update;
var ud = ub.CurrentDate("dt").Inc("run", 1).SetOnInsert("data", t);
List<Task> tasks = new List<Task>();
List<double> mean = new List<double>();
for (int i = 0; i < 100; i++)
{
int j = i;
tasks.Add(Task.Run(async () =>
{
await Task.Delay(rnd.Next(10, 100));
DateTime start = DateTime.Now;
BsonDocument d = await col.FindOneAndUpdateAsync(
fb.Eq("_id", id),
ud,
new FindOneAndUpdateOptions<BsonDocument>()
{ IsUpsert = true, ReturnDocument = ReturnDocument.After }
);
mean.Add((DateTime.Now - start).TotalMilliseconds);
if (d["run"].AsInt32 == 1)
{
Console.WriteLine($"Process {j} have the lock");
await Task.Delay(rnd.Next(10, 100));
await col.DeleteOneAsync(fb.Eq("_id", id));
}
}));
}
try
{
Task.WaitAll(tasks.ToArray());
}
catch (Exception ex)
{
do
{
Console.WriteLine(ex.Message);
ex = ex.InnerException;
}
while (ex != null);
}
Console.WriteLine($"Average = {mean.Average()}, Min = {mean.Min()}, Max = {mean.Max()}");
Console.WriteLine("Press return to exit.");
Console.ReadLine();
}