-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Enable DynamoDB entity relationships (#2923)
- Loading branch information
1 parent
c55e43c
commit f70b64a
Showing
20 changed files
with
1,287 additions
and
190 deletions.
There are no files selected for viewing
121 changes: 121 additions & 0 deletions
121
src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Caching/LRUCache.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Caching/LRUHashSet.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Caching/WeakReferenceKey.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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<T> | ||
/// </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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.