Refactor EJS_Cache to store all cache data in a single database, but seperate tables for metadata and blobs

This commit is contained in:
Michael Green 2025-11-21 16:45:34 +11:00
parent cdbb6a2f8d
commit 56bb0035f5
3 changed files with 53 additions and 11 deletions

View File

@ -6,15 +6,13 @@ class EJS_Cache {
/**
* Creates an instance of EJS_Cache.
* @param {boolean} enabled - Whether caching is enabled.
* @param {EJS_STORAGE} storage - Instance of EJS_STORAGE for IndexedDB operations.
* @param {EJS_STORAGE} blobStorage - Instance of EJS_STORAGE for storing blob data.
* @param {string} databaseName - Name of the IndexedDB database to use for caching.
* @param {number} maxSizeMB - Maximum size of the cache in megabytes.
* @param {number} maxAgeMins - Maximum age of items (in minutes) before they are cleaned up.
*/
constructor(enabled = true, storage, blobStorage, maxSizeMB = 4096, maxAgeMins = 7200, debug = false) {
constructor(enabled = true, databaseName, maxSizeMB = 4096, maxAgeMins = 7200, debug = false) {
this.enabled = enabled;
this.storage = storage;
this.blobStorage = blobStorage;
this.databaseName = databaseName;
this.maxSizeMB = maxSizeMB;
this.maxAgeMins = maxAgeMins;
this.minAgeMins = Math.max(60, maxAgeMins * 0.1); // Minimum 1 hour, or 10% of max age
@ -25,9 +23,7 @@ class EJS_Cache {
if (this.debug) {
console.log("Initialized EJS_Cache with settings:", {
enabled: this.enabled,
storage: this.storage,
blobStorage: this.blobStorage,
enabledValue: this.enabled,
databaseName: this.databaseName,
maxSizeMB: this.maxSizeMB,
maxAgeMins: this.maxAgeMins,
minAgeMins: this.minAgeMins
@ -35,6 +31,38 @@ class EJS_Cache {
}
}
/**
* Initializes the IndexedDB database and object stores.
* @returns {Promise<void>}
*/
async #createCacheDatabase() {
if (!this.enabled) return;
if (this.storage && this.blobStorage) return;
return new Promise((resolve, reject) => {
const request = window.indexedDB.open(this.databaseName, 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create object stores
db.createObjectStore("cache");
db.createObjectStore("blobs");
};
request.onsuccess = (event) => {
this.storage = new EJS_STORAGE(this.databaseName, "cache");
this.blobStorage = new EJS_STORAGE(this.databaseName, "blobs");
resolve();
};
request.onerror = (event) => {
console.error("Error creating cache database:", event);
reject(event);
};
});
}
/**
* Indicates whether the startup cleanup has been completed.
*/
@ -60,6 +88,9 @@ class EJS_Cache {
async get(key, metadataOnly = false) {
if (!this.enabled) return null;
// ensure database is created
await this.#createCacheDatabase();
// clean up cache on first get if not already done
if (!this.#startupCleanupCompleted) {
await this.cleanup();
@ -88,6 +119,9 @@ class EJS_Cache {
async put(item) {
if (!this.enabled) return;
// ensure database is created
await this.#createCacheDatabase();
// before putting, ensure item is of type EJS_CacheItem
if (!(item instanceof EJS_CacheItem)) {
throw new Error("Item must be an instance of EJS_CacheItem");
@ -146,6 +180,9 @@ class EJS_Cache {
* @param {string} key - The unique key identifying the cached item to delete.
*/
async delete(key) {
// ensure database is created
await this.#createCacheDatabase();
// fail silently if the key does not exist
try {
await this.storage.remove(key);
@ -159,6 +196,9 @@ class EJS_Cache {
* Clears all items from the cache.
*/
async clear() {
// ensure database is created
await this.#createCacheDatabase();
const allItems = await this.storage.getAll();
for (let i = 0; i < allItems.length; i++) {
await this.delete(allItems[i].key);
@ -171,6 +211,9 @@ class EJS_Cache {
async cleanup() {
if (!this.enabled) return;
// ensure database is created
await this.#createCacheDatabase();
if (this.debug) console.log("[EJS Cache] Starting cache cleanup...");
const cleanupStartTime = performance.now();

View File

@ -353,8 +353,7 @@ class EmulatorJS {
this.storageCache = new window.EJS_Cache(
this.config.cacheConfig.enabled,
new window.EJS_STORAGE("EmulatorJS-cache", "cache"),
new window.EJS_STORAGE("EmulatorJS-cacheBlobs", "cacheblobs"),
"EmulatorJS-Cache",
this.config.cacheConfig.cacheMaxSizeMB,
this.config.cacheConfig.cacheMaxAgeMins || 7200,
this.debug

View File

@ -24,7 +24,7 @@ class EJS_STORAGE {
openRequest.onerror = () => resolve();
openRequest.onsuccess = () => {
let db = openRequest.result;
let transaction = db.transaction([this.storeName], mode);
let transaction = db.transaction(this.storeName, mode);
let objectStore = transaction.objectStore(this.storeName);
resolve(objectStore);
};