Cache info storage_location

This commit is contained in:
simonredfern 2026-01-01 03:40:41 +01:00
parent a366afaad4
commit 5e00e012db
4 changed files with 66 additions and 10 deletions

View File

@ -25,4 +25,22 @@ object InMemory extends MdcLoggable {
logger.trace(s"InMemory.memoizeWithInMemory.underlyingGuavaCache size ${underlyingGuavaCache.size()}, current cache key is $cacheKey")
memoize(ttl)(f)
}
/**
* Count keys matching a pattern in the in-memory cache
* @param pattern Pattern to match (supports * wildcard)
* @return Number of matching keys
*/
def countKeys(pattern: String): Int = {
try {
val regex = pattern.replace("*", ".*").r
val allKeys = underlyingGuavaCache.asMap().keySet()
import scala.collection.JavaConverters._
allKeys.asScala.count(key => regex.pattern.matcher(key).matches())
} catch {
case e: Throwable =>
logger.error(s"Error counting in-memory cache keys for pattern $pattern: ${e.getMessage}")
0
}
}
}

View File

@ -733,6 +733,11 @@ trait APIMethods600 {
|- Current version counter
|- Number of keys in each namespace
|- Description and category
|- Storage location (redis, memory, both, or unknown)
| - "redis": Keys stored in Redis
| - "memory": Keys stored in in-memory cache
| - "both": Keys in both locations (indicates a BUG - should never happen)
| - "unknown": No keys found, storage location cannot be determined
|- Total key count across all namespaces
|- Redis availability status
|
@ -749,7 +754,8 @@ trait APIMethods600 {
current_version = 1,
key_count = 42,
description = "Rate limit call counters",
category = "Rate Limiting"
category = "Rate Limiting",
storage_location = "redis"
),
CacheNamespaceInfoJsonV600(
namespace_id = "rd_localised",
@ -757,7 +763,8 @@ trait APIMethods600 {
current_version = 1,
key_count = 128,
description = "Localized resource docs",
category = "API Documentation"
category = "API Documentation",
storage_location = "redis"
)
),
total_keys = 170,

View File

@ -289,7 +289,8 @@ case class CacheNamespaceInfoJsonV600(
current_version: Long,
key_count: Int,
description: String,
category: String
category: String,
storage_location: String
)
case class CacheInfoJsonV600(
@ -1153,7 +1154,7 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
}
def createCacheInfoJsonV600(): CacheInfoJsonV600 = {
import code.api.cache.Redis
import code.api.cache.{Redis, InMemory}
import code.api.Constant
val namespaceDescriptions = Map(
@ -1178,14 +1179,41 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
val prefix = Constant.getVersionedCachePrefix(namespaceId)
val pattern = s"${prefix}*"
val keyCount = try {
val count = Redis.countKeys(pattern)
totalKeys += count
count
// Dynamically determine storage location by checking where keys exist
var redisKeyCount = 0
var memoryKeyCount = 0
var storageLocation = "unknown"
try {
redisKeyCount = Redis.countKeys(pattern)
totalKeys += redisKeyCount
} catch {
case _: Throwable =>
redisAvailable = false
0
}
try {
memoryKeyCount = InMemory.countKeys(pattern)
totalKeys += memoryKeyCount
} catch {
case _: Throwable =>
// In-memory cache error (shouldn't happen, but handle gracefully)
}
// Determine storage based on where keys actually exist
val keyCount = if (redisKeyCount > 0 && memoryKeyCount > 0) {
storageLocation = "both"
redisKeyCount + memoryKeyCount
} else if (redisKeyCount > 0) {
storageLocation = "redis"
redisKeyCount
} else if (memoryKeyCount > 0) {
storageLocation = "memory"
memoryKeyCount
} else {
// No keys found in either location - we don't know where they would be stored
storageLocation = "unknown"
0
}
val (description, category) = namespaceDescriptions.getOrElse(namespaceId, ("Unknown namespace", "Other"))
@ -1196,7 +1224,8 @@ object JSONFactory600 extends CustomJsonFormats with MdcLoggable {
current_version = version,
key_count = keyCount,
description = description,
category = category
category = category,
storage_location = storageLocation
)
}

View File

@ -156,6 +156,8 @@ class CacheEndpointsTest extends V600ServerSetup {
namespace.key_count should be >= 0
namespace.description should not be empty
namespace.category should not be empty
namespace.storage_location should not be empty
namespace.storage_location should (equal("redis") or equal("memory") or equal("both") or equal("unknown"))
}
}
}