简体   繁体   English

即使在记录日志后,InsertOneAsync()之后也立即无法始终运行ReplaceOneAsync()

[英]ReplaceOneAsync() immediately after InsertOneAsync() not always working, even when journaled

On a single-instance MongoDB server, even with the write concern on the client set to journaled, one in every couple of thousand documents isn't replacable immediately after inserting. 在单实例MongoDB服务器上,即使将客户端的写操作设置为日志记录,插入后也无法立即替换每千两千个文档中的一个。

I was under the impression that once journaled, documents are immediately available for querying. 我的印象是,一旦记录日志,便可以立即使用这些文档进行查询。

The code below inserts a document, then updates the DateModified property of the document and tries to update the document based on the document's Id and the old value of that property. 下面的代码插入一个文档,然后更新该文档的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);
}

The code inserts at a rate of around 250 documents per second. 该代码以每秒约250个文档的速度插入。 One in around 1,000-15,000 calls to ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, ...) fails, as it returns a ModifiedCount of 0. The failure rate depends on whether we run a Debug or Release build and with debugger attached or not: more speed means more errors. 在1,000至15,000个调用ReplaceOneAsync(d => d.Id == document.Id && d.DateModified == oldDateModified, ...)失败,因为它返回的ModifiedCount为0。失败率取决于我们是否运行Debug或Release版本并且是否连接调试器:提高速度意味着出现更多错误。

The code shown represents something that I can't really easily change. 显示的代码代表我无法轻易更改的内容。 Of course I'd rather perform a series of Update.Set() calls, but that's not really an option right now. 当然,我宁愿执行一系列Update.Set()调用,但是现在这实际上不是一个选择。 The InsertOneAsync() followed by a ReplaceOneAsync() is abstracted by some kind of repository pattern that updates entities by reference. 某种存储库模式抽象了InsertOneAsync() ReplaceOneAsync()后的ReplaceOneAsync() ,该存储库模式通过引用来更新实体。 The non-async counterparts of the methods display the same behavior. 方法的非异步副本显示相同的行为。

A simple Thread.Sleep(100) between inserting and replacing mitigates the problem. 在插入和替换之间使用简单的Thread.Sleep(100)缓解此问题。

When the query fails, and we wait a while and then attempt to query the document again in the code below, it'll be found every time. 当查询失败时,我们会稍等片刻,然后尝试在下面的代码中再次查询该文档,每次都会找到它。

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!");
    }
}

Versions on which this occurs: 发生这种情况的版本:

  • MongoDB Community Server 3.4.0, 3.4.1, 3.4.3, 3.4.4 and 3.4.10, all on WiredTiger storage engine MongoDB社区服务器3.4.0、3.4.1、3.4.3、3.4.4和3.4.10均位于WiredTiger存储引擎上
  • Server runs on Windows, other OSes as well 服务器可在Windows以及其他操作系统上运行
  • C# Mongo Driver 2.3.0 and 2.4.4 C#Mongo驱动程序2.3.0和2.4.4

Is this an issue in MongoDB, or are we doing (or assuming) something wrong? 这是MongoDB中的问题,还是我们做(或假设)做错了事?

Or, the actual end goal, how can I ensure an insert is immediately retrievable by an update? 或者,实际的最终目标是如何确保更新可以立即检索插入内容?

ReplaceOneAsync returns 0 if the new document is identical to the old one (because nothing changed). 如果新文档与旧文档相同,则ReplaceOneAsync返回0(因为未进行任何更改)。

It looks to me like if your test executes fast enough the various calls to DateTime.Now could return the same value, so it is possible that you are passing the exact same document to InsertOneAsync and ReplaceOneAsync. 在我看来,如果您的测试执行得足够快,则对DateTime.Now的各种调用可能会返回相同的值,因此您可能会将完全相同的文档传递给InsertOneAsync和ReplaceOneAsync。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 MongoDB C#2.1 ReplaceOneAsync不适用于存储库模式 - MongoDB C# 2.1 ReplaceOneAsync not working for repository pattern WebApi分页不起作用,即使我正确设置了url参数,页面也始终为0 - WebApi Pagination not working, page is always 0 even when I set url parameter correctly Sitefinity配置属性为null,即使在设置后也立即为null - Sitefinity config property null, even immediately after being set 当我使用 ReplaceOneAsync 和 IsUpsert = true mongodb 添加一个空 ID 时。 我该如何阻止? - When I use ReplaceOneAsync and IsUpsert = true mongodb add's a null Id. How do I stop this? Asp.net core 3.1 授权无效!!! 即使提供了令牌,也始终返回 401 - Asp.net core 3.1 Authorization not working!!! Always return 401 even when token is provided 即使在 PointExit 之后,凝视也始终执行 - gaze always execute even after PointExit 即使设置为“关闭”,也始终启用“自动完成”功能 - AutoComplete always is enabled even after setting to OFF 即使在 Logout() 之后,IsAuthenticated 也始终为真 - IsAuthenticated is always true even after Logout() 即使选中,复选框也总是返回false - Checkbox is always returning false even when checked ReplaceOneAsync 不替换文档 - ReplaceOneAsync does not replace the document
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM