@@ -295,17 +295,18 @@ public record EntityHistoryWithOffset(EntityHistory entityHistory, int nextOffse
295295
296296 private record InheritanceCacheKey (String entityType , UUID entityId , String fieldsKey ) {}
297297
298- private static final int STRING_OBJECT_OVERHEAD_BYTES = 40 ;
298+ private static final int ENTITY_OBJECT_OVERHEAD_BYTES = 40 ;
299299
300- // Conservative upper-bound weight for a String: length() * 2 (UTF-16 worst-case) + 40 (header).
301- // On Java 21 with compact strings, LATIN1 content uses fewer bytes, so this overestimates
302- // slightly — which is intentional for memory capping. Zero allocation, single field read.
300+ // Weigh an EntityInterface by its JSON serialization size: length * 2 (UTF-16 worst-case) + 40.
301+ // Serialization happens once on cache write; the resulting byte estimate caps total heap used
302+ // by the cache. Overestimates slightly (compact strings on Java 21 use fewer bytes) — intentional
303+ // for memory safety.
303304 // Defaults used before CacheConfiguration is loaded at startup. initCaches() replaces these.
304- public static volatile LoadingCache <Pair <String , String >, String > CACHE_WITH_NAME =
305+ public static volatile LoadingCache <Pair <String , String >, EntityInterface > CACHE_WITH_NAME =
305306 buildEntityNameCache (
306307 CacheConfiguration .DEFAULT_ENTITY_CACHE_MAX_SIZE_BYTES ,
307308 CacheConfiguration .DEFAULT_ENTITY_CACHE_TTL_SECONDS );
308- public static volatile LoadingCache <Pair <String , UUID >, String > CACHE_WITH_ID =
309+ public static volatile LoadingCache <Pair <String , UUID >, EntityInterface > CACHE_WITH_ID =
309310 buildEntityIdCache (
310311 CacheConfiguration .DEFAULT_ENTITY_CACHE_MAX_SIZE_BYTES ,
311312 CacheConfiguration .DEFAULT_ENTITY_CACHE_TTL_SECONDS );
@@ -327,25 +328,34 @@ public static void initCaches(CacheConfiguration config) {
327328 config .getEntityCacheTTLSeconds ());
328329 }
329330
330- private static LoadingCache <Pair <String , String >, String > buildEntityNameCache (
331+ private static int weighEntity (EntityInterface value ) {
332+ if (value == null ) {
333+ return ENTITY_OBJECT_OVERHEAD_BYTES ;
334+ }
335+ try {
336+ return JsonUtils .pojoToJson (value ).length () * 2 + ENTITY_OBJECT_OVERHEAD_BYTES ;
337+ } catch (Exception e ) {
338+ return ENTITY_OBJECT_OVERHEAD_BYTES ;
339+ }
340+ }
341+
342+ private static LoadingCache <Pair <String , String >, EntityInterface > buildEntityNameCache (
331343 long maxWeightBytes , int ttlSeconds ) {
332344 return CacheBuilder .newBuilder ()
333345 .maximumWeight (maxWeightBytes )
334346 .weigher (
335- (Weigher <Pair <String , String >, String >)
336- (key , value ) -> value .length () * 2 + STRING_OBJECT_OVERHEAD_BYTES )
347+ (Weigher <Pair <String , String >, EntityInterface >) (key , value ) -> weighEntity (value ))
337348 .expireAfterWrite (ttlSeconds , TimeUnit .SECONDS )
338349 .recordStats ()
339350 .build (new EntityLoaderWithName ());
340351 }
341352
342- private static LoadingCache <Pair <String , UUID >, String > buildEntityIdCache (
353+ private static LoadingCache <Pair <String , UUID >, EntityInterface > buildEntityIdCache (
343354 long maxWeightBytes , int ttlSeconds ) {
344355 return CacheBuilder .newBuilder ()
345356 .maximumWeight (maxWeightBytes )
346357 .weigher (
347- (Weigher <Pair <String , UUID >, String >)
348- (key , value ) -> value .length () * 2 + STRING_OBJECT_OVERHEAD_BYTES )
358+ (Weigher <Pair <String , UUID >, EntityInterface >) (key , value ) -> weighEntity (value ))
349359 .expireAfterWrite (ttlSeconds , TimeUnit .SECONDS )
350360 .recordStats ()
351361 .build (new EntityLoaderWithId ());
0 commit comments