C# InsertOneAsync()之后立即执行的ReplaceOneAsync()并不总是有效,即使在记录日志时也是如此

C# InsertOneAsync()之后立即执行的ReplaceOneAsync()并不总是有效,即使在记录日志时也是如此,c#,mongodb,journaling,C#,Mongodb,Journaling,在单实例MongoDB服务器上,即使客户机上的写关注点设置为journaled,插入后每几千个文档中就有一个文档不能立即重新播放 我的印象是,一旦记录下来,文档就可以立即查询 下面的代码插入文档,然后更新文档的DateModified属性,并尝试根据文档的Id和该属性的旧值更新文档 public class MyDocument { public BsonObjectId Id { get; set; } public DateTime DateModified { get;

在单实例MongoDB服务器上,即使客户机上的写关注点设置为journaled,插入后每几千个文档中就有一个文档不能立即重新播放

我的印象是,一旦记录下来,文档就可以立即查询

下面的代码插入文档,然后更新文档的
DateModified
属性,并尝试根据文档的Id和该属性的旧值更新文档

public class MyDocument
{
    public BsonObjectId Id { get; set; }

    public DateTime DateModified { get; set; }
}

static void Main(string[] args)
{
    var r = Task.Run(MainAsync);

    Console.WriteLine("Inserting documents... Press any key to exit.");
    Console.ReadKey(intercept: true);
}

private static async Task MainAsync()
{
    var client = new MongoClient("mongodb://localhost:27017");
    var database = client.GetDatabase("updateInsertedDocuments");

    var concern = new WriteConcern(journal: true);

    var collection = database.GetCollection<MyDocument>("docs").WithWriteConcern(concern);

    int errorCount = 0;
    int totalCount = 0;

    do
    {
        totalCount++;

        // Create and insert the document
        var document = new MyDocument
        {
            DateModified = DateTime.Now,
        };
        await collection.InsertOneAsync(document);

        // Save and update the modified date
        var oldDateModified = document.DateModified;
        document.DateModified = DateTime.Now;

        // Try to update the document by Id and the earlier DateModified
        var result = await collection.ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, document);

        if (result.ModifiedCount == 0)
        {
            Console.WriteLine($"Error {++errorCount}/{totalCount}: doc {document.Id} did not have DateModified {oldDateModified.ToString("yyyy-MM-dd HH:mm:ss.ffffff")}");

            await DoesItExist(collection, document, oldDateModified);
        }
    }
    while (true);
}
发生这种情况的版本:

  • MongoDB Community Server 3.4.0、3.4.1、3.4.3、3.4.4和3.4.10,均基于WiredTiger存储引擎
  • 服务器运行在Windows和其他操作系统上
  • C#Mongo驱动程序2.3.0和2.4.4
这是MongoDB中的一个问题,还是我们正在做(或假设)一些错误的事情


或者,实际的最终目标是,如何确保插入可以通过更新立即检索?

ReplaceOneAsync在新文档与旧文档相同(因为没有更改)的情况下返回0


在我看来,如果您的测试执行对DateTime的各种调用足够快。现在可以返回相同的值,因此您可能正在将完全相同的文档传递给InsertOneAsync和ReplaceOneAsync。

我尝试了您发布的代码,但似乎无法再现您看到的情况。你使用的C#驱动程序是什么版本?@Kevin good catch,它发生在驱动程序2.3.0和2.4.4上。在我当前的机器(MongoDB 3.4.3)上,这些驱动程序的错误率是1/2500。我不必让工具运行很长时间就可以看到打印的错误。@KevinAdistambha,我也可以使用Mongo 3.4.4和3.6.6-rc3、驱动程序2.4.4和C#4.6复制它。1@KevinAdistambha,此外,我注意到,当我增加服务器的延迟时,问题就变得不那么严重了。11ms似乎完全否定了这个问题(但可能会更少)。对,因此我们应该检查
MatchedCount
,而不是
ModifiedCount
。我可以发誓,我们不会在文档未做任何更改的情况下尝试替换文档,但这听起来是围绕该代码添加更多单元测试的理想机会。
private static async Task DoesItExist(IMongoCollection<MyDocument> collection, MyDocument document, DateTime oldDateModified)
{
    Thread.Sleep(500);

    var fromDatabaseCursor = await collection.FindAsync(d => d.Id == document.Id && d.DateModified == oldDateModified);
    var fromDatabaseDoc = await fromDatabaseCursor.FirstOrDefaultAsync();

    if (fromDatabaseDoc != null)
    {
        Console.WriteLine("But it was found!");
    }
    else
    {
        Console.WriteLine("And wasn't found!");
    }
}