Alachisoft / NCache

NCache: Highly Scalable Distributed Cache for .NET
http://www.alachisoft.com
Apache License 2.0
651 stars 124 forks source link

NCache doesn't respect sliding expiration when you get items by tags #33

Open killemth opened 5 years ago

killemth commented 5 years ago

It appears that NCache evicts CacheItem objects without proper regard for the SlidingExpiration property, perhaps when accessing said objects is only by OQL or the Tag based lookup methods, such as GetByAllTags().

The following code is responsible for inserting the CacheItem with a SlidingExpiration property.

        CacheItem cacheItem = new CacheItem(model)
        {
            Tags = new[]
            {
                new Tag(WalletTransactionKeyName),
                new Tag(TagOwnerId(model.OwnerId)),
            },
            SlidingExpiration = TimeSpan.FromDays(30),
            Priority = CacheItemPriority.Default
        };

        Cache.Insert(BuildCacheKey(WalletTransactionKeyName, model.TransactionId), cacheItem);

The following code is responsible for accessing the objects using a Tag lookup method, which is also the only other method that touches this CacheItem object.

        Hashtable results = Cache.GetByAllTags(
            new[]
            {
                new Tag(WalletTransactionKeyName),
                new Tag(TagOwnerId(ownerId))
            });

        if (results.Count == 0)
        {
            return new List<WalletTransactionModel>();
        }

        List<WalletTransactionModel> transactions = new List<WalletTransactionModel>(results.Count);
        foreach (DictionaryEntry entry in results)
        {
            WalletTransactionModel transaction = entry.Value as WalletTransactionModel;
            if (transaction == null)
            {
                continue;
            }

            transactions.Add(transaction);
        }

        transactions = transactions.OrderByDescending(t => t.TransactionDateTime).ToList();

        return transactions;

It is expected that the transaction CacheItem would live in the Cache for a duration of at least 30-days since the last time it was accessed, however, it appears to be evicted sometime within a 12-hour window.

Brad-NCache commented 5 years ago

Hi Killemth,

I have reviewed the code and ran a few tests using it on my end with shorter sliding expiration value and it is working as expected. Items are expired as expected only after the expiration is elapsed and item is not accessed (even with using the GetbyAllTags method call) for the specified period of time.

This confirms that it is not API related as it is working fine for my test case. However, I will try to verify the same test using a longer sliding expiration of 12 hours and will review the results. I will update this thread once I have completed the testing.

In the meantime, I will recommend that you try running this with a shorter sliding expiration time span and see if you are still able to reproduce this behavior. I am also sharing my sample in this thread that you can use to test with configurable sliding expiration intervals.

Testing.zip

Brad-NCache commented 5 years ago

Hello Killemth,

I have modified the sliding expiration test with multiple items set with the same tags and inserted in cache and have found that the items do not expire before time even if the sliding expiration is set at 12 hrs and items accessed using the GetByAllTags() a minute before they are set to expire due to inactivity.

I am attaching the new modified code where I have only used the GetByAllTags() method to access the items corresponding to the tags that were set on them. Please execute the code attached and if you still see the same behavior as before, do let me know and I will further try to pinpoint the root cause.

Testing2.zip

killemth commented 5 years ago

Thanks for the response and results. I will attempt to run a test when I have some more time. For now, I have vacated that concept and went to using absolute expiration and some other logic to ensure freshness.