Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/src/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ The System.Text.Json library is built-in as part of the shared framework in .NET
<Compile Include="$(CommonPath)Polyfills\BitConverterPolyfills.cs" Link="Common\Polyfills\BitConverterPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\ArrayPolyfills.cs" Link="Common\Polyfills\ArrayPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\RuntimeHelpersPolyfills.cs" Link="Common\Polyfills\RuntimeHelpersPolyfills.cs" />
<Compile Include="$(CommonPath)Polyfills\StopwatchPolyfills.cs" Link="Common\Polyfills\StopwatchPolyfills.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp' or $([MSBuild]::VersionLessThan('$(TargetFrameworkVersion)', '9.0'))">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ internal sealed partial class ReflectionEmitCachingMemberAccessor
private sealed class Cache<TKey> where TKey : notnull
{
private int _evictLock;
private long _lastEvictedTicks; // timestamp of latest eviction operation.
private readonly long _evictionIntervalTicks; // min timespan needed to trigger a new evict operation.
private readonly long _slidingExpirationTicks; // max timespan allowed for cache entries to remain inactive.
private long _lastEvictedTimestamp; // Stopwatch timestamp of the latest eviction operation.
private readonly TimeSpan _evictionInterval; // min duration needed to trigger a new evict operation.
private readonly TimeSpan _slidingExpiration; // max duration allowed for cache entries to remain inactive.
private readonly ConcurrentDictionary<TKey, CacheEntry> _cache = new();

public Cache(TimeSpan slidingExpiration, TimeSpan evictionInterval)
{
_slidingExpirationTicks = slidingExpiration.Ticks;
_evictionIntervalTicks = evictionInterval.Ticks;
_lastEvictedTicks = DateTime.UtcNow.Ticks;
_slidingExpiration = slidingExpiration;
_evictionInterval = evictionInterval;
_lastEvictedTimestamp = Stopwatch.GetTimestamp();
}

public TValue GetOrAdd<TValue>(TKey key, Func<TKey, TValue> valueFactory) where TValue : class?
Expand All @@ -36,17 +36,17 @@ public TValue GetOrAdd<TValue>(TKey key, Func<TKey, TValue> valueFactory) where
#else
key => new(valueFactory(key)));
#endif
long utcNowTicks = DateTime.UtcNow.Ticks;
Volatile.Write(ref entry.LastUsedTicks, utcNowTicks);
long nowTimestamp = Stopwatch.GetTimestamp();
Volatile.Write(ref entry.LastUsedTimestamp, nowTimestamp);

if (utcNowTicks - Volatile.Read(ref _lastEvictedTicks) >= _evictionIntervalTicks)
if (Stopwatch.GetElapsedTime(Volatile.Read(ref _lastEvictedTimestamp), nowTimestamp) >= _evictionInterval)
{
if (Interlocked.CompareExchange(ref _evictLock, 1, 0) == 0)
{
if (utcNowTicks - _lastEvictedTicks >= _evictionIntervalTicks)
if (Stopwatch.GetElapsedTime(_lastEvictedTimestamp, nowTimestamp) >= _evictionInterval)
{
EvictStaleCacheEntries(utcNowTicks);
Volatile.Write(ref _lastEvictedTicks, utcNowTicks);
EvictStaleCacheEntries(nowTimestamp);
Volatile.Write(ref _lastEvictedTimestamp, nowTimestamp);
}

Volatile.Write(ref _evictLock, 0);
Expand All @@ -59,14 +59,14 @@ public TValue GetOrAdd<TValue>(TKey key, Func<TKey, TValue> valueFactory) where
public void Clear()
{
_cache.Clear();
_lastEvictedTicks = DateTime.UtcNow.Ticks;
_lastEvictedTimestamp = Stopwatch.GetTimestamp();
}

private void EvictStaleCacheEntries(long utcNowTicks)
private void EvictStaleCacheEntries(long nowTimestamp)
{
foreach (KeyValuePair<TKey, CacheEntry> kvp in _cache)
{
if (utcNowTicks - Volatile.Read(ref kvp.Value.LastUsedTicks) >= _slidingExpirationTicks)
if (Stopwatch.GetElapsedTime(Volatile.Read(ref kvp.Value.LastUsedTimestamp), nowTimestamp) >= _slidingExpiration)
{
_cache.TryRemove(kvp.Key, out _);
}
Expand All @@ -76,7 +76,7 @@ private void EvictStaleCacheEntries(long utcNowTicks)
private sealed class CacheEntry
{
public readonly object? Value;
public long LastUsedTicks;
public long LastUsedTimestamp;

public CacheEntry(object? value)
{
Expand Down
Loading