@thi.ng/cache 2.1.106 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -1
- package/README.md +28 -21
- package/api.d.ts +11 -6
- package/lru.d.ts +2 -2
- package/lru.js +15 -22
- package/mru.d.ts +1 -2
- package/mru.js +1 -3
- package/package.json +2 -2
- package/tlru.d.ts +19 -4
- package/tlru.js +21 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2024-03-
|
|
3
|
+
- **Last updated**: 2024-03-11T19:30:41Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,25 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
### [2.2.1](https://github.com/thi-ng/umbrella/tree/@thi.ng/cache@2.2.1) (2024-03-11)
|
|
13
|
+
|
|
14
|
+
#### 🩹 Bug fixes
|
|
15
|
+
|
|
16
|
+
- fix regression, all ctor args optional again ([54e6b37](https://github.com/thi-ng/umbrella/commit/54e6b37))
|
|
17
|
+
|
|
18
|
+
## [2.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/cache@2.2.0) (2024-03-11)
|
|
19
|
+
|
|
20
|
+
#### 🚀 Features
|
|
21
|
+
|
|
22
|
+
- add value update callback, update TLRUCache ([d2fed06](https://github.com/thi-ng/umbrella/commit/d2fed06))
|
|
23
|
+
- add CacheOpts.update
|
|
24
|
+
- update doSetEntry() in all impls
|
|
25
|
+
- refactor TLRUCache.getSet() as async fn
|
|
26
|
+
- update TLRUCache.prune() to return eviction count
|
|
27
|
+
- various other refactoring
|
|
28
|
+
- add tests
|
|
29
|
+
- add docs
|
|
30
|
+
|
|
12
31
|
### [2.1.106](https://github.com/thi-ng/umbrella/tree/@thi.ng/cache@2.1.106) (2024-03-11)
|
|
13
32
|
|
|
14
33
|
#### 🩹 Bug fixes
|
package/README.md
CHANGED
|
@@ -47,7 +47,8 @@ strategies](https://en.wikipedia.org/wiki/Cache_replacement_policies).
|
|
|
47
47
|
- Supports any types for both keys & values
|
|
48
48
|
- Customizable cache limits (no. of items / actual size)
|
|
49
49
|
- Customizable key equality checks (@thi.ng/equiv by default)
|
|
50
|
-
- Optional item release callbacks (to clean up resources when
|
|
50
|
+
- Optional item update & release callbacks (e.g. to clean up resources when
|
|
51
|
+
value is being updated or evicted)
|
|
51
52
|
|
|
52
53
|
## Status
|
|
53
54
|
|
|
@@ -79,7 +80,7 @@ For Node.js REPL:
|
|
|
79
80
|
const cache = await import("@thi.ng/cache");
|
|
80
81
|
```
|
|
81
82
|
|
|
82
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 1.
|
|
83
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.06 KB
|
|
83
84
|
|
|
84
85
|
## Dependencies
|
|
85
86
|
|
|
@@ -119,6 +120,10 @@ interface CacheOpts<K, V> {
|
|
|
119
120
|
* Eviction callback to clean up resources
|
|
120
121
|
*/
|
|
121
122
|
release: (k: K, v: V) => void;
|
|
123
|
+
/**
|
|
124
|
+
* Update callback to clean up resources
|
|
125
|
+
*/
|
|
126
|
+
update: (k: K, vold: V, vnew: V) => void;
|
|
122
127
|
/**
|
|
123
128
|
* Factory for ES6 Map compatible instance
|
|
124
129
|
* to index cache entries
|
|
@@ -137,13 +142,14 @@ interface CacheOpts<K, V> {
|
|
|
137
142
|
|
|
138
143
|
### LRU
|
|
139
144
|
|
|
140
|
-
Removes least recently used items if a new item is added, but would not satisfy
|
|
145
|
+
Removes least recently used items if a new item is added, but would not satisfy
|
|
146
|
+
cache limit. Every time a cached item is accessed, it's recency is updated.
|
|
141
147
|
|
|
142
148
|
```ts
|
|
143
|
-
import
|
|
149
|
+
import { LRUCache } from "@thi.ng/cache";
|
|
144
150
|
|
|
145
|
-
// caches can be configured with
|
|
146
|
-
const lru = new
|
|
151
|
+
// caches can be configured with maxlen, maxsize and sizing functions (see below)
|
|
152
|
+
const lru = new LRUCache<string, number>(null, { maxlen: 3 });
|
|
147
153
|
lru.set("foo", 23);
|
|
148
154
|
lru.set("bar", 42);
|
|
149
155
|
lru.set("baz", 66);
|
|
@@ -155,7 +161,7 @@ lru.get("foo");
|
|
|
155
161
|
// 23
|
|
156
162
|
|
|
157
163
|
// caches are fully iterable
|
|
158
|
-
// largely intended for inspection, does not update recency
|
|
164
|
+
// largely intended for inspection only, does not update recency
|
|
159
165
|
// btw. "foo" appears last since most recently accessed
|
|
160
166
|
[...lru]
|
|
161
167
|
// [ { k: 'bar', v: 42, s: 0 },
|
|
@@ -172,12 +178,12 @@ lru.delete("foo");
|
|
|
172
178
|
|
|
173
179
|
// caches have a getSet() method to obtain & store a new value
|
|
174
180
|
// if its key is not known. this process is asynchronous
|
|
175
|
-
lru.getSet("boo", () =>
|
|
181
|
+
lru.getSet("boo", async () => 999).then(console.log);
|
|
176
182
|
// 999
|
|
177
183
|
|
|
178
184
|
// the given retrieval fn is only called if there's a cache miss
|
|
179
185
|
// (not the case here). `getSet()` always returns a promise
|
|
180
|
-
lru.getSet("boo", () =>
|
|
186
|
+
lru.getSet("boo", async () => 123).then(console.log);
|
|
181
187
|
// 999
|
|
182
188
|
|
|
183
189
|
// caches can be limited by size instead of (or in addition to)
|
|
@@ -187,13 +193,14 @@ lru.getSet("boo", () => Promise.resolve(123)).then(console.log);
|
|
|
187
193
|
// we also provide a release hook for demo purposes
|
|
188
194
|
|
|
189
195
|
// the first arg is an iterable of KV pairs to store (just as for Map)
|
|
190
|
-
lru = new
|
|
196
|
+
lru = new LRUCache<string, number[]>(
|
|
191
197
|
[ ["a", [1.0, 2.0]], ["b", [3.0, 4.0, 5.0]] ],
|
|
192
198
|
{
|
|
193
199
|
maxsize: 32,
|
|
194
200
|
ksize: (k) => k.length,
|
|
195
201
|
vsize: (v) => v.length * 8,
|
|
196
|
-
release: (k, v) => console.log("release", k, v)
|
|
202
|
+
release: (k, v) => console.log("release", k, v),
|
|
203
|
+
update: (k, vold, vnew) => console.log("update", k, vold, "->", vnew)
|
|
197
204
|
}
|
|
198
205
|
);
|
|
199
206
|
// release a [1, 2] ("a" is evicted due to maxsize constraint)
|
|
@@ -206,19 +213,18 @@ lru.size
|
|
|
206
213
|
|
|
207
214
|
### TLRU
|
|
208
215
|
|
|
209
|
-
Time-aware LRU cache. Extends LRU strategy with TTL (time-to-live)
|
|
210
|
-
values associated with each entry. `has()` will only return `true` and
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
given, TTL defaults to 1 hour.
|
|
216
|
+
Time-aware [LRU cache](#lru). Extends LRU strategy with TTL (time-to-live)
|
|
217
|
+
values associated with each entry. `has()` will only return `true` and `get()`
|
|
218
|
+
only returns a cached value if its TTL hasn't yet expired. When adding a new
|
|
219
|
+
value to the cache, first removes expired entries and if there's still not
|
|
220
|
+
sufficient space removes entries in LRU order. `set()` takes an optional entry
|
|
221
|
+
specific `ttl` arg. If not given, uses the cache instance's default (provided
|
|
222
|
+
via ctor option arg). If no instance TTL is given, TTL defaults to 1 hour.
|
|
217
223
|
|
|
218
224
|
```ts
|
|
219
225
|
import { TLRUCache } from "@thi.ng/cache";
|
|
220
226
|
|
|
221
|
-
// same opts as LRUCache, but here with custom TTL period (in ms)
|
|
227
|
+
// same opts as LRUCache, but here with custom default TTL period (in ms)
|
|
222
228
|
tlru = new TLRUCache(null, { ttl: 10000 });
|
|
223
229
|
|
|
224
230
|
// with item specific TTL (500ms)
|
|
@@ -227,7 +233,8 @@ tlru.set("foo", 42, 500)
|
|
|
227
233
|
|
|
228
234
|
### MRU
|
|
229
235
|
|
|
230
|
-
Similar to LRU, but removes most recently accessed items first.
|
|
236
|
+
Similar to LRU, but removes most recently accessed items first.
|
|
237
|
+
[Wikipedia](https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU))
|
|
231
238
|
|
|
232
239
|
```ts
|
|
233
240
|
import { MRUCache } from "@thi.ng/cache";
|
package/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fn, Fn0, Fn2, ICopy, IEmpty, ILength, IRelease } from "@thi.ng/api";
|
|
1
|
+
import type { Fn, Fn0, Fn2, Fn3, ICopy, IEmpty, ILength, IRelease } from "@thi.ng/api";
|
|
2
2
|
export interface ICache<K, V> extends Iterable<Readonly<[K, CacheEntry<K, V>]>>, ICopy<ICache<K, V>>, IEmpty<ICache<K, V>>, ILength, IRelease {
|
|
3
3
|
readonly size: number;
|
|
4
4
|
/**
|
|
@@ -57,20 +57,25 @@ export interface ICache<K, V> extends Iterable<Readonly<[K, CacheEntry<K, V>]>>,
|
|
|
57
57
|
}
|
|
58
58
|
export interface CacheOpts<K, V> {
|
|
59
59
|
/**
|
|
60
|
-
*
|
|
61
|
-
* {@link CacheOpts.
|
|
60
|
+
* Function to compute the size of a given key in arbitrary user defined
|
|
61
|
+
* units (must be same unit as given to {@link CacheOpts.maxsize}).
|
|
62
62
|
*/
|
|
63
63
|
ksize: Fn<K, number>;
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
* {@link CacheOpts.
|
|
65
|
+
* Function to compute the size of a given value in arbitrary user defined
|
|
66
|
+
* units (must be same unit as given to {@link CacheOpts.maxsize}).
|
|
67
67
|
*/
|
|
68
68
|
vsize: Fn<V, number>;
|
|
69
69
|
/**
|
|
70
|
-
*
|
|
70
|
+
* Callback function to perform custom tasks when an item gets evicted from
|
|
71
71
|
* the cache.
|
|
72
72
|
*/
|
|
73
73
|
release: Fn2<K, V, void>;
|
|
74
|
+
/**
|
|
75
|
+
* Callback function to perform custom tasks when an item gets updated in the cache.
|
|
76
|
+
* The function will be called with a key and its associated old and news values.
|
|
77
|
+
*/
|
|
78
|
+
update: Fn3<K, V, V, void>;
|
|
74
79
|
/**
|
|
75
80
|
* Custom ES6 Map compatible implementation to use as the cache's backing
|
|
76
81
|
* store.
|
package/lru.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fn0 } from "@thi.ng/api";
|
|
1
|
+
import type { Fn0, Nullable } from "@thi.ng/api";
|
|
2
2
|
import type { ConsCell } from "@thi.ng/dcons";
|
|
3
3
|
import { DCons } from "@thi.ng/dcons/dcons";
|
|
4
4
|
import type { CacheEntry, CacheOpts, ICache } from "./api.js";
|
|
@@ -7,7 +7,7 @@ export declare class LRUCache<K, V> implements ICache<K, V> {
|
|
|
7
7
|
protected items: DCons<CacheEntry<K, V>>;
|
|
8
8
|
protected opts: CacheOpts<K, V>;
|
|
9
9
|
protected _size: number;
|
|
10
|
-
constructor(pairs?: Iterable<[K, V]
|
|
10
|
+
constructor(pairs?: Nullable<Iterable<[K, V]>>, opts?: Partial<CacheOpts<K, V>>);
|
|
11
11
|
get length(): number;
|
|
12
12
|
get size(): number;
|
|
13
13
|
[Symbol.iterator](): IterableIterator<readonly [K, CacheEntry<K, V>]>;
|
package/lru.js
CHANGED
|
@@ -6,16 +6,14 @@ class LRUCache {
|
|
|
6
6
|
opts;
|
|
7
7
|
_size;
|
|
8
8
|
constructor(pairs, opts) {
|
|
9
|
-
const _opts =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
opts
|
|
18
|
-
);
|
|
9
|
+
const _opts = {
|
|
10
|
+
maxlen: Infinity,
|
|
11
|
+
maxsize: Infinity,
|
|
12
|
+
map: () => /* @__PURE__ */ new Map(),
|
|
13
|
+
ksize: () => 0,
|
|
14
|
+
vsize: () => 0,
|
|
15
|
+
...opts
|
|
16
|
+
};
|
|
19
17
|
this.map = _opts.map();
|
|
20
18
|
this.items = new DCons();
|
|
21
19
|
this._size = 0;
|
|
@@ -73,10 +71,7 @@ class LRUCache {
|
|
|
73
71
|
}
|
|
74
72
|
get(key, notFound) {
|
|
75
73
|
const e = this.map.get(key);
|
|
76
|
-
|
|
77
|
-
return this.resetEntry(e);
|
|
78
|
-
}
|
|
79
|
-
return notFound;
|
|
74
|
+
return e ? this.resetEntry(e) : notFound;
|
|
80
75
|
}
|
|
81
76
|
set(key, value) {
|
|
82
77
|
const size = this.opts.ksize(key) + this.opts.vsize(value);
|
|
@@ -113,16 +108,13 @@ class LRUCache {
|
|
|
113
108
|
return e.value.v;
|
|
114
109
|
}
|
|
115
110
|
ensureSize() {
|
|
116
|
-
const release = this.opts
|
|
117
|
-
|
|
118
|
-
const maxl = this.opts.maxlen;
|
|
119
|
-
while (this._size > maxs || this.length >= maxl) {
|
|
111
|
+
const { release, maxsize, maxlen } = this.opts;
|
|
112
|
+
while (this._size > maxsize || this.length >= maxlen) {
|
|
120
113
|
const e = this.items.drop();
|
|
121
|
-
if (!e)
|
|
114
|
+
if (!e)
|
|
122
115
|
return false;
|
|
123
|
-
}
|
|
124
116
|
this.map.delete(e.k);
|
|
125
|
-
release
|
|
117
|
+
release?.(e.k, e.v);
|
|
126
118
|
this._size -= e.s;
|
|
127
119
|
}
|
|
128
120
|
return true;
|
|
@@ -131,11 +123,12 @@ class LRUCache {
|
|
|
131
123
|
const ee = e.value;
|
|
132
124
|
this.map.delete(ee.k);
|
|
133
125
|
this.items.remove(e);
|
|
134
|
-
this.opts.release
|
|
126
|
+
this.opts.release?.(ee.k, ee.v);
|
|
135
127
|
this._size -= ee.s;
|
|
136
128
|
}
|
|
137
129
|
doSetEntry(e, k, v, s) {
|
|
138
130
|
if (e) {
|
|
131
|
+
this.opts.update?.(k, e.value.v, v);
|
|
139
132
|
e.value.v = v;
|
|
140
133
|
e.value.s = s;
|
|
141
134
|
this.items.asTail(e);
|
package/mru.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ConsCell } from "@thi.ng/dcons";
|
|
2
|
-
import type { CacheEntry
|
|
2
|
+
import type { CacheEntry } from "./api.js";
|
|
3
3
|
import { LRUCache } from "./lru.js";
|
|
4
4
|
export declare class MRUCache<K, V> extends LRUCache<K, V> {
|
|
5
|
-
constructor(pairs?: Iterable<[K, V]> | null, opts?: Partial<CacheOpts<K, V>>);
|
|
6
5
|
empty(): MRUCache<K, V>;
|
|
7
6
|
protected resetEntry(e: ConsCell<CacheEntry<K, V>>): V;
|
|
8
7
|
protected doSetEntry(e: ConsCell<CacheEntry<K, V>> | undefined, k: K, v: V, s: number): void;
|
package/mru.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { LRUCache } from "./lru.js";
|
|
2
2
|
class MRUCache extends LRUCache {
|
|
3
|
-
constructor(pairs, opts) {
|
|
4
|
-
super(pairs, opts);
|
|
5
|
-
}
|
|
6
3
|
empty() {
|
|
7
4
|
return new MRUCache(null, this.opts);
|
|
8
5
|
}
|
|
@@ -12,6 +9,7 @@ class MRUCache extends LRUCache {
|
|
|
12
9
|
}
|
|
13
10
|
doSetEntry(e, k, v, s) {
|
|
14
11
|
if (e) {
|
|
12
|
+
this.opts.update?.(k, e.value.v, v);
|
|
15
13
|
e.value.v = v;
|
|
16
14
|
e.value.s = s;
|
|
17
15
|
this.items.asHead(e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/cache",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "In-memory cache implementations with ES6 Map-like API and different eviction strategies",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
],
|
|
92
92
|
"year": 2018
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "c85c9fd8fa824da957ad498a4b2fda1b3be190c5\n"
|
|
95
95
|
}
|
package/tlru.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { Fn0 } from "@thi.ng/api";
|
|
1
|
+
import type { Fn0, Nullable } from "@thi.ng/api";
|
|
2
2
|
import type { ConsCell, DCons } from "@thi.ng/dcons";
|
|
3
3
|
import type { CacheEntry, CacheOpts } from "./api.js";
|
|
4
4
|
import { LRUCache } from "./lru.js";
|
|
5
5
|
export interface TLRUCacheOpts<K, V> extends CacheOpts<K, V> {
|
|
6
|
+
/**
|
|
7
|
+
* Default time-to-live (cache period in milliseconds) before an entry is
|
|
8
|
+
* considered expired.
|
|
9
|
+
*
|
|
10
|
+
* @defaultValue 3600000 (1 hour)
|
|
11
|
+
*/
|
|
6
12
|
ttl: number;
|
|
7
13
|
}
|
|
8
14
|
export interface TLRUCacheEntry<K, V> extends CacheEntry<K, V> {
|
|
@@ -26,14 +32,23 @@ export declare class TLRUCache<K, V> extends LRUCache<K, V> {
|
|
|
26
32
|
protected opts: TLRUCacheOpts<K, V>;
|
|
27
33
|
protected map: Map<K, ConsCell<TLRUCacheEntry<K, V>>>;
|
|
28
34
|
protected items: DCons<TLRUCacheEntry<K, V>>;
|
|
29
|
-
constructor(pairs?: Iterable<[K, V]
|
|
35
|
+
constructor(pairs?: Nullable<Iterable<[K, V]>>, opts?: Partial<TLRUCacheOpts<K, V>>);
|
|
30
36
|
empty(): TLRUCache<K, V>;
|
|
31
37
|
has(key: K): boolean;
|
|
32
38
|
get(key: K, notFound?: V): V | undefined;
|
|
33
39
|
set(key: K, value: V, ttl?: number): V;
|
|
34
40
|
getSet(key: K, retrieve: Fn0<Promise<V>>, ttl?: number): Promise<V>;
|
|
35
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Scans all cached entries and evicts any which are expired by now (based
|
|
43
|
+
* on their TTL). Does **not** modify last-accessed time of remaining
|
|
44
|
+
* entries. Returns number of entries evicted.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* For very large caches, it's recommended to call this function in a
|
|
48
|
+
* cron-like manner...
|
|
49
|
+
*/
|
|
50
|
+
prune(): number;
|
|
36
51
|
protected ensureSize(): boolean;
|
|
37
|
-
protected
|
|
52
|
+
protected doSetEntry(e: ConsCell<TLRUCacheEntry<K, V>> | undefined, k: K, v: V, s: number, ttl?: number): void;
|
|
38
53
|
}
|
|
39
54
|
//# sourceMappingURL=tlru.d.ts.map
|
package/tlru.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { LRUCache } from "./lru.js";
|
|
2
2
|
class TLRUCache extends LRUCache {
|
|
3
3
|
constructor(pairs, opts) {
|
|
4
|
-
|
|
5
|
-
super(pairs, opts);
|
|
4
|
+
super(pairs, { ttl: 60 * 60 * 1e3, ...opts });
|
|
6
5
|
}
|
|
7
6
|
empty() {
|
|
8
7
|
return new TLRUCache(null, this.opts);
|
|
@@ -26,36 +25,43 @@ class TLRUCache extends LRUCache {
|
|
|
26
25
|
const additionalSize = Math.max(0, size - (e ? e.value.s : 0));
|
|
27
26
|
this._size += additionalSize;
|
|
28
27
|
if (this.ensureSize()) {
|
|
29
|
-
|
|
30
|
-
this.doSetTlruEntry(e, key, value, size, t);
|
|
28
|
+
this.doSetEntry(e, key, value, size, ttl);
|
|
31
29
|
} else {
|
|
32
30
|
this._size -= additionalSize;
|
|
33
31
|
}
|
|
34
32
|
return value;
|
|
35
33
|
}
|
|
36
|
-
getSet(key, retrieve, ttl = this.opts.ttl) {
|
|
34
|
+
async getSet(key, retrieve, ttl = this.opts.ttl) {
|
|
37
35
|
const e = this.get(key);
|
|
38
|
-
|
|
39
|
-
return Promise.resolve(e);
|
|
40
|
-
}
|
|
41
|
-
return retrieve().then((v) => this.set(key, v, ttl));
|
|
36
|
+
return e !== void 0 ? e : this.set(key, await retrieve(), ttl);
|
|
42
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Scans all cached entries and evicts any which are expired by now (based
|
|
40
|
+
* on their TTL). Does **not** modify last-accessed time of remaining
|
|
41
|
+
* entries. Returns number of entries evicted.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
44
|
+
* For very large caches, it's recommended to call this function in a
|
|
45
|
+
* cron-like manner...
|
|
46
|
+
*/
|
|
43
47
|
prune() {
|
|
44
48
|
const now = Date.now();
|
|
45
49
|
let cell = this.items.head;
|
|
50
|
+
let count = 0;
|
|
46
51
|
while (cell) {
|
|
47
52
|
if (cell.value.t < now) {
|
|
48
53
|
this.removeEntry(cell);
|
|
54
|
+
count++;
|
|
49
55
|
}
|
|
50
56
|
cell = cell.next;
|
|
51
57
|
}
|
|
58
|
+
return count;
|
|
52
59
|
}
|
|
53
60
|
ensureSize() {
|
|
54
|
-
const
|
|
55
|
-
const maxl = this.opts.maxlen;
|
|
61
|
+
const { maxlen, maxsize } = this.opts;
|
|
56
62
|
const now = Date.now();
|
|
57
63
|
let cell = this.items.head;
|
|
58
|
-
while (cell && (this._size >
|
|
64
|
+
while (cell && (this._size > maxsize || this.length >= maxlen)) {
|
|
59
65
|
if (cell.value.t < now) {
|
|
60
66
|
this.removeEntry(cell);
|
|
61
67
|
}
|
|
@@ -63,8 +69,10 @@ class TLRUCache extends LRUCache {
|
|
|
63
69
|
}
|
|
64
70
|
return super.ensureSize();
|
|
65
71
|
}
|
|
66
|
-
|
|
72
|
+
doSetEntry(e, k, v, s, ttl = this.opts.ttl) {
|
|
73
|
+
const t = Date.now() + ttl;
|
|
67
74
|
if (e) {
|
|
75
|
+
this.opts.update?.(k, e.value.v, v);
|
|
68
76
|
e.value.v = v;
|
|
69
77
|
e.value.s = s;
|
|
70
78
|
e.value.t = t;
|