@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
206 lines (186 loc) • 4.06 kB
JavaScript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import { LRUCache } from 'lru-cache';
import { isMemoryUsage } from './MemoryUsage';
/**
* The options for a cache entry.
*/
/**
* The default max number of entries.
*/
export const DEFAULT_MAX_ENTRIES = 8192;
/**
* The default TTL (time to live), in milliseconds.
*/
export const DEFAULT_TTL = 240_000; // 240 seconds
/**
* The default capacity, in bytes.
*/
export const DEFAULT_CAPACITY = 536_870_912; // 512 MB
/**
* The cache.
*
*/
export class Cache {
isMemoryUsage = true;
/**
* Constructs a cache.
*
* @param opts - The options.
*/
constructor(opts) {
this._deleteHandlers = new Map();
this._enabled = true;
this._lru = this.createLRUCache(opts);
}
createLRUCache(opts) {
return new LRUCache({
ttl: opts?.ttl ?? DEFAULT_TTL,
ttlResolution: 1000,
// 1 second
updateAgeOnGet: true,
maxSize: opts?.byteCapacity ?? DEFAULT_CAPACITY,
max: opts?.maxNumberOfEntries ?? DEFAULT_MAX_ENTRIES,
allowStale: false,
dispose: (value, key) => {
this.onDisposed(key, value);
}
});
}
/**
* Configure the cache with the specified configuration. The cache must be
* empty otherwise this method will throw an error.
*/
configure(config) {
if (this.count > 0) {
throw new Error('cannot configure the cache as it is not empty.');
}
this._lru = this.createLRUCache(config);
}
getMemoryUsage(context) {
this._lru.forEach(e => {
if (isMemoryUsage(e)) {
e.getMemoryUsage(context);
}
});
}
/**
* Enables or disables the cache.
*/
get enabled() {
return this._enabled;
}
set enabled(v) {
this._enabled = v;
}
/**
* Gets or sets the default TTL (time to live) of the cache.
*/
get defaultTtl() {
return this._lru.ttl;
}
set defaultTtl(v) {
this._lru.ttl = v;
}
/**
* Gets the maximum size of the cache, in bytes.
*/
get maxSize() {
return this._lru.maxSize;
}
/**
* Gets the maximum number of entries.
*/
get capacity() {
return this._lru.max;
}
/**
* Gets the number of entries.
*/
get count() {
return this._lru.size;
}
/**
* Gets the size of entries, in bytes
*/
get size() {
return this._lru.calculatedSize;
}
/**
* Returns an array of entries.
*/
entries() {
return [...this._lru.entries()];
}
onDisposed(key, value) {
const handler = this._deleteHandlers.get(key);
if (handler) {
this._deleteHandlers.delete(key);
handler(value);
}
}
/**
* Removes stale entries.
*/
purge() {
this._lru.purgeStale();
}
/**
* Returns the entry with the specified key, or `undefined` if no entry matches this key.
*
* @param key - The entry key.
* @returns The entry, or `undefined`.
*/
get(key) {
if (!this.enabled) {
return undefined;
}
return this._lru.get(key);
}
/**
* Stores an entry in the cache, or replaces an existing entry with the same key.
*
* @param key - The key.
* @param value - The value.
* @param options - The options.
*/
set(key, value, options = {}) {
if (!this.enabled) {
return value;
}
if (typeof key !== 'string') {
throw new Error('the cache expects strings as keys.');
}
this._lru.set(key, value, {
ttl: options.ttl ?? this.defaultTtl,
size: options.size ?? 1024 // Use a default size if not provided
});
if (options.onDelete) {
this._deleteHandlers.set(key, options.onDelete);
}
return value;
}
/**
* Deletes an entry.
*
* @param key - The key.
* @returns `true` if the entry was deleted, `false` otherwise.
*/
delete(key) {
return this._lru.delete(key);
}
/**
* Clears the cache.
*
*/
clear() {
this._lru.clear();
}
}
/**
* A global singleton cache.
*/
export const GlobalCache = new Cache();