using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace OTT.Lib.Cache.Benchmark
public static class OttLibCacheBenchmark
static async Task Main(string[] args)
CacheStack.CurrentNode = CacheStack.NewNode();
var value1Task = cache.GetAsync("key1", async s1 =>
await cache.GetAsync("key1.1", FactoryFnAsync);
return await FactoryFnAsync(s1);
var value2Task = cache.GetAsync("key2", async s2 =>
await cache.GetAsync("key2.1", async s2_1 =>
await cache.GetAsync("key2.1.1", FactoryFnAsync);
await cache.GetAsync("key2.1.1", FactoryFnAsync);
return await FactoryFnAsync(s2_1);
await cache.GetAsync("key2.2", FactoryFnAsync);
return await FactoryFnAsync(s2);
var result = await Task.WhenAll(value1Task, value2Task);
Console.WriteLine("Result=" + string.Join(',',result));
Console.WriteLine("InvKeys=" + string.Join(',', CacheStack.GetInvalidationKeys()));
private static async Task<(string, List<string>)> FactoryFnAsync(string s)
return (s, new List<string> { "invalidation" + s });
public static class CacheStack
private static readonly AsyncLocal<ConcurrentDictionary<string, bool>> Current = new AsyncLocal<ConcurrentDictionary<string, bool>>();
public static ConcurrentDictionary<string, bool> CurrentNode
set => Current.Value = value;
public static ConcurrentDictionary<string, bool> NewNode() => new ConcurrentDictionary<string, bool>();
public static void AddInvalidationKeys(ICollection<string> invalidationKeys)
if (invalidationKeys.Count == 0) return;
var current = CurrentNode;
foreach (var invalidationKey in invalidationKeys)
current.TryAdd(invalidationKey, true);
public static ICollection<string> GetInvalidationKeys() => CurrentNode.Keys;
public async Task<T> GetAsync<T>(string key, Func<string, Task<(T, List<string>)>> factoryFn)
var parentNode = CacheStack.CurrentNode;
CacheStack.CurrentNode = CacheStack.NewNode();
var (value, invalidationKeys) = await factoryFn(key);
var currentInvalidationKeys = CacheStack.GetInvalidationKeys();
CacheStack.CurrentNode = parentNode;
CacheStack.AddInvalidationKeys(invalidationKeys);
CacheStack.AddInvalidationKeys(currentInvalidationKeys);
Console.WriteLine(key + "-" + string.Join(',', invalidationKeys.Union(currentInvalidationKeys)));