Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 63 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ node-cache

# Simple and fast NodeJS internal caching.

A simple caching module that has `set`, `get` and `delete` methods and works a little bit like memcached.
Keys can have a timeout (`ttl`) after which they expire and are deleted from the cache.
A simple caching module that has `set`, `get` and `delete` methods and works a little bit like memcached.
Keys can have a timeout (`ttl`) after which they expire and are deleted from the cache.
All keys are stored in a single object so the practical limit is at around 1m keys.

**Since `4.1.0`**:
*Key-validation*: The keys can be given as either `string` or `number`, but are casted to a `string` internally anyway.
*Key-validation*: The keys can be given as either `string` or `number`, but are casted to a `string` internally anyway.
All other types will either throw an error or call the callback with an error.


Expand All @@ -41,14 +41,16 @@ const myCache = new NodeCache();

### Options

- `stdTTL`: *(default: `0`)* the standard ttl as number in seconds for every generated cache element.
- `stdTTL`: *(default: `0`)* the standard ttl as number in seconds for every generated cache element.
`0` = unlimited
- `checkperiod`: *(default: `600`)* The period in seconds, as a number, used for the automatic delete check interval.
- `checkperiod`: *(default: `600`)* The period in seconds, as a number, used for the automatic delete check interval.
`0` = no periodic check.
- `errorOnMissing`: *(default: `false`)* en/disable throwing or passing an error to the callback if attempting to `.get` a missing or expired value.
- `useClones`: *(default: `true`)* en/disable cloning of variables. If `true` you'll get a copy of the cached variable. If `false` you'll save and get just the reference.
**Note:** `true` is recommended, because it'll behave like a server-based caching. You should set `false` if you want to save mutable objects or other complex types with mutability involved and wanted.
- `useClones`: *(default: `true`)* en/disable cloning of variables. If `true` you'll get a copy of the cached variable. If `false` you'll save and get just the reference.
**Note:** `true` is recommended, because it'll behave like a server-based caching. You should set `false` if you want to save mutable objects or other complex types with mutability involved and wanted.
_Here's a [simple code exmaple](https://runkit.com/mpneuried/useclones-example-83) showing the different behavior_
- `deleteOnExpire`: *(default: `true`)* whether variables will be deleted automatically when they expire.
If `true` the variable will be deleted. If `false` the variable will remain. You are encouraged to handle the variable upon the event `expired` by yourself.

```js
const NodeCache = require( "node-cache" );
Expand All @@ -59,7 +61,7 @@ const myCache = new NodeCache( { stdTTL: 100, checkperiod: 120 } );

`myCache.set( key, val, [ ttl ], [callback] )`

Sets a `key` `value` pair. It is possible to define a `ttl` (in seconds).
Sets a `key` `value` pair. It is possible to define a `ttl` (in seconds).
Returns `true` on success.

```js
Expand All @@ -75,7 +77,7 @@ myCache.set( "myKey", obj, function( err, success ){

> Note: If the key expires based on it's `ttl` it will be deleted entirely from the internal data object.

**Since `1.0.0`**:
**Since `1.0.0`**:
Callback is now optional. You can also use synchronous syntax.

```js
Expand Down Expand Up @@ -107,7 +109,7 @@ myCache.get( "myKey", function( err, value ){
});
```

**Since `1.0.0`**:
**Since `1.0.0`**:
Callback is now optional. You can also use synchronous syntax.

```js
Expand All @@ -118,7 +120,7 @@ if ( value == undefined ){
// { my: "Special", variable: 42 }
```

**Since `2.0.0`**:
**Since `2.0.0`**:

The return format changed to a simple value and a `ENOTFOUND` error if not found *( as `callback( err )` or on sync call as result instance of `Error` )*.

Expand Down Expand Up @@ -161,7 +163,7 @@ myCache.mget( [ "myKeyA", "myKeyB" ], function( err, value ){
});
```

**Since `1.0.0`**:
**Since `1.0.0`**:
Callback is now optional. You can also use synchronous syntax.

```js
Expand All @@ -174,7 +176,7 @@ value = myCache.mget( [ "myKeyA", "myKeyB" ] );
*/
```

**Since `2.0.0`**:
**Since `2.0.0`**:

The method for mget changed from `.get( [ "a", "b" ] )` to `.mget( [ "a", "b" ] )`

Expand All @@ -193,7 +195,7 @@ myCache.del( "myKey", function( err, count ){
});
```

**Since `1.0.0`**:
**Since `1.0.0`**:
Callback is now optional. You can also use synchronous syntax.

```js
Expand All @@ -216,7 +218,7 @@ myCache.del( [ "myKeyA", "myKeyB" ], function( err, count ){
});
```

**Since `1.0.0`**:
**Since `1.0.0`**:
Callback is now optional. You can also use synchronous syntax.

```js
Expand All @@ -234,7 +236,7 @@ value = myCache.del( [ "A", "B", "C", "D" ] );

`myCache.ttl( key, ttl, [callback] )`

Redefine the ttl of a key. Returns true if the key has been found and changed. Otherwise returns false.
Redefine the ttl of a key. Returns true if the key has been found and changed. Otherwise returns false.
If the ttl-argument isn't passed the default-TTL will be used.

The key will be deleted when passing in a `ttl < 0`.
Expand Down Expand Up @@ -302,7 +304,7 @@ ts = myCache.getTtl( "unknownKey" )

`myCache.keys( [callback] )`

Returns an array of all existing keys.
Returns an array of all existing keys.

```js
// async
Expand All @@ -325,7 +327,7 @@ console.log( mykeys );

`myCache.getStats()`

Returns the statistics.
Returns the statistics.

```js
myCache.getStats();
Expand All @@ -344,7 +346,7 @@ myCache.getStats();

`myCache.flushAll()`

Flush all data.
Flush all data.

```js
myCache.flushAll();
Expand Down Expand Up @@ -379,7 +381,7 @@ You will get the `key` and the `value` as callback argument.

```js
myCache.on( "set", function( key, value ){
// ... do something ...
// ... do something ...
});
```

Expand All @@ -390,7 +392,7 @@ You will get the `key` and the deleted `value` as callback arguments.

```js
myCache.on( "del", function( key, value ){
// ... do something ...
// ... do something ...
});
```

Expand All @@ -401,7 +403,7 @@ You will get the `key` and `value` as callback argument.

```js
myCache.on( "expired", function( key, value ){
// ... do something ...
// ... do something ...
});
```

Expand All @@ -411,7 +413,7 @@ Fired when the cache has been flushed.

```js
myCache.on( "flush", function(){
// ... do something ...
// ... do something ...
});
```

Expand All @@ -426,8 +428,8 @@ Instead of returning an object with the key `{ "myKey": "myValue" }` it returns

### version `3.x`

Due to the [Issue #30](https://github.com/mpneuried/nodecache/issues/30) and [Issue #27](https://github.com/mpneuried/nodecache/issues/27) variables will now be cloned.
This could break your code, because for some variable types ( e.g. Promise ) its not possible to clone them.
Due to the [Issue #30](https://github.com/mpneuried/nodecache/issues/30) and [Issue #27](https://github.com/mpneuried/nodecache/issues/27) variables will now be cloned.
This could break your code, because for some variable types ( e.g. Promise ) its not possible to clone them.
You can disable the cloning by setting the option `useClones: false`. In this case it's compatible with version `2.x`.

## Benchmarks
Expand All @@ -437,37 +439,37 @@ You can disable the cloning by setting the option `useClones: false`. In this ca
After adding io.js to the travis test here are the benchmark results for set and get of 100000 elements.
But be careful with this results, because it has been executed on travis machines, so it is not guaranteed, that it was executed on similar hardware.

**node.js `0.10.36`**
SET: `324`ms ( `3.24`µs per item )
GET: `7956`ms ( `79.56`µs per item )
**node.js `0.10.36`**
SET: `324`ms ( `3.24`µs per item )
GET: `7956`ms ( `79.56`µs per item )

**node.js `0.12.0`**
SET: `432`ms ( `4.32`µs per item )
GET: `42767`ms ( `427.67`µs per item )
**node.js `0.12.0`**
SET: `432`ms ( `4.32`µs per item )
GET: `42767`ms ( `427.67`µs per item )

**io.js `v1.1.0`**
SET: `510`ms ( `5.1`µs per item )
GET: `1535`ms ( `15.35`µs per item )
**io.js `v1.1.0`**
SET: `510`ms ( `5.1`µs per item )
GET: `1535`ms ( `15.35`µs per item )

### Version 2.0.x

Again the same benchmarks by travis with version 2.0

**node.js `0.6.21`**
SET: `786`ms ( `7.86`µs per item )
GET: `56`ms ( `0.56`µs per item )
**node.js `0.6.21`**
SET: `786`ms ( `7.86`µs per item )
GET: `56`ms ( `0.56`µs per item )

**node.js `0.10.36`**
**node.js `0.10.36`**
SET: `353`ms ( `3.53`µs per item )
GET: `41`ms ( `0.41`µs per item )
GET: `41`ms ( `0.41`µs per item )

**node.js `0.12.2`**
SET: `327`ms ( `3.27`µs per item )
GET: `32`ms ( `0.32`µs per item )
**node.js `0.12.2`**
SET: `327`ms ( `3.27`µs per item )
GET: `32`ms ( `0.32`µs per item )

**io.js `v1.7.1`**
SET: `238`ms ( `2.38`µs per item )
GET: `34`ms ( `0.34`µs per item )
**io.js `v1.7.1`**
SET: `238`ms ( `2.38`µs per item )
GET: `34`ms ( `0.34`µs per item )

> As you can see the version 2.x will increase the GET performance up to 200x in node 0.10.x.
This is possible because the memory allocation for the object returned by 1.x is very expensive.
Expand All @@ -476,36 +478,36 @@ This is possible because the memory allocation for the object returned by 1.x is

*see [travis results](https://travis-ci.org/mpneuried/nodecache/builds/64560503)*

**node.js `0.6.21`**
SET: `786`ms ( `7.24`µs per item )
GET: `56`ms ( `1.14`µs per item )
**node.js `0.6.21`**
SET: `786`ms ( `7.24`µs per item )
GET: `56`ms ( `1.14`µs per item )

**node.js `0.10.38`**
**node.js `0.10.38`**
SET: `353`ms ( `5.41`µs per item )
GET: `41`ms ( `1.23`µs per item )
GET: `41`ms ( `1.23`µs per item )

**node.js `0.12.4`**
SET: `327`ms ( `4.63`µs per item )
GET: `32`ms ( `0.60`µs per item )
**node.js `0.12.4`**
SET: `327`ms ( `4.63`µs per item )
GET: `32`ms ( `0.60`µs per item )

**io.js `v2.1.0`**
SET: `238`ms ( `4.06`µs per item )
**io.js `v2.1.0`**
SET: `238`ms ( `4.06`µs per item )
GET: `34`ms ( `0.67`µs per item )

> until the version 3.0.x the object cloning is included, so we lost a little bit of the performance

### Version 3.1.x

**node.js `v0.10.41`**
SET: `305ms` ( `3.05µs` per item )
**node.js `v0.10.41`**
SET: `305ms` ( `3.05µs` per item )
GET: `104ms` ( `1.04µs` per item )

**node.js `v0.12.9`**
SET: `337ms` ( `3.37µs` per item )
**node.js `v0.12.9`**
SET: `337ms` ( `3.37µs` per item )
GET: `167ms` ( `1.67µs` per item )

**node.js `v4.2.6`**
SET: `356ms` ( `3.56µs` per item )
**node.js `v4.2.6`**
SET: `356ms` ( `3.56µs` per item )
GET: `83ms` ( `0.83µs` per item )

## Compatibility
Expand Down
14 changes: 9 additions & 5 deletions _src/lib/node_cache.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ module.exports = class NodeCache extends EventEmitter
useClones: true
# en/disable throwing errors when trying to `.get` missing or expired values.
errorOnMissing: false
# whether values should be deleted automatically at expiration
deleteOnExpire: true
, @options )

# statistics container
Expand Down Expand Up @@ -488,16 +490,18 @@ module.exports = class NodeCache extends EventEmitter

# ## _check
#
# internal method the check the value. If it's not valid any moe delete it
# internal method the check the value. If it's not valid any more delete it
_check: ( key, data )=>
_retval = true
# data is invalid if the ttl is to old and is not 0
#console.log data.t < Date.now(), data.t, Date.now()
if data.t isnt 0 and data.t < Date.now()
@del( key )
if @options.deleteOnExpire
_retval = false;
@del( key )
@emit( "expired", key, @_unwrap(data) )
return false
else
return true

return _retval

# ## _isInvalidKey
#
Expand Down
26 changes: 21 additions & 5 deletions _src/test/mocha_test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ localCacheTTL = new nodeCache({
checkperiod: 0
})

localCacheNoDelete = new nodeCache({
stdTTL: 0.3,
checkperiod: 0
deleteOnExpire: false
})

BENCH = {}

Expand All @@ -35,14 +40,14 @@ localCache._killCheckPeriod()
state = {}

describe "`#{pkg.name}@#{pkg.version}` on `node@#{process.version}`", () ->

after ->
txt = "Benchmark node@#{process.version}:"
for type, ops of BENCH
txt += "\n - #{type}: #{ops.toFixed(1)} ops/s"
console.log txt
return

describe "general callback-style", () ->
before () ->
state =
Expand Down Expand Up @@ -1407,7 +1412,18 @@ describe "`#{pkg.name}@#{pkg.version}` on `node@#{process.version}`", () ->
return
return
return



it "set a key key with a cache initialized with no automatic delete on expire", (done) ->
localCacheNoDelete.set state.key1, state.val, (err, res) ->
setTimeout(() ->
res = localCacheNoDelete.get state.key1
should(res).eql(state.val)
done()
return
, 500)
return

it "test issue #78 with expire event not fired", ( done )->
@timeout( 6000 )
localCacheTTL2 = new nodeCache({
Expand All @@ -1416,10 +1432,10 @@ describe "`#{pkg.name}@#{pkg.version}` on `node@#{process.version}`", () ->
})
expCount = 0
expkeys = [ "ext78_test:a", "ext78_test:b" ]

localCacheTTL2.set( expkeys[ 0 ], expkeys[ 0 ], 2)
localCacheTTL2.set( expkeys[ 1 ], expkeys[ 1 ], 3)

localCacheTTL2.on "expired", ( key, value )->
key.should.eql( expkeys[ expCount ] )
value.should.eql( expkeys[ expCount ] )
Expand Down
Loading