in code/KustoCopyConsole/Concurrency/AsyncCache.cs [33:66]
public async Task<T> GetCacheItemAsync(CancellationToken ct)
{
while (true)
{
var cacheNode = _cacheNode;
if (cacheNode.IsItemAvailable && cacheNode.ExpirationTime > DateTime.Now)
{
return cacheNode.Item!;
}
else
{ // Try to "enter" the cache node: this might be a competition
if (cacheNode.EnterSource.TrySetResult())
{
var result = await _asyncFetchFunction();
var newCacheNode = new CacheNode(
new TaskCompletionSource(),
new TaskCompletionSource(),
true,
result.Item2,
DateTime.Now.Add(result.Item1));
Interlocked.Exchange(ref _cacheNode, newCacheNode);
cacheNode.ExitSource.SetResult();
return newCacheNode.Item!;
}
else
{ // Fail to enter the cache node: another thread will fetch the item
await cacheNode.ExitSource.Task;
}
}
}
}