diff --git a/default/config.yaml b/default/config.yaml index 559e34638..f4bacf9ff 100644 --- a/default/config.yaml +++ b/default/config.yaml @@ -138,8 +138,8 @@ performance: # Enables lazy loading of character cards. Improves performances with large card libraries. # May have compatibility issues with some extensions. lazyLoadCharacters: false - # The maximum amount of memory that parsed character cards can use in MB - cardsCacheCapacity: 100 + # The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching. + memoryCacheCapacity: '100mb' # Allow secret keys exposure via API allowKeysExposure: false diff --git a/post-install.js b/post-install.js index 3ff1fc080..0048d9c6f 100644 --- a/post-install.js +++ b/post-install.js @@ -98,8 +98,8 @@ const keyMigrationMap = [ }, { oldKey: 'cardsCacheCapacity', - newKey: 'performance.cardsCacheCapacity', - migrate: (value) => value, + newKey: 'performance.memoryCacheCapacity', + migrate: (value) => `${value}mb`, }, // uncomment one release after 1.12.13 /* diff --git a/src/endpoints/characters.js b/src/endpoints/characters.js index f70e6d9c1..eb73b8db8 100644 --- a/src/endpoints/characters.js +++ b/src/endpoints/characters.js @@ -23,10 +23,9 @@ import { invalidateThumbnail } from './thumbnails.js'; import { importRisuSprites } from './sprites.js'; const defaultAvatarPath = './public/img/ai4.png'; -// KV-store for parsed character data -const cacheCapacity = Number(getConfigValue('performance.cardsCacheCapacity', 100, 'number')); // MB // With 100 MB limit it would take roughly 3000 characters to reach this limit -const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); +const memoryCacheCapacity = getConfigValue('performance.memoryCacheCapacity', '100mb'); +const memoryCache = new MemoryLimitedMap(memoryCacheCapacity); // Some Android devices require tighter memory management const isAndroid = process.platform === 'android'; // Use shallow character data for the character list @@ -41,12 +40,12 @@ const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', async function readCharacterData(inputFile, inputFormat = 'png') { const stat = fs.statSync(inputFile); const cacheKey = `${inputFile}-${stat.mtimeMs}`; - if (characterDataCache.has(cacheKey)) { - return characterDataCache.get(cacheKey); + if (memoryCache.has(cacheKey)) { + return memoryCache.get(cacheKey); } const result = parse(inputFile, inputFormat); - !isAndroid && characterDataCache.set(cacheKey, result); + !isAndroid && memoryCache.set(cacheKey, result); return result; } @@ -62,12 +61,12 @@ async function readCharacterData(inputFile, inputFormat = 'png') { async function writeCharacterData(inputFile, data, outputFile, request, crop = undefined) { try { // Reset the cache - for (const key of characterDataCache.keys()) { + for (const key of memoryCache.keys()) { if (Buffer.isBuffer(inputFile)) { break; } if (key.startsWith(inputFile)) { - characterDataCache.delete(key); + memoryCache.delete(key); break; } } diff --git a/src/util.js b/src/util.js index e6246b5d2..1dec2b466 100644 --- a/src/util.js +++ b/src/util.js @@ -16,6 +16,7 @@ import mime from 'mime-types'; import { default as simpleGit } from 'simple-git'; import chalk from 'chalk'; import { LOG_LEVELS } from './constants.js'; +import bytes from 'bytes'; /** * Parsed config object. @@ -856,14 +857,10 @@ export function setupLogLevel() { export class MemoryLimitedMap { /** * Creates an instance of MemoryLimitedMap. - * @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values. + * @param {string} cacheCapacity - Maximum memory usage in human-readable format (e.g., '1 GB'). */ - constructor(maxMemoryInBytes) { - if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) { - console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.'); - maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB - } - this.maxMemory = maxMemoryInBytes; + constructor(cacheCapacity) { + this.maxMemory = bytes.parse(cacheCapacity) ?? 0; this.currentMemory = 0; this.map = new Map(); this.queue = []; @@ -886,6 +883,10 @@ export class MemoryLimitedMap { * @param {string} value */ set(key, value) { + if (this.maxMemory <= 0) { + return; + } + if (typeof key !== 'string' || typeof value !== 'string') { return; }