Use human-readable memory cache capacity in config
| @@ -138,8 +138,8 @@ performance: | ||
| 138 | 138 | # Enables lazy loading of character cards. Improves performances with large card libraries. |
| 139 | 139 | # May have compatibility issues with some extensions. |
| 140 | 140 | lazyLoadCharacters: false |
| 141 | 141 | # The maximum amount of memory that parsed character cards can use. inSet MBto 0 to disable memory caching. |
| 142 | 142 | cardsCacheCapacitymemoryCacheCapacity: 100'100mb' |
| 143 | 143 | |
| 144 | 144 | # Allow secret keys exposure via API |
| 145 | 145 | allowKeysExposure: false |
| @@ -98,8 +98,8 @@ const keyMigrationMap = [ | ||
| 98 | 98 | }, |
| 99 | 99 | { |
| 100 | 100 | oldKey: 'cardsCacheCapacity', |
| 101 | 101 | newKey: 'performance.cardsCacheCapacitymemoryCacheCapacity', |
| 102 | 102 | migrate: (value) => `${value}mb`, |
| 103 | 103 | }, |
| 104 | 104 | // uncomment one release after 1.12.13 |
| 105 | 105 | /* |
| @@ -23,10 +23,9 @@ import { invalidateThumbnail } from './thumbnails.js'; | ||
| 23 | 23 | import { importRisuSprites } from './sprites.js'; |
| 24 | 24 | const defaultAvatarPath = './public/img/ai4.png'; |
| 25 | 25 | |
| 26 | -// KV-store for parsed character data | |
| 27 | -const cacheCapacity = Number(getConfigValue('performance.cardsCacheCapacity', 100, 'number')); // MB | |
| 28 | 26 | // With 100 MB limit it would take roughly 3000 characters to reach this limit |
| 29 | -const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); | |
| 27 | +const memoryCacheCapacity = getConfigValue('performance.memoryCacheCapacity', '100mb'); | |
| 28 | +const memoryCache = new MemoryLimitedMap(memoryCacheCapacity); | |
| 30 | 29 | // Some Android devices require tighter memory management |
| 31 | 30 | const isAndroid = process.platform === 'android'; |
| 32 | 31 | // Use shallow character data for the character list |
| @@ -41,12 +40,12 @@ const useShallowCharacters = !!getConfigValue('performance.lazyLoadCharacters', | ||
| 41 | 40 | async function readCharacterData(inputFile, inputFormat = 'png') { |
| 42 | 41 | const stat = fs.statSync(inputFile); |
| 43 | 42 | const cacheKey = `${inputFile}-${stat.mtimeMs}`; |
| 44 | 43 | if (characterDataCachememoryCache.has(cacheKey)) { |
| 45 | 44 | return characterDataCachememoryCache.get(cacheKey); |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | 47 | const result = parse(inputFile, inputFormat); |
| 49 | 48 | !isAndroid && characterDataCachememoryCache.set(cacheKey, result); |
| 50 | 49 | return result; |
| 51 | 50 | } |
| 52 | 51 | |
| @@ -62,12 +61,12 @@ async function readCharacterData(inputFile, inputFormat = 'png') { | ||
| 62 | 61 | async function writeCharacterData(inputFile, data, outputFile, request, crop = undefined) { |
| 63 | 62 | try { |
| 64 | 63 | // Reset the cache |
| 65 | 64 | for (const key of characterDataCachememoryCache.keys()) { |
| 66 | 65 | if (Buffer.isBuffer(inputFile)) { |
| 67 | 66 | break; |
| 68 | 67 | } |
| 69 | 68 | if (key.startsWith(inputFile)) { |
| 70 | 69 | characterDataCachememoryCache.delete(key); |
| 71 | 70 | break; |
| 72 | 71 | } |
| 73 | 72 | } |
| @@ -16,6 +16,7 @@ import mime from 'mime-types'; | ||
| 16 | 16 | import { default as simpleGit } from 'simple-git'; |
| 17 | 17 | import chalk from 'chalk'; |
| 18 | 18 | import { LOG_LEVELS } from './constants.js'; |
| 19 | +import bytes from 'bytes'; | |
| 19 | 20 | |
| 20 | 21 | /** |
| 21 | 22 | * Parsed config object. |
| @@ -856,14 +857,10 @@ export function setupLogLevel() { | ||
| 856 | 857 | export class MemoryLimitedMap { |
| 857 | 858 | /** |
| 858 | 859 | * Creates an instance of MemoryLimitedMap. |
| 859 | 860 | * @param {numberstring} maxMemoryInBytescacheCapacity - The maximum allowedMaximum memory usage in byteshuman-readable forformat string(e.g., values'1 GB'). |
| 860 | 861 | */ |
| 861 | 862 | constructor(maxMemoryInBytescacheCapacity) { |
| 862 | - if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) { | |
| 863 | + this.maxMemory = bytes.parse(cacheCapacity) ?? 0; | |
| 863 | - console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.'); | |
| 864 | - maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB | |
| 865 | - } | |
| 866 | - this.maxMemory = maxMemoryInBytes; | |
| 867 | 864 | this.currentMemory = 0; |
| 868 | 865 | this.map = new Map(); |
| 869 | 866 | this.queue = []; |
| @@ -886,6 +883,10 @@ export class MemoryLimitedMap { | ||
| 886 | 883 | * @param {string} value |
| 887 | 884 | */ |
| 888 | 885 | set(key, value) { |
| 886 | + if (this.maxMemory <= 0) { | |
| 887 | + return; | |
| 888 | + } | |
| 889 | + | |
| 889 | 890 | if (typeof key !== 'string' || typeof value !== 'string') { |
| 890 | 891 | return; |
| 891 | 892 | } |