Replaced GetEmbeddingCacheSize with GetStats, fixed long loading times for front-end stats retrieval

This commit is contained in:
2026-01-02 02:04:19 +01:00
parent 09832d1c0b
commit aa4fc03c3d
9 changed files with 140 additions and 76 deletions

View File

@@ -5,8 +5,10 @@ using System.Text.Json;
using AdaptiveExpressions;
using ElmahCore;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Server.Exceptions;
using Server.Helper;
using Server.Models;
using Shared.Models;
[ApiController]
@@ -17,13 +19,15 @@ public class ServerController : ControllerBase
private readonly IConfiguration _config;
private AIProvider _aIProvider;
private readonly SearchdomainManager _searchdomainManager;
private readonly IOptions<EmbeddingSearchOptions> _options;
public ServerController(ILogger<ServerController> logger, IConfiguration config, AIProvider aIProvider, SearchdomainManager searchdomainManager)
public ServerController(ILogger<ServerController> logger, IConfiguration config, AIProvider aIProvider, SearchdomainManager searchdomainManager, IOptions<EmbeddingSearchOptions> options)
{
_logger = logger;
_config = config;
_aIProvider = aIProvider;
_searchdomainManager = searchdomainManager;
_options = options;
}
/// <summary>
@@ -47,31 +51,51 @@ public class ServerController : ControllerBase
}
/// <summary>
/// Gets the total memory size of the embedding cache
/// Gets numeric info regarding the searchdomains
/// </summary>
[HttpGet("EmbeddingCache/Size")]
public ActionResult<ServerGetEmbeddingCacheSizeResult> GetEmbeddingCacheSize()
[HttpGet("Stats")]
public async Task<ActionResult<ServerGetStatsResult>> Stats()
{
long size = 0;
long elementCount = 0;
long embeddingsCount = 0;
LRUCache<string, Dictionary<string, float[]>> embeddingCache = _searchdomainManager.embeddingCache;
var cacheListField = embeddingCache.GetType()
.GetField("_cacheList", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException("_cacheList field not found"); // TODO Remove this unsafe reflection atrocity
LinkedList<string> cacheListOriginal = (LinkedList<string>)cacheListField.GetValue(embeddingCache)!;
LinkedList<string> cacheList = new(cacheListOriginal);
foreach (string key in cacheList)
try
{
if (!embeddingCache.TryGet(key, out var entry))
continue;
long size = 0;
long elementCount = 0;
long embeddingsCount = 0;
LRUCache<string, Dictionary<string, float[]>> embeddingCache = _searchdomainManager.embeddingCache;
var cacheListField = embeddingCache.GetType()
.GetField("_cacheList", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException("_cacheList field not found"); // TODO Remove this unsafe reflection atrocity
LinkedList<string> cacheListOriginal = (LinkedList<string>)cacheListField.GetValue(embeddingCache)!;
LinkedList<string> cacheList = new(cacheListOriginal);
// estimate size
size += EstimateEntrySize(key, entry);
elementCount++;
embeddingsCount += entry.Keys.Count;
foreach (string key in cacheList)
{
if (!embeddingCache.TryGet(key, out var entry))
continue;
// estimate size
size += EstimateEntrySize(key, entry);
elementCount++;
embeddingsCount += entry.Keys.Count;
}
var sqlHelper = DatabaseHelper.GetSQLHelper(_options.Value);
Task<long> entityCountTask = DatabaseHelper.CountEntities(sqlHelper);
long queryCacheUtilization = 0;
foreach (string searchdomain in _searchdomainManager.ListSearchdomains())
{
if (SearchdomainHelper.IsSearchdomainLoaded(_searchdomainManager, searchdomain))
{
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_searchdomainManager, searchdomain, _logger);
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new ServerGetStatsResult(){Success = false, Message = message});
queryCacheUtilization += searchdomain_.GetSearchCacheSize();
}
};
long entityCount = await entityCountTask;
return new ServerGetStatsResult() { Success = true, EntityCount = entityCount, QueryCacheUtilization = queryCacheUtilization, SizeInBytes = size, MaxElementCount = _searchdomainManager.EmbeddingCacheMaxCount, ElementCount = elementCount, EmbeddingsCount = embeddingsCount};
} catch (Exception ex)
{
ElmahExtensions.RaiseError(ex);
return StatusCode(500, new ServerGetStatsResult(){Success = false, Message = ex.Message});
}
return new ServerGetEmbeddingCacheSizeResult() { Success = true, SizeInBytes = size, MaxElementCount = _searchdomainManager.EmbeddingCacheMaxCount, ElementCount = elementCount, EmbeddingsCount = embeddingsCount};
}
private static long EstimateEntrySize(string key, Dictionary<string, float[]> value)