using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Castle.Core.Logging;
using Nito.AsyncEx;
namespace Abp.Runtime.Caching
{
///
/// Base class for caches.
/// It's used to simplify implementing .
///
public abstract class CacheBase : ICache
{
public ILogger Logger { get; set; }
public string Name { get; }
public TimeSpan DefaultSlidingExpireTime { get; set; }
public TimeSpan? DefaultAbsoluteExpireTime { get; set; }
protected readonly object SyncObj = new object();
private readonly AsyncLock _asyncLock = new AsyncLock();
///
/// Constructor.
///
///
protected CacheBase(string name)
{
Name = name;
DefaultSlidingExpireTime = TimeSpan.FromHours(1);
Logger = NullLogger.Instance;
}
public virtual object Get(string key, Func factory)
{
object item = null;
try
{
item = GetOrDefault(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
lock (SyncObj)
{
try
{
item = GetOrDefault(key);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (item == null)
{
item = factory(key);
if (item == null)
{
return null;
}
try
{
Set(key, item);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
}
}
}
return item;
}
public virtual object[] Get(string[] keys, Func factory)
{
object[] items = null;
try
{
items = GetOrDefault(keys);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
if (items == null)
{
items = new object[keys.Length];
}
if (items.Any(i => i == null))
{
lock (SyncObj)
{
try
{
items = GetOrDefault(keys);
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
var fetched = new List>();
for (var i = 0; i < items.Length; i++)
{
string key = keys[i];
object value = items[i];
if (value == null)
{
value = factory(key);
}
if (value != null)
{
fetched.Add(new KeyValuePair(key, value));
}
}
if (fetched.Any())
{
try
{
Set(fetched.ToArray());
}
catch (Exception ex)
{
Logger.Error(ex.ToString(), ex);
}
}
}
}
return items;
}
public virtual async Task