Skip to content

Commit

Permalink
Merge branch 'main' into feature/netstandard-odbc-instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
nr-ahemsath authored Jan 16, 2025
2 parents 82aaafe + ee0dd2b commit 7ac9299
Show file tree
Hide file tree
Showing 22 changed files with 1,290 additions and 192 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build_buildtools.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Add msbuild to PATH (required for MsiInstaller build)
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
Expand Down
3 changes: 2 additions & 1 deletion FullAgent.sln
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Home", "src\Agent\NewRelic\
{4F5D77F3-B41A-44A7-AF10-2D5462CE0162} = {4F5D77F3-B41A-44A7-AF10-2D5462CE0162}
{570429FD-C785-4673-82DF-643D06B6DC53} = {570429FD-C785-4673-82DF-643D06B6DC53}
{5BBEEC11-B753-4631-BCDD-43BE73B5CCAC} = {5BBEEC11-B753-4631-BCDD-43BE73B5CCAC}
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661} = {5D74E5C5-9BA3-423B-86F7-14C2D1A14661}
{614988AD-7C73-4E71-8F95-520D5F485984} = {614988AD-7C73-4E71-8F95-520D5F485984}
{64C7F267-5185-4AB7-9EB5-0183D8BB0171} = {64C7F267-5185-4AB7-9EB5-0183D8BB0171}
{686AE051-BC8C-4AEC-803D-237AEB807CA9} = {686AE051-BC8C-4AEC-803D-237AEB807CA9}
Expand Down Expand Up @@ -540,8 +541,8 @@ Global
{5D74E5C5-9BA3-423B-86F7-14C2D1A14661} = {5E86E10A-C38F-48CB-ADE9-67B22BB2F50A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D8B98070-6B8E-403C-A07F-A3F2E4A3A3D0}
EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35
SolutionGuid = {D8B98070-6B8E-403C-A07F-A3F2E4A3A3D0}
EndGlobalSection
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = FullAgent.vsmdi
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections.Generic;
using System.Threading;

namespace NewRelic.Agent.Extensions.Caching
{
/// <summary>
/// A thread-safe LRU cache implementation.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class LRUCache<TKey, TValue>
{
private readonly int _capacity;
private readonly Dictionary<TKey, LinkedListNode<CacheItem>> _cacheMap;
private readonly LinkedList<CacheItem> _lruList;
private readonly ReaderWriterLockSlim _lock = new();

public LRUCache(int capacity)
{
if (capacity <= 0)
{
throw new ArgumentException("Capacity must be greater than zero.", nameof(capacity));
}

_capacity = capacity;
_cacheMap = new Dictionary<TKey, LinkedListNode<CacheItem>>(capacity);
_lruList = new LinkedList<CacheItem>();
}

public TValue Get(TKey key)
{
_lock.EnterUpgradeableReadLock();
try
{
if (_cacheMap.TryGetValue(key, out var node))
{
// Move the accessed node to the front of the list
_lock.EnterWriteLock();
try
{
_lruList.Remove(node);
_lruList.AddFirst(node);
}
finally
{
_lock.ExitWriteLock();
}
return node.Value.Value;
}
throw new KeyNotFoundException("The given key was not present in the cache.");
}
finally
{
_lock.ExitUpgradeableReadLock();
}
}

public void Put(TKey key, TValue value)
{
_lock.EnterWriteLock();
try
{
if (_cacheMap.TryGetValue(key, out var node))
{
// Update the value and move the node to the front of the list
node.Value.Value = value;
_lruList.Remove(node);
_lruList.AddFirst(node);
}
else
{
if (_cacheMap.Count >= _capacity)
{
// Remove the least recently used item
var lruNode = _lruList.Last;
_cacheMap.Remove(lruNode.Value.Key);
_lruList.RemoveLast();
}

// Add the new item to the cache
var cacheItem = new CacheItem(key, value);
var newNode = new LinkedListNode<CacheItem>(cacheItem);
_lruList.AddFirst(newNode);
_cacheMap[key] = newNode;
}
}
finally
{
_lock.ExitWriteLock();
}
}
public bool ContainsKey(TKey key)
{
_lock.EnterReadLock();
try
{
return _cacheMap.ContainsKey(key);
}
finally
{
_lock.ExitReadLock();
}
}

private class CacheItem
{
public TKey Key { get; }
public TValue Value { get; set; }

public CacheItem(TKey key, TValue value)
{
Key = key;
Value = value;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using System.Collections.Generic;
using System.Threading;

namespace NewRelic.Agent.Extensions.Caching
{
/// <summary>
/// A thread-safe LRU HashSet implementation.
/// </summary>
/// <typeparam name="T"></typeparam>
public class LRUHashSet<T>
{
private readonly int _capacity;
private readonly HashSet<T> _hashSet;
private readonly LinkedList<T> _lruList;
private readonly ReaderWriterLockSlim _lock = new();

public LRUHashSet(int capacity)
{
if (capacity <= 0)
{
throw new ArgumentException("Capacity must be greater than zero.", nameof(capacity));
}

_capacity = capacity;
_hashSet = new HashSet<T>();
_lruList = new LinkedList<T>();
}

public bool Add(T item)
{
_lock.EnterWriteLock();
try
{
if (_hashSet.Contains(item))
{
// Move the accessed item to the front of the list
_lruList.Remove(item);
_lruList.AddFirst(item);
return false;
}
else
{
if (_hashSet.Count >= _capacity)
{
// Remove the least recently used item
var lruItem = _lruList.Last.Value;
_hashSet.Remove(lruItem);
_lruList.RemoveLast();
}

// Add the new item to the set and list
_hashSet.Add(item);
_lruList.AddFirst(item);
return true;
}
}
finally
{
_lock.ExitWriteLock();
}
}

public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return _hashSet.Contains(item);
}
finally
{
_lock.ExitReadLock();
}
}

public bool Remove(T item)
{
_lock.EnterWriteLock();
try
{
if (_hashSet.Remove(item))
{
_lruList.Remove(item);
return true;
}
return false;
}
finally
{
_lock.ExitWriteLock();
}
}

public int Count
{
get
{
_lock.EnterReadLock();
try
{
return _hashSet.Count;
}
finally
{
_lock.ExitReadLock();
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using System;

namespace NewRelic.Agent.Extensions.Caching
{
/// <summary>
/// Creates an object that can be used as a dictionary key, which holds a WeakReference&lt;T&gt;
/// </summary>
/// <typeparam name="T"></typeparam>
public class WeakReferenceKey<T> where T : class
{
private WeakReference<T> WeakReference { get; }

public WeakReferenceKey(T cacheKey)
{
WeakReference = new WeakReference<T>(cacheKey);
}

public override bool Equals(object obj)
{
if (obj is WeakReferenceKey<T> otherKey)
{
if (WeakReference.TryGetTarget(out var thisTarget) &&
otherKey.WeakReference.TryGetTarget(out var otherTarget))
{
return ReferenceEquals(thisTarget, otherTarget);
}
}

return false;
}

public override int GetHashCode()
{
if (WeakReference.TryGetTarget(out var target))
{
return target.GetHashCode();
}

return 0;
}

/// <summary>
/// Gets the value from the WeakReference or null if the target has been garbage collected.
/// </summary>
public T Value => WeakReference.TryGetTarget(out var target) ? target : null;
}
}
Loading

0 comments on commit 7ac9299

Please sign in to comment.