diff --git a/src/Server/Controllers/SearchdomainController.cs b/src/Server/Controllers/SearchdomainController.cs index 2acf8dd..ffd1e8e 100644 --- a/src/Server/Controllers/SearchdomainController.cs +++ b/src/Server/Controllers/SearchdomainController.cs @@ -286,7 +286,7 @@ public class SearchdomainController : ControllerBase { (Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger); if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message}); - long sizeInBytes = DatabaseHelper.GetSearchdomainDatabaseSize(searchdomain_.helper, searchdomain); - return Ok(new SearchdomainGetDatabaseSizeResult() { SearchdomainDatabaseSizeBytes = sizeInBytes, Success = true }); + long EmbeddingCacheUtilization = DatabaseHelper.GetSearchdomainDatabaseSize(searchdomain_.helper, searchdomain); + return Ok(new SearchdomainGetDatabaseSizeResult() { SearchdomainDatabaseSizeBytes = EmbeddingCacheUtilization, Success = true }); } } diff --git a/src/Server/Controllers/ServerController.cs b/src/Server/Controllers/ServerController.cs index 7fd23a0..494dae3 100644 --- a/src/Server/Controllers/ServerController.cs +++ b/src/Server/Controllers/ServerController.cs @@ -80,6 +80,9 @@ public class ServerController : ControllerBase var sqlHelper = DatabaseHelper.GetSQLHelper(_options.Value); Task entityCountTask = DatabaseHelper.CountEntities(sqlHelper); long queryCacheUtilization = 0; + long queryCacheElementCount = 0; + long queryCacheMaxElementCountAll = 0; + long queryCacheMaxElementCountLoadedSearchdomainsOnly = 0; foreach (string searchdomain in _searchdomainManager.ListSearchdomains()) { if (SearchdomainHelper.IsSearchdomainLoaded(_searchdomainManager, searchdomain)) @@ -87,10 +90,29 @@ public class ServerController : ControllerBase (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(); + queryCacheElementCount += searchdomain_.queryCache.Count; + queryCacheMaxElementCountAll += searchdomain_.queryCache.Capacity; + queryCacheMaxElementCountLoadedSearchdomainsOnly += searchdomain_.queryCache.Capacity; + } else + { + var searchdomainSettings = DatabaseHelper.GetSearchdomainSettings(sqlHelper, searchdomain); + queryCacheMaxElementCountAll += searchdomainSettings.QueryCacheSize; } }; long entityCount = await entityCountTask; - return new ServerGetStatsResult() { Success = true, EntityCount = entityCount, QueryCacheUtilization = queryCacheUtilization, SizeInBytes = size, MaxElementCount = _searchdomainManager.EmbeddingCacheMaxCount, ElementCount = elementCount, EmbeddingsCount = embeddingsCount}; + + return new ServerGetStatsResult() { + Success = true, + EntityCount = entityCount, + QueryCacheUtilization = queryCacheUtilization, + QueryCacheElementCount = queryCacheElementCount, + QueryCacheMaxElementCountAll = queryCacheMaxElementCountAll, + QueryCacheMaxElementCountLoadedSearchdomainsOnly = queryCacheMaxElementCountLoadedSearchdomainsOnly, + EmbeddingCacheUtilization = size, + EmbeddingCacheMaxElementCount = _searchdomainManager.EmbeddingCacheMaxCount, + EmbeddingCacheElementCount = elementCount, + EmbeddingsCount = embeddingsCount + }; } catch (Exception ex) { ElmahExtensions.RaiseError(ex); diff --git a/src/Server/Helper/DatabaseHelper.cs b/src/Server/Helper/DatabaseHelper.cs index c4336c8..5183fbe 100644 --- a/src/Server/Helper/DatabaseHelper.cs +++ b/src/Server/Helper/DatabaseHelper.cs @@ -1,6 +1,7 @@ using System.Configuration; using System.Data.Common; using System.Text; +using System.Text.Json; using MySql.Data.MySqlClient; using Server.Exceptions; using Server.Models; @@ -244,4 +245,22 @@ public class DatabaseHelper(ILogger logger) searchdomainSumReader.Close(); return result; } + + public static SearchdomainSettings GetSearchdomainSettings(SQLHelper helper, string searchdomain) + { + Dictionary parameters = new() + { + ["name"] = searchdomain + }; + DbDataReader reader = helper.ExecuteSQLCommand("SELECT settings from searchdomain WHERE name = @name", parameters); + try + { + reader.Read(); + string settingsString = reader.GetString(0); + return JsonSerializer.Deserialize(settingsString); + } finally + { + reader.Close(); + } + } } \ No newline at end of file diff --git a/src/Server/Resources/SharedResources.de.resx b/src/Server/Resources/SharedResources.de.resx index 04636c2..633a8a9 100644 --- a/src/Server/Resources/SharedResources.de.resx +++ b/src/Server/Resources/SharedResources.de.resx @@ -300,4 +300,19 @@ Searchdomain Datenbank-Auslastung konnte nicht abgerufen werden + + Query-Cache Einträge + + + Query-Cache Kapazität (alle) + + + Anzahl der Einträge, die insgesamt in den Query-Cache passen. Ungeladene Searchdomains werden berücksichtigt. + + + Query-Cache Kapazität (geladen) + + + Anzahl der Einträge, die insgesamt in den Query-Cache der geladenen Searchdomains passen. + \ No newline at end of file diff --git a/src/Server/Resources/SharedResources.en.resx b/src/Server/Resources/SharedResources.en.resx index 000c7bc..f19d653 100644 --- a/src/Server/Resources/SharedResources.en.resx +++ b/src/Server/Resources/SharedResources.en.resx @@ -300,4 +300,19 @@ Unable to fetch searchdomain database utilization + + Query cache entry count + + + Query cache capacity (all) + + + Number of query cache entries that can be stored in the query cache, including searchdomains that are currently not loaded. + + + Query cache capacity (loaded) + + + Number of query cache entries that can be stored in the query cache of all loaded searchdomains. + \ No newline at end of file diff --git a/src/Server/Searchdomain.cs b/src/Server/Searchdomain.cs index ce5cc12..e856947 100644 --- a/src/Server/Searchdomain.cs +++ b/src/Server/Searchdomain.cs @@ -278,15 +278,7 @@ public class Searchdomain public SearchdomainSettings GetSettings() { - Dictionary parameters = new() - { - ["name"] = searchdomain - }; - DbDataReader reader = helper.ExecuteSQLCommand("SELECT settings from searchdomain WHERE name = @name", parameters); - reader.Read(); - string settingsString = reader.GetString(0); - reader.Close(); - return JsonSerializer.Deserialize(settingsString); + return DatabaseHelper.GetSearchdomainSettings(helper, searchdomain); } public void ReconciliateOrInvalidateCacheForNewOrUpdatedEntity(Entity entity) @@ -343,13 +335,13 @@ public class Searchdomain public long GetSearchCacheSize() { - long sizeInBytes = 0; + long EmbeddingCacheUtilization = 0; foreach (var entry in queryCache) { - sizeInBytes += sizeof(int); // string length prefix - sizeInBytes += entry.Key.Length * sizeof(char); // string characters - sizeInBytes += entry.Value.EstimateSize(); + EmbeddingCacheUtilization += sizeof(int); // string length prefix + EmbeddingCacheUtilization += entry.Key.Length * sizeof(char); // string characters + EmbeddingCacheUtilization += entry.Value.EstimateSize(); } - return sizeInBytes; + return EmbeddingCacheUtilization; } } diff --git a/src/Server/Views/Home/Index.cshtml b/src/Server/Views/Home/Index.cshtml index 12f5004..ea70424 100644 --- a/src/Server/Views/Home/Index.cshtml +++ b/src/Server/Views/Home/Index.cshtml @@ -104,6 +104,43 @@ @T["Total query cache utilization"] + + +
+ @T["Query cache entry count"] + +
+ +
+ + @T["Query cache capacity (loaded)"] + + + +
+ +
+
+
+ + +
+ + @T["Query cache capacity (all)"] + + + +
+ +
+
+
@@ -135,6 +172,17 @@ let embeddingcacheEmbeddingCount = document.getElementById("embeddingcacheEmbeddingCount"); showThrobber(embeddingcacheEmbeddingCount); let embeddingcacheElementCountProgressBar = document.getElementById("embeddingcacheElementCountProgressBar"); + + let querycacheCount = document.getElementById("querycacheCount"); + showThrobber(querycacheCount); + let querycacheMaxElementCount = document.getElementById("querycacheMaxElementCount"); + showThrobber(querycacheMaxElementCount); + let querycacheMaxElementCountProgressBar = document.getElementById("querycacheMaxElementCountProgressBar"); + let querycacheLoadedMaxElementCount = document.getElementById("querycacheLoadedMaxElementCount"); + showThrobber(querycacheLoadedMaxElementCount); + let querycacheLoadedElementCountProgressBar = document.getElementById("querycacheLoadedElementCountProgressBar"); + + let healthchecksServer = document.getElementById("healthchecksServer"); let healthchecksAiProvider = document.getElementById("healthchecksAiProvider"); @@ -145,23 +193,34 @@ searchdomainCount.textContent = searchdomains.length; }); getServerStats().then(result => { - let utilization = result.SizeInBytes; - let maxElementCount = result.MaxElementCount; - let elementCount = result.ElementCount; + let utilization = result.EmbeddingCacheUtilization; + let embeddingCacheMaxElementCount = result.EmbeddingCacheMaxElementCount; + let embeddingCacheElementCount = result.ElementCount; let embeddingCount = result.EmbeddingsCount; let entityCount = result.EntityCount; let queryCacheUtilization = result.QueryCacheUtilization; + let queryCacheElementCount = result.QueryCacheElementCount; + let queryCacheMaxElementCountAll = result.QueryCacheMaxElementCountAll; + let queryCacheMaxElementCountLoadedSearchdomainsOnly = result.QueryCacheMaxElementCountLoadedSearchdomainsOnly; hideThrobber(embeddingcacheSize); embeddingcacheSize.textContent = NumberOfBytesAsHumanReadable(utilization); hideThrobber(embeddingcacheElementCount); - embeddingcacheElementCount.textContent = `${elementCount.toLocaleString()} / ${maxElementCount.toLocaleString()}`; + embeddingcacheElementCount.textContent = `${embeddingCacheElementCount.toLocaleString()} / ${embeddingCacheMaxElementCount.toLocaleString()}`; hideThrobber(embeddingcacheEmbeddingCount); embeddingcacheEmbeddingCount.textContent = embeddingCount; - embeddingcacheElementCountProgressBar.style.width = `${elementCount / maxElementCount * 100}%`; + embeddingcacheElementCountProgressBar.style.width = `${embeddingCacheElementCount / embeddingCacheMaxElementCount * 100}%`; hideThrobber(searchdomainEntityCount); searchdomainEntityCount.textContent = entityCount; hideThrobber(totalQuerycacheUtilization); totalQuerycacheUtilization.textContent = NumberOfBytesAsHumanReadable(queryCacheUtilization); + hideThrobber(querycacheMaxElementCount); + querycacheCount.textContent = queryCacheElementCount; + hideThrobber(querycacheCount); + querycacheMaxElementCount.textContent = queryCacheMaxElementCountAll.toLocaleString(); + querycacheMaxElementCountProgressBar.style.width = `${queryCacheElementCount / queryCacheMaxElementCountAll * 100}%`; + hideThrobber(querycacheLoadedMaxElementCount); + querycacheLoadedMaxElementCount.textContent = queryCacheMaxElementCountLoadedSearchdomainsOnly.toLocaleString(); + querycacheLoadedMaxElementCountProgressBar.style.width = `${queryCacheElementCount / queryCacheMaxElementCountLoadedSearchdomainsOnly * 100}%`; }); getHealthCheckStatusAndApply(healthchecksServer, "/healthz/Database"); getHealthCheckStatusAndApply(healthchecksAiProvider, "/healthz/AIProvider"); diff --git a/src/Shared/Models/ServerModels.cs b/src/Shared/Models/ServerModels.cs index 2ad0eae..59905fd 100644 --- a/src/Shared/Models/ServerModels.cs +++ b/src/Shared/Models/ServerModels.cs @@ -10,16 +10,22 @@ public class ServerGetModelsResult : SuccesMessageBaseModel public class ServerGetStatsResult : SuccesMessageBaseModel { - [JsonPropertyName("SizeInBytes")] - public long? SizeInBytes { get; set; } - [JsonPropertyName("MaxElementCount")] - public long? MaxElementCount { get; set; } + [JsonPropertyName("EmbeddingCacheUtilization")] + public long? EmbeddingCacheUtilization { get; set; } + [JsonPropertyName("EmbeddingCacheMaxElementCount")] + public long? EmbeddingCacheMaxElementCount { get; set; } [JsonPropertyName("ElementCount")] - public long? ElementCount { get; set; } + public long? EmbeddingCacheElementCount { get; set; } [JsonPropertyName("EmbeddingsCount")] public long? EmbeddingsCount { get; set; } [JsonPropertyName("EntityCount")] public long? EntityCount { get; set; } + [JsonPropertyName("QueryCacheElementCount")] + public long? QueryCacheElementCount { get; set; } + [JsonPropertyName("QueryCacheMaxElementCountAll")] + public long? QueryCacheMaxElementCountAll { get; set; } + [JsonPropertyName("QueryCacheMaxElementCountLoadedSearchdomainsOnly")] + public long? QueryCacheMaxElementCountLoadedSearchdomainsOnly { get; set; } [JsonPropertyName("QueryCacheUtilization")] public long? QueryCacheUtilization { get; set; } } \ No newline at end of file