Skip to content

Commit

Permalink
feat(ShadowContainer): cache cleanup based on shadows stats (#853)
Browse files Browse the repository at this point in the history
(cherry picked from commit b7a3364)
  • Loading branch information
roubachof authored and mergify[bot] committed Oct 6, 2023
1 parent 34124b0 commit 99b596b
Showing 1 changed file with 74 additions and 4 deletions.
78 changes: 74 additions & 4 deletions src/Uno.Toolkit.Skia.WinUI/Controls/Shadows/ShadowsCache.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.Extensions.Logging;
using SkiaSharp;
using Uno.Extensions;
Expand All @@ -8,9 +12,19 @@
namespace Uno.Toolkit.UI;
public class ShadowsCache
{
private const int CleanupInterval = 30;

private static readonly ILogger _logger = typeof(ShadowsCache).Log();

private readonly ConcurrentDictionary<string, CacheBucket> _shadowsCache = new ConcurrentDictionary<string, CacheBucket>();
private static readonly Func<CacheBucket, DateTime, bool> OneHitSinceAShortTime =
(bucket, time) => bucket.Hit == 1 && (time - bucket.LastHit).TotalMinutes > 1;

private static readonly Func<CacheBucket, DateTime, bool> SeveralHitsSinceALongTime =
(bucket, time) => bucket.Hit > 1 && (time - bucket.LastHit).TotalMinutes > 3;

private readonly ConcurrentDictionary<string, CacheBucket> _shadowsCache = new();

private DateTime _lastCleanupUtcTime = DateTime.UtcNow;

public void AddOrUpdate(string key, SKImage image)
{
Expand All @@ -19,17 +33,17 @@ public void AddOrUpdate(string key, SKImage image)
_logger.Trace($"[ShadowsCache] AddOrUpdate => key: {key}");
}

var bucket = _shadowsCache.AddOrUpdate(
_shadowsCache.AddOrUpdate(
key,
(key) =>
_ =>
{
if (_logger.IsEnabled(LogLevel.Trace))
{
_logger.Trace($"[ShadowsCache] inserting new shadow in cache");
}
return new CacheBucket(image);
},
(key, existing) =>
(_, existing) =>
{
existing.AddHit();
if (_logger.IsEnabled(LogLevel.Trace))
Expand All @@ -38,6 +52,8 @@ public void AddOrUpdate(string key, SKImage image)
}
return existing;
});

CleanupIfNeeded();
}

public bool TryGetValue(string key, out SKImage? image)
Expand All @@ -46,6 +62,7 @@ public bool TryGetValue(string key, out SKImage? image)
{
_logger.Trace($"[ShadowsCache] TryGet => key: {key}");
}

if (_shadowsCache.TryGetValue(key, out var bucket))
{
bucket.AddHit();
Expand Down Expand Up @@ -101,4 +118,57 @@ public void AddHit()
LastHit = DateTime.UtcNow;
}
}

public async void CleanupIfNeeded()
{
if (!_shadowsCache.IsEmpty && (DateTime.UtcNow - _lastCleanupUtcTime).TotalSeconds > CleanupInterval)
{
try
{
await CleanupAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.Warn($"[ShadowsCache] Cleanup failed: {ex}");
}
}
}

/// <summary>
/// Removing old shadows based on their stats.
/// </summary>
private Task CleanupAsync()
{
_lastCleanupUtcTime = DateTime.UtcNow;

return Task.Run(() =>
{
var stopwatch = new Stopwatch();
if (_logger.IsEnabled(LogLevel.Trace))
{
stopwatch.Start();
_logger.Trace($"[ShadowsCache] Cleanup starting");
}
DateTime utcNow = DateTime.UtcNow;
int removedShadows = 0;
foreach (var expiredBucket in _shadowsCache
.Where(x => OneHitSinceAShortTime(x.Value, utcNow) || SeveralHitsSinceALongTime(x.Value, utcNow)))
{
if (_shadowsCache.TryRemove(expiredBucket.Key, out _))
{
removedShadows++;
}
}
if (_logger.IsEnabled(LogLevel.Trace))
{
stopwatch.Stop();
if (_logger.IsEnabled(LogLevel.Trace))
{
_logger.Trace($"[ShadowsCache] Cleanup done in {stopwatch.ElapsedMilliseconds} ms ({removedShadows} shadows removed)");
}
}
});
}
}

0 comments on commit 99b596b

Please sign in to comment.