From a721dfba6f97d29b6948143d73cfee5eefdd2815 Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Tue, 8 Nov 2022 00:47:09 +0200 Subject: [PATCH] fix: improve memory management, cache last expiration check result --- src/config/app.ts | 2 +- src/data/icon-sets.ts | 9 +++++++++ src/data/storage/cleanup.ts | 22 +++++++++++++++++----- src/types/storage.ts | 5 ++++- tests/data/storage-long-test.ts | 3 +++ 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/config/app.ts b/src/config/app.ts index e58c937..3648bfc 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -87,7 +87,7 @@ export const storageConfig: MemoryStorageConfig = { // Should be set to at least 10 seconds (10000) to avoid repeated read operations minExpiration: 20000, - // Timeout in milliseconds to check expired items, > 0 (if disabled, cleanupAfterSec is not ran) + // Timeout in milliseconds to check expired items, > 0 (if disabled, cleanupAfter is not ran) timer: 60000, // Number of milliseconds to keep item in storage after last use, > minExpiration diff --git a/src/data/icon-sets.ts b/src/data/icon-sets.ts index b53f12a..1fb9ebc 100644 --- a/src/data/icon-sets.ts +++ b/src/data/icon-sets.ts @@ -1,6 +1,8 @@ import type { StoredIconSet } from '../types/icon-set/storage'; import type { IconSetEntry, Importer } from '../types/importers'; +import { iconSetsStorage } from './icon-set/store/storage'; import { updateSearchIndex } from './search'; +import { cleanupStorageCache } from './storage/startup'; /** * All importers @@ -132,6 +134,13 @@ export function triggerIconSetsUpdate() { console.log('Checking for updates...'); (async () => { + // Clear as much memory as possible by running storage cleanup immediately + await cleanupStorageCache(iconSetsStorage); + try { + global.gc?.(); + } catch {} + + // Check for updates let updated = false; for (let i = 0; i < importers?.length; i++) { updated = (await importers[i].checkForUpdate()) || updated; diff --git a/src/data/storage/cleanup.ts b/src/data/storage/cleanup.ts index c7806c8..76d469d 100644 --- a/src/data/storage/cleanup.ts +++ b/src/data/storage/cleanup.ts @@ -55,18 +55,26 @@ export function cleanupStorage(storage: MemoryStorage) { const cleanupAfter = config.cleanupAfter; if (cleanupAfter) { const minTimer = Math.min(Date.now() - cleanupAfter, lastUsedLimit); - watched.forEach((item) => { - if (item.lastUsed < minTimer) { - cleanupStoredItem(storage, item); - } - }); + if (!storage.minLastUsed || storage.minLastUsed < minTimer) { + watched.forEach((item) => { + if (item.lastUsed < minTimer) { + cleanupStoredItem(storage, item); + } + }); + } } // Check items limit const maxCount = config.maxCount; if (maxCount && watched.size > maxCount) { + if (storage.minLastUsed && storage.minLastUsed > lastUsedLimit) { + // Cannot cleanup: minLastUsed set from last check is too high + return; + } + // Sort items const sortedList = Array.from(watched).sort((item1, item2) => item1.lastUsed - item2.lastUsed); + delete storage.minLastUsed; // Delete items, sorted by `lastUsed` for (let i = 0; i < sortedList.length && watched.size > maxCount; i++) { @@ -74,6 +82,10 @@ export function cleanupStorage(storage: MemoryStorage) { const item = sortedList[i]; if (item.lastUsed < lastUsedLimit) { cleanupStoredItem(storage, item); + } else { + // Ran out of items to delete + storage.minLastUsed = item.lastUsed; + return; } } } diff --git a/src/types/storage.ts b/src/types/storage.ts index d8a173d..8111d0b 100644 --- a/src/types/storage.ts +++ b/src/types/storage.ts @@ -46,7 +46,7 @@ export interface MemoryStorageConfig { // Should be set to at least 10 seconds (10000) to avoid repeated read operations minExpiration?: number; - // Timeout in milliseconds to check expired items, > 0 (if disabled, cleanupAfterSec is not ran) + // Timeout in milliseconds to check expired items, > 0 (if disabled, cleanupAfter is not ran) timer?: number; // Number of milliseconds to keep item in storage after last use, > minExpiration @@ -72,4 +72,7 @@ export interface MemoryStorage { // Watched items watched: Set>; + + // Minimum `lastUsed` value from last sort. Used to avoid re-sorting too often + minLastUsed?: number; } diff --git a/tests/data/storage-long-test.ts b/tests/data/storage-long-test.ts index 88b3e89..128cd5d 100644 --- a/tests/data/storage-long-test.ts +++ b/tests/data/storage-long-test.ts @@ -59,6 +59,9 @@ describe('Advanced storage tests', () => { // Fake expiration for last item and run cleanup process lastItem.lastUsed -= 100000; + if (storage.minLastUsed) { + storage.minLastUsed -= 100000; + } cleanupStorage(storage); // Only `lastItem` should have been removed