addorgeexististing不考虑过期

本文关键字:过期 不考虑 addorgeexististing | 更新日期: 2023-09-27 18:16:21

我使用(。. NET 4.5) MemoryCache,结合SlidingExpiration.

我注意到. addorgetexisting()方法似乎没有考虑到过期,而. get()却考虑到了。

单元测试:

    [TestMethod]
    public void NonWorking()
    {
        var memCache = new MemoryCache("somekey");
        var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };
        var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
        Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
        Thread.Sleep(1100);
        // Expecting null, since the existing item for key1 has expired by now.
        // It is, however, still "foo".
        Assert.AreEqual(null, memCache.AddOrGetExisting("key1", "bar", cachePolicy));
        // FYI: afterwards, memCache.Get("key1") still equals "foo"
    }
    [TestMethod]
    public void Working()
    {
        var memCache = new MemoryCache("somekey");
        var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };
        var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
        Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
        Thread.Sleep(1100);
        Assert.AreEqual(null, memCache.Get("key1"));
    }

问题:

这是预期行为为。addorgetexisting ()?

我可以回到。get(),然后,如果null,。add()。
但是,因此我必须实现我自己的锁来确保线程安全。

addorgeexististing不考虑过期

问题在于AddOrGetExisting的第二次调用。当调用该方法时,它会创建一个MemoryCacheEntry的新实例.net框架的源代码。在这个条目中,它将过期时间设置为UtcNow + 1秒,创建线程。睡眠无用。(参见构造函数的这一行)

我不知道为什么它不使用现有条目的策略来确定超时。我猜这一行应该使用existingEntry而不是entry。也许这是一个bug?

下面是框架中产生"错误行为"的代码

existingEntry = _entries[key] as MemoryCacheEntry;
// has it expired?
if (existingEntry != null && /* THERE => */ entry.UtcAbsExp <= DateTime.UtcNow) {
    toBeReleasedEntry = existingEntry;
    toBeReleasedEntry.State = EntryState.RemovingFromCache;
    existingEntry = null;
}

existingEntry是应该过期的"旧条目",条目是具有未过期UtcAbsExp值的新条目。

如果您将线程睡眠扩展到足够远,则会发生预期的行为。我假设MemoryCache的Timer机制过期的元素。

我还没有深入研究代码来确定默认计时器间隔是什么,但我怀疑它可能是10秒。使用9秒仍然失败,15秒过去了——对我来说。

所以这个bug在AddOrGetExisting中的影响取决于你调用AddOrGetExisting的频率。如果您调用它的速度始终比滑动过期窗口慢,但比MemoryCache计时器检查过期的速度快,那么您将遇到最坏的情况,即始终保留最老的值,即使它已经过期。如果旧值和新值不相等,那么你的代码中就会出现不正确的行为。

如果你知道会有一段时间你没有访问这个值,计时器会使项目过期,你可以容忍上面的情况,项目应该过期,但没有,那么你可能会接受这个问题。