Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: isaacs/node-lru-cache
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v7.0.4
Choose a base ref
...
head repository: isaacs/node-lru-cache
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v7.1.0
Choose a head ref
  • 10 commits
  • 12 files changed
  • 1 contributor

Commits on Feb 8, 2022

  1. ci: tests

    isaacs committed Feb 8, 2022
    Copy the full SHA
    f6ebe7e View commit details
  2. Copy the full SHA
    97ee33f View commit details
  3. Copy the full SHA
    224e339 View commit details
  4. Copy the full SHA
    733feec View commit details
  5. Copy the full SHA
    bf6cc14 View commit details
  6. Copy the full SHA
    7086716 View commit details
  7. add changelog.md

    Fix #77
    isaacs committed Feb 8, 2022
    Copy the full SHA
    4616d9b View commit details
  8. Copy the full SHA
    a1ec7b4 View commit details
  9. feat: ttlResolution and ttlAutopurge

    The first makes TTL performance much better.
    
    The second makes it much MUCH worse lol
    
    But it's a thing people ask for often and are surprised to not have.
    isaacs committed Feb 8, 2022
    Copy the full SHA
    374aaa6 View commit details
  10. 7.1.0

    isaacs committed Feb 8, 2022
    Copy the full SHA
    0ee3152 View commit details
Showing with 494 additions and 66 deletions.
  1. +39 −0 .github/workflows/ci.yml
  2. +74 −0 CHANGELOG.md
  3. +113 −48 README.md
  4. +68 −6 index.js
  5. +2 −2 package-lock.json
  6. +1 −1 package.json
  7. +7 −1 tap-snapshots/test/deprecations.js.test.cjs
  8. +66 −0 tap-snapshots/test/map-like.js.test.cjs
  9. +4 −0 test/basic.js
  10. +4 −0 test/deprecations.js
  11. +26 −2 test/map-like.js
  12. +90 −6 test/ttl.js
39 changes: 39 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: CI

on: [push, pull_request]

jobs:
build:
strategy:
matrix:
node-version: [12.x, 14.x, 16.x, 17.x]
platform:
- os: ubuntu-latest
shell: bash
- os: macos-latest
shell: bash
- os: windows-latest
shell: bash
- os: windows-latest
shell: powershell
fail-fast: false

runs-on: ${{ matrix.platform.os }}
defaults:
run:
shell: ${{ matrix.platform.shell }}

steps:
- name: Checkout Repository
uses: actions/checkout@v1.1.0

- name: Use Nodejs ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install

- name: Run Tests
run: npm test -- -c -t0
74 changes: 74 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# cringe lorg

### 7.1.0 - 2022-02

* Add `ttlResolution` option
* Add `ttlAutopurge` option

## v7 - 2022-02

This library changed to a different algorithm and internal data structure
in version 7, yielding significantly better performance, albeit with
some subtle changes as a result.

If you were relying on the internals of LRUCache in version 6 or before, it
probably will not work in version 7 and above.

### Specific API Changes

For the most part, the feature set has been maintained as much as possible.

However, some other cleanup and refactoring changes were made in v7 as
well.

* The `set()`, `get()`, and `has()` functions take options objects
instead of positional booleans/integers for optional parameters.
* `size` can be set explicitly on `set()`.
* `cache.length` was renamed to the more fitting `cache.size`.
* Deprecations:
* `stale` option -> `allowStale`
* `maxAge` option -> `ttl`
* `length` option -> `sizeCalculation`
* `length` property -> `size`
* `prune()` method -> `purgeStale()`
* `reset()` method -> `clear()`
* The objects used by `cache.load()` and `cache.dump()` are incompatible
with previous versions.

## v6 - 2020-07

* Drop support for node v8 and earlier

## v5 - 2018-11

* Add updateAgeOnGet option
* Guards around setting max/maxAge to non-numbers
* Use classes, drop support for old nodes

## v4 - 2015-12

* Improve performance
* add noDisposeOnSet option
* feat(prune): allow users to proactively prune old entries
* Use Symbols for private members
* Add maxAge setter/getter

## v3 - 2015-11

* Add cache.rforEach
* Allow non-string keys

## v2 - 2012-08

* add cache.pop()
* add cache.peek()
* add cache.keys()
* add cache.values()
* fix memory leak
* add `stale` option to return stale values before deleting
* use null-prototype object to avoid hazards
* make options argument an object

## v1 - 2010-05

* initial implementation
161 changes: 113 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -60,9 +60,9 @@ const options = {
},

// max time to live for items before they are considered stale
// note that stale items are NOT preemptively removed, and MAY
// live in the cache, contributing to its LRU max, long after they
// have expired.
// note that stale items are NOT preemptively removed by default,
// and MAY live in the cache, contributing to its LRU max, long after
// they have expired.
// Also, as this cache is optimized for LRU/MRU operations, some of
// the staleness/TTL checks will reduce performance, as they will incur
// overhead by deleting items.
@@ -153,8 +153,9 @@ If you put more stuff in it, then items will fall out.
Boolean, default `false`. Only relevant if `dispose` option is set.

* `ttl` - max time to live for items before they are considered stale.
Note that stale items are NOT preemptively removed, and MAY live in the
cache, contributing to its LRU max, long after they have expired.
Note that stale items are NOT preemptively removed by default, and MAY
live in the cache, contributing to its LRU max, long after they have
expired.

Also, as this cache is optimized for LRU/MRU operations, some of
the staleness/TTL checks will reduce performance, as they will incur
@@ -172,9 +173,33 @@ If you put more stuff in it, then items will fall out.

Deprecated alias: `maxAge`

* `ttlResolution` - Minimum amount of time in ms in which to check for
staleness. Defaults to `1`, which means that the current time is checked
at most once per millisecond.

Set to `0` to check the current time every time staleness is tested.

Note that setting this to a higher value _will_ improve performance
somewhat while using ttl tracking, albeit at the expense of keeping
stale items around a bit longer than intended.

* `ttlAutopurge` - Preemptively remove stale items from the cache.

Note that this may _significantly_ degrade performance, especially if
the cache is storing a large number of items. It is almost always best
to just leave the stale items in the cache, and let them fall out as
new items are added.

Note that this means that `allowStale` is a bit pointless, as stale
items will be deleted almost as soon as they expire.

Use with caution!

Boolean, default `false`

* `allowStale` - By default, if you set `ttl`, it'll only delete stale
items from the cache when you `get(key)`. That is, it's not
pre-emptively pruning items.
preemptively pruning items.

If you set `allowStale:true`, it'll return the stale value as well as
deleting it. If you don't set this, then it'll return `undefined` when
@@ -208,7 +233,9 @@ If you put more stuff in it, then items will fall out.
Create a new LRUCache. All options are documented above, and are on
the cache as public members.

* `cache.max`, `cache.ttl`, `cache.allowStale`, etc.
* `cache.max`, `cache.maxSize`, `cache.allowStale`, `cache.noDisposeOnSet`,
`cache.sizeCalculation`, `cache.dispose`, `cache.maxSize`, `cache.ttl`,
`cache.updateAgeOnGet`

All option names are exposed as public members on the cache object.

@@ -313,28 +340,79 @@ If you put more stuff in it, then items will fall out.
Delete any stale entries. Returns `true` if anything was removed,
`false` otherwise.

Deprecated alias: `prune`

* `forEach(fn, [thisp])`

Call the `fn` function with each set of `fn(value, key, cache)` in the
LRU cache, from most recent to least recently used.

Does not affect recency of use.

If `thisp` is provided, function will be called in the `this`-context
of the provided object.

* `rforEach(fn, [thisp])`

Same as `cache.forEach(fn, thisp)`, but in order from least recently
used to most recently used.

* `pop()`

Evict the least recently used item, returning its value.

Returns `undefined` if cache is empty.

### Internal Methods and Properties

Do not use or rely on these. They will change or be removed without
notice. They will cause undefined behavior if used inappropriately.
In order to optimize performance as much as possible, "private" members and
methods are exposed on the object as normal properties, rather than being
accessed via Symbols, private members, or closure variables.

**Do not use or rely on these.** They will change or be removed without
notice. They will cause undefined behavior if used inappropriately. There
is no need or reason to ever call them directly.

This documentation is here so that it is especially clear that this not
"undocumented" because someone forgot; it _is_ documented, and the
documentation is telling you not to do it.

Do not report bugs that stem from using these properties. They will be
**Do not report bugs that stem from using these properties.** They will be
ignored.

* `setKeyIndex()` Assign an index to a given key.
* `getKeyIndex()` Get the index for a given key.
* `deleteKeyIndex()` Remove the index for a given key.
* `getDisposeData()` Get the data to pass to a `dispose()` call.
* `callDispose()` Actually call the `dispose()` function.
* `onSet()` Called to assign data when `set()` is called.
* `evict()` Delete the least recently used item.
* `onDelete()` Perform actions required for deleting an entry.
* `isStale()` Check if an item is stale, by index.
* `list` The internal linked list of indexes defining recency.
* `initializeTTLTracking()` Set up the cache for tracking TTLs
* `updateItemAge(index)` Called when an item age is updated, by internal ID
* `setItemTTL(index)` Called when an item ttl is updated, by internal ID
* `isStale(index)` Called to check an item's staleness, by internal ID
* `initializeSizeTracking()` Set up the cache for tracking item size.
Called automatically when a size is specified.
* `removeItemSize(index)` Updates the internal size calculation when an
item is removed or modified, by internal ID
* `addItemSize(index)` Updates the internal size calculation when an item
is added or modified, by internal ID
* `indexes()` An iterator over the non-stale internal IDs, from most
recently to least recently used.
* `rindexes()` An iterator over the non-stale internal IDs, from least
recently to most recently used.
* `newIndex()` Create a new internal ID, either reusing a deleted ID,
evicting the least recently used ID, or walking to the end of the
allotted space.
* `evict()` Evict the least recently used internal ID, returning its ID.
Does not do any bounds checking.
* `connect(p, n)` Connect the `p` and `n` internal IDs in the linked list.
* `moveToTail(index)` Move the specified internal ID to the most recently
used position.
* `keyMap` Map of keys to internal IDs
* `keyList` List of keys by internal ID
* `valList` List of values by internal ID
* `sizes` List of calculated sizes by internal ID
* `ttls` List of TTL values by internal ID
* `starts` List of start time values by internal ID
* `next` Array of "next" pointers by internal ID
* `prev` Array of "previous" pointers by internal ID
* `head` Internal ID of least recently used item
* `tail` Internal ID of most recently used item
* `free` Stack of deleted internal IDs

## Performance

@@ -382,18 +460,21 @@ ideally as rarely as possible, so optimizing set over get would be unwise.
If performance matters to you:

1. If it's at all possible to use small integer values as keys, and you can
guarantee that no other types of values will be used as keys, then do that,
and use a cache such as [lru-fast](https://npmjs.com/package/lru-fast)
which uses an Object as its data store.
guarantee that no other types of values will be used as keys, then do
that, and use a cache such as
[lru-fast](https://npmjs.com/package/lru-fast), or [mnemonist's
LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache) which
uses an Object as its data store.
2. Failing that, if at all possible, use short non-numeric strings (ie,
less than 256 characters) as your keys.
3. If you know that the types of your keys will be long strings, strings
that look like floats, `null`, objects, or some mix of types, then this
library will work well for you.
4. Do not use a `dispose` function, size tracking, or ttl behavior, unless
absolutely needed. These features are convenient, and necessary in some
use cases, and every attempt has been made to make the performance
impact minimal, but it isn't nothing.
less than 256 characters) as your keys, and use [mnemonist's
LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache).
3. If the types of your keys will be long strings, strings that look like
floats, `null`, objects, or some mix of types, or if you aren't sure,
then this library will work well for you.
4. Do not use a `dispose` function, size tracking, or especially ttl
behavior, unless absolutely needed. These features are convenient, and
necessary in some use cases, and every attempt has been made to make the
performance impact minimal, but it isn't nothing.

## Breaking Changes in Version 7

@@ -404,20 +485,4 @@ some subtle changes as a result.
If you were relying on the internals of LRUCache in version 6 or before, it
probably will not work in version 7 and above.

### Specific API Changes

For the most part, the feature set has been maintained as much as possible.

However, some other cleanup and refactoring changes were made in v7 as
well.

* The `set()`, `get()`, and `has()` functions take options objects
instead of positional booleans/integers for optional parameters.
* `size` can be set explicitly on `set()`.
* `cache.length` was renamed to the more fitting `cache.size`.
* Option name deprecations:
* `stale` -> `allowStale`
* `length` -> `sizeCalculation`
* `maxAge` -> `ttl`
* The objects used by `cache.load()` and `cache.dump()` are incompatible
with previous versions.
For more info, see the [change log](CHANGELOG.md).
Loading