Added query cache size limiting, added custom enumerable LRUCache, renamed search to query in various places, fixed client GetEmbeddingsCacheSize endpoint

This commit is contained in:
2026-01-03 17:57:18 +01:00
parent 063c81e8dc
commit 027a9244ad
7 changed files with 270 additions and 36 deletions

202
src/Shared/LRUCache.cs Normal file
View File

@@ -0,0 +1,202 @@
namespace Shared;
public class EnumerableLruCache<TKey, TValue> where TKey : notnull
{
private readonly Dictionary<TKey, TValue> _cache;
private readonly LinkedList<TKey> _keys = new();
private int _capacity;
private ReaderWriterLockSlim _readerWriterLock;
public int Capacity
{
get
{
_readerWriterLock.EnterReadLock();
try
{
return _capacity;
}
finally
{
_readerWriterLock.ExitReadLock();
}
}
set
{
_readerWriterLock.EnterWriteLock();
try
{
_capacity = value;
// Trim cache if new capacity is smaller than current size
while (_keys.Count > _capacity)
{
TKey last = _keys.Last!.Value;
_keys.RemoveLast();
_cache.Remove(last);
}
}
finally
{
_readerWriterLock.ExitWriteLock();
}
}
}
public EnumerableLruCache(int capacity)
{
_readerWriterLock = new();
_capacity = capacity;
_cache = [];
}
public TValue this[TKey key]
{
get
{
_readerWriterLock.EnterReadLock();
try
{
return _cache[key];
}
finally
{
_readerWriterLock.ExitReadLock();
}
}
set
{
_readerWriterLock.EnterWriteLock();
try
{
if (_cache.TryGetValue(key, out _))
{
_keys.Remove(key);
}
_keys.AddFirst(key);
_cache[key] = value;
if (_keys.Count > _capacity)
{
TKey last = _keys.Last!.Value;
_keys.RemoveLast();
_cache.Remove(last);
}
}
finally
{
_readerWriterLock.ExitWriteLock();
}
}
}
public bool ContainsKey(TKey key)
{
_readerWriterLock.EnterReadLock();
try
{
return _cache.ContainsKey(key);
} finally
{
_readerWriterLock.ExitReadLock();
}
}
public int Count()
{
_readerWriterLock.EnterReadLock();
try
{
return _cache.Count;
} finally
{
_readerWriterLock.ExitReadLock();
}
}
public void Set(TKey key, TValue value)
{
_readerWriterLock.EnterWriteLock();
try
{
if (_cache.TryGetValue(key, out _))
{
_keys.Remove(key);
}
_keys.AddFirst(key);
_cache[key] = value;
if (_keys.Count > _capacity)
{
TKey? last = _keys.Last();
_keys.RemoveLast();
_cache.Remove(last);
}
} finally
{
_readerWriterLock.ExitWriteLock();
}
}
public void Remove(TKey key)
{
_readerWriterLock.EnterWriteLock();
try
{
_keys.Remove(key);
_cache.Remove(key);
} finally
{
_readerWriterLock.ExitWriteLock();
}
}
public bool TryGetValue(TKey key, out TValue? value)
{
_readerWriterLock.EnterReadLock();
try
{
return _cache.TryGetValue(key, out value);
} finally
{
_readerWriterLock.ExitReadLock();
}
}
public Dictionary<TKey, TValue> AsDictionary()
{
_readerWriterLock.EnterReadLock();
try
{
return new Dictionary<TKey, TValue>(_cache);
}
finally
{
_readerWriterLock.ExitReadLock();
}
}
public IEnumerable<KeyValuePair<TKey, TValue>> Items()
{
_readerWriterLock.EnterReadLock();
try
{
foreach (var key in _keys)
{
if (_cache.TryGetValue(key, out var value))
{
yield return new KeyValuePair<TKey, TValue>(key, value);
}
}
} finally
{
_readerWriterLock.ExitReadLock();
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Items().GetEnumerator();
}
}