-
-
Notifications
You must be signed in to change notification settings - Fork 56
/
ResourceCache{TEntity}.cs
119 lines (97 loc) · 3.72 KB
/
ResourceCache{TEntity}.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using k8s;
using k8s.Models;
using KellermanSoftware.CompareNetObjects;
using KubeOps.Operator.DevOps;
using KubeOps.Operator.Entities.Extensions;
namespace KubeOps.Operator.Caching
{
internal class ResourceCache<TEntity>
where TEntity : IKubernetesObject<V1ObjectMeta>
{
private const string ResourceVersion = "ResourceVersion";
private const string ManagedFields = "ManagedFields";
private const string Finalizers = "Metadata.Finalizers";
private const string Status = "Status";
private readonly CompareLogic _compare = new(
new()
{
Caching = true,
AutoClearCache = false,
MembersToIgnore = new() { ResourceVersion, ManagedFields },
});
private readonly ConcurrentDictionary<string, TEntity> _cache = new();
private readonly ResourceCacheMetrics<TEntity> _metrics;
public ResourceCache(ResourceCacheMetrics<TEntity> metrics)
{
_metrics = metrics;
}
public TEntity Get(string id) => _cache[id];
public TEntity Upsert(TEntity resource, out CacheComparisonResult result)
{
result = CompareCache(resource);
var clone = resource.DeepClone();
if (clone == null)
{
throw new ArgumentNullException(nameof(clone));
}
_cache.AddOrUpdate(resource.Metadata.Uid, clone, (_, _) => clone);
_metrics.CachedItemsSize.Set(_cache.Count);
_metrics.CachedItemsSummary.Observe(_cache.Count);
return resource;
}
public void Fill(IEnumerable<TEntity> resources)
{
foreach (var entity in resources)
{
var clone = entity.DeepClone();
if (clone == null)
{
throw new ArgumentNullException(nameof(clone));
}
_cache.AddOrUpdate(entity.Metadata.Uid, clone, (_, _) => clone);
}
_metrics.CachedItemsSize.Set(_cache.Count);
_metrics.CachedItemsSummary.Observe(_cache.Count);
}
public void Remove(TEntity resource) => Remove(resource.Metadata.Uid);
public void Clear()
{
_cache.Clear();
_metrics.CachedItemsSize.Set(_cache.Count);
_metrics.CachedItemsSummary.Observe(_cache.Count);
}
private CacheComparisonResult CompareCache(TEntity resource)
{
if (!Exists(resource))
{
return CacheComparisonResult.Other;
}
var cacheObject = _cache[resource.Metadata.Uid];
var comparison = _compare.Compare(resource, cacheObject);
if (comparison.AreEqual)
{
return CacheComparisonResult.Other;
}
if (comparison.Differences.All(d => d.PropertyName.Split('.')[0] == Status))
{
return CacheComparisonResult.StatusModified;
}
if (comparison.Differences.All(d => d.ParentPropertyName == Finalizers || d.PropertyName == Finalizers))
{
return CacheComparisonResult.FinalizersModified;
}
return CacheComparisonResult.Other;
}
private bool Exists(TEntity resource) => _cache.ContainsKey(resource.Metadata.Uid);
private void Remove(string resourceUid)
{
_cache.TryRemove(resourceUid, out _);
_metrics.CachedItemsSize.Set(_cache.Count);
_metrics.CachedItemsSummary.Observe(_cache.Count);
}
}
}