Skip to content

Commit 322e3bc

Browse files
TagHelperCollection Prelude: Support types and helpers (#12503)
| Prelude | [Part 1](#12504) | [Part 2](#12505) | [Part 3](#12506) | [Part 4](#12507) | [Part 5](#12509) | This is a set of support utilities and helpers added as part of the `TagHelperCollection` changes: - Added `InterlockedOperations.Initialize(...)` overloads for lock free initialization with a factory method. (f3686aa) - Added two `LazyValue` structs that use the new `InterlockedOperations.Initialize(...)` overloads. These are useful for lazily initializing a value without extra allocations or locks. (81795f5) - Added `OverloadResolutionPriorityAttribute` polyfill type. (27ab174) - Refactored `TagHelperCache` to extract `CleanableWeakCache<TKey, TValue>`. This caches items as weak references. When the number of items added reaches a configurable threshold, the cache is cleaned up, and any dead weak references are removed. (673a9b5) ---- CI Build: https://dev.azure.com/dnceng/internal/_build/results?buildId=2842136&view=results Toolset Run: https://dev.azure.com/dnceng/internal/_build/results?buildId=2842197&view=results
2 parents 80cf794 + 3617eab commit 322e3bc

File tree

8 files changed

+1686
-88
lines changed

8 files changed

+1686
-88
lines changed
Lines changed: 4 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,19 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System;
5-
using System.Collections.Generic;
6-
using System.Diagnostics.CodeAnalysis;
74
using Microsoft.AspNetCore.Razor.Language;
8-
using Microsoft.AspNetCore.Razor.PooledObjects;
95
using Microsoft.AspNetCore.Razor.Utilities;
106

117
namespace Microsoft.CodeAnalysis.Razor.Utilities;
128

13-
internal sealed class TagHelperCache
9+
internal sealed class TagHelperCache : CleanableWeakCache<Checksum, TagHelperDescriptor>
1410
{
15-
public static readonly TagHelperCache Default = new();
16-
17-
private readonly Dictionary<Checksum, WeakReference<TagHelperDescriptor>> _checksumToTagHelperMap = new();
18-
1911
private const int CleanUpThreshold = 200;
20-
private int _addsSinceLastCleanUp;
21-
22-
public TagHelperCache()
23-
{
24-
}
2512

26-
public TagHelperDescriptor GetOrAdd(Checksum checksum, TagHelperDescriptor tagHelper)
27-
{
28-
lock (_checksumToTagHelperMap)
29-
{
30-
// Note: This returns null if tagHelper was added to the cache.
31-
return TryAddOrGet_NoLock(checksum, tagHelper) ?? tagHelper;
32-
}
33-
}
34-
35-
public bool TryAdd(Checksum checksum, TagHelperDescriptor tagHelper)
36-
{
37-
lock (_checksumToTagHelperMap)
38-
{
39-
// Note: This returns null if tagHelper was added to the cache.
40-
return TryAddOrGet_NoLock(checksum, tagHelper) is null;
41-
}
42-
}
43-
44-
/// <summary>
45-
/// Try to add the given tag helper to the cache. If it already exists, return the cached instance.
46-
/// </summary>
47-
private TagHelperDescriptor? TryAddOrGet_NoLock(Checksum checksum, TagHelperDescriptor tagHelper)
48-
{
49-
if (++_addsSinceLastCleanUp >= CleanUpThreshold)
50-
{
51-
CleanUpDeadObjects_NoLock();
52-
}
53-
54-
if (!_checksumToTagHelperMap.TryGetValue(checksum, out var weakRef))
55-
{
56-
_checksumToTagHelperMap.Add(checksum, new(tagHelper));
57-
return null;
58-
}
59-
60-
if (!weakRef.TryGetTarget(out var cachedTagHelper))
61-
{
62-
weakRef.SetTarget(tagHelper);
63-
return null;
64-
}
65-
66-
return cachedTagHelper;
67-
}
68-
69-
public bool TryGet(Checksum checksum, [NotNullWhen(true)] out TagHelperDescriptor? tagHelper)
70-
{
71-
lock (_checksumToTagHelperMap)
72-
{
73-
if (_checksumToTagHelperMap.TryGetValue(checksum, out var weakRef) &&
74-
weakRef.TryGetTarget(out tagHelper))
75-
{
76-
return true;
77-
}
78-
79-
tagHelper = null;
80-
return false;
81-
}
82-
}
13+
public static readonly TagHelperCache Default = new();
8314

84-
private void CleanUpDeadObjects_NoLock()
15+
public TagHelperCache()
16+
: base(CleanUpThreshold)
8517
{
86-
using var deadChecksums = new PooledArrayBuilder<Checksum>();
87-
88-
foreach (var (checksum, weakRef) in _checksumToTagHelperMap)
89-
{
90-
if (!weakRef.TryGetTarget(out _))
91-
{
92-
deadChecksums.Add(checksum);
93-
}
94-
}
95-
96-
foreach (var checksum in deadChecksums)
97-
{
98-
_checksumToTagHelperMap.Remove(checksum);
99-
}
100-
101-
_addsSinceLastCleanUp = 0;
10218
}
10319
}

0 commit comments

Comments
 (0)