namespace NATS.Server.Auth;
///
/// Fixed-capacity LRU cache for permission results.
/// Lock-protected (per-client, low contention).
/// Reference: Go client.go maxPermCacheSize=128.
///
public sealed class PermissionLruCache
{
private readonly int _capacity;
private readonly Dictionary> _map;
private readonly LinkedList<(string Key, bool Value)> _list = new();
private readonly object _lock = new();
public PermissionLruCache(int capacity = 128)
{
_capacity = capacity;
_map = new Dictionary>(capacity, StringComparer.Ordinal);
}
public bool TryGet(string key, out bool value)
{
lock (_lock)
{
if (_map.TryGetValue(key, out var node))
{
value = node.Value.Value;
_list.Remove(node);
_list.AddFirst(node);
return true;
}
value = default;
return false;
}
}
public int Count
{
get
{
lock (_lock)
{
return _map.Count;
}
}
}
public void Set(string key, bool value)
{
lock (_lock)
{
if (_map.TryGetValue(key, out var existing))
{
_list.Remove(existing);
existing.Value = (key, value);
_list.AddFirst(existing);
return;
}
if (_map.Count >= _capacity)
{
var last = _list.Last!;
_map.Remove(last.Value.Key);
_list.RemoveLast();
}
var node = new LinkedListNode<(string Key, bool Value)>((key, value));
_list.AddFirst(node);
_map[key] = node;
}
}
}