U4-7807 Domain, language, public access cache (GetAll) caches not working when there are no items

This commit is contained in:
Shannon
2016-01-22 17:05:27 +01:00
parent f78a425985
commit 3ecb9d0f86
4 changed files with 84 additions and 5 deletions

View File

@@ -158,8 +158,7 @@ namespace Umbraco.Core.Cache
else if (_options.GetAllCacheAllowZeroCount)
{
//if the repository allows caching a zero count, then check the zero count cache
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
if (zeroCount != null && zeroCount.Any() == false)
if (HasZeroCountCache())
{
//there is a zero count cache so return an empty list
return new TEntity[] {};
@@ -179,6 +178,16 @@ namespace Umbraco.Core.Cache
return entityCollection;
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected virtual bool HasZeroCountCache()
{
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
return (zeroCount != null && zeroCount.Any() == false);
}
/// <summary>
/// Performs the lookup for all entities of this type from the cache
/// </summary>

View File

@@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
@@ -12,10 +14,18 @@ namespace Umbraco.Core.Cache
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
where TEntity : class, IAggregateRoot
{
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache, new RepositoryCachePolicyOptions())
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache,
new RepositoryCachePolicyOptions
{
//Definitely allow zero'd cache entires since this is a full set, in many cases there will be none,
// and we must cache this!
GetAllCacheAllowZeroCount = true
})
{
}
private bool? _hasZeroCountCache;
/// <summary>
/// For this type of caching policy, we don't cache individual items
/// </summary>
@@ -44,6 +54,19 @@ namespace Umbraco.Core.Cache
});
}
/// <summary>
/// Looks up the zero count cache, must return null if it doesn't exist
/// </summary>
/// <returns></returns>
protected override bool HasZeroCountCache()
{
if (_hasZeroCountCache.HasValue)
return _hasZeroCountCache.Value;
_hasZeroCountCache = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey()) != null;
return _hasZeroCountCache.Value;
}
/// <summary>
/// This policy will cache the full data set as a single collection
/// </summary>
@@ -51,6 +74,10 @@ namespace Umbraco.Core.Cache
protected override TEntity[] GetAllFromCache()
{
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
//This method will get called before checking for zero count cache, so we'll just set the flag here
_hasZeroCountCache = found != null;
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
}
}

View File

@@ -14,7 +14,7 @@ namespace Umbraco.Core.Cache
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache)
{
_runtimeCache = runtimeCache;
_runtimeCache = runtimeCache;
}
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Web.Caching;
using Moq;
using NUnit.Framework;
@@ -13,6 +14,48 @@ namespace Umbraco.Tests.Cache
[TestFixture]
public class FullDataSetCachePolicyTests
{
[Test]
public void Get_All_Caches_Empty_List()
{
var cached = new List<string>();
IList list = null;
var cache = new Mock<IRuntimeCacheProvider>();
cache.Setup(x => x.InsertCacheItem(It.IsAny<string>(), It.IsAny<Func<object>>(), It.IsAny<TimeSpan?>(), It.IsAny<bool>(),
It.IsAny<CacheItemPriority>(), It.IsAny<CacheItemRemovedCallback>(), It.IsAny<string[]>()))
.Callback((string cacheKey, Func<object> o, TimeSpan? t, bool b, CacheItemPriority cip, CacheItemRemovedCallback circ, string[] s) =>
{
cached.Add(cacheKey);
list = o() as IList;
});
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(() =>
{
//return null if this is the first pass
return cached.Any() ? new DeepCloneableList<AuditItem>() : null;
});
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] {}, o => new AuditItem[] {});
}
Assert.AreEqual(1, cached.Count);
Assert.IsNotNull(list);
//Do it again, ensure that its coming from the cache!
defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
using (defaultPolicy)
{
var found = defaultPolicy.GetAll(new object[] { }, o => new AuditItem[] { });
}
Assert.AreEqual(1, cached.Count);
Assert.IsNotNull(list);
}
[Test]
public void Get_All_Caches_As_Single_List()
{
@@ -28,7 +71,7 @@ namespace Umbraco.Tests.Cache
list = o() as IList;
});
cache.Setup(x => x.GetCacheItemsByKeySearch(It.IsAny<string>())).Returns(new AuditItem[] { });
cache.Setup(x => x.GetCacheItem(It.IsAny<string>())).Returns(new AuditItem[] { });
var defaultPolicy = new FullDataSetRepositoryCachePolicy<AuditItem, object>(cache.Object);
using (defaultPolicy)