Skip to content

Commit

Permalink
Update documentation (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
vweevers authored Sep 12, 2021
1 parent f3555d2 commit 9754a90
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 50 deletions.
90 changes: 43 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,66 +24,62 @@

## Usage

Augment `levelup` to handle a new `'ttl'` option on `put()` and `batch()` that specifies the number of milliseconds an entry should remain in the data store. After the TTL, the entry will be automatically cleared for you.
**If you are upgrading:** please see [`UPGRADING.md`](UPGRADING.md).

Requires [`levelup`][levelup], [`level`][level] or [`level-hyper`][level-hyper] to be installed separately.
Augment `levelup` to handle a new `ttl` option on `put()` and `batch()` that specifies the number of milliseconds an entry should remain in the data store. After the TTL, the entry will be automatically cleared for you.

**_Note 1: Version 1.0.0 data stores are not backward compatible with previous versions. If you have unexpired entries in a data store managed by pre-1.0.0, don't expect them to expire if you upgrade to 1.0.0+._** _This is due to a level-sublevel change. It is also recommended that you only use level-sublevel 6.0.0+ with level-ttl._

**_Note 2: `level-ttl` has partial support for `level-spaces`. It should work fine as long as you don't use the `'defaultTTL'` feature, see below. This is being worked on so we can have full support for `level-spaces` as well._**
Requires [`levelup`][levelup], [`level`][level] or one of its variants like [`level-rocksdb`][level-rocksdb] to be installed separately.

```js
var levelup = require('level')
, ttl = require('level-ttl')
const level = require('level')
const ttl = require('level-ttl')

var db = levelup('/tmp/foo.db')
db = ttl(db)
const db = ttl(level('./db'))

// --------------------------- put() --------------------------- //
// this entry will only stay in the data store for 1 hour
db.put('foo', 'bar', { ttl: 1000 * 60 * 60 }, function (err) { /* .. */ })
// This entry will only stay in the store for 1 hour
db.put('foo', 'bar', { ttl: 1000 * 60 * 60 }, (err) => {
// ..
})

// -------------------------- batch() -------------------------- //
// the two 'put' entries will only stay in the data store for 1 hour
db.batch([
{ type: 'put', key: 'foo', value: 'bar' }
, { type: 'put', key: 'bam', value: 'boom' }
, { type: 'del', key: 'w00t' }
], { ttl: 1000 * 60 * 60 }, function (err) { /* .. */ })
// Same for these two entries
{ type: 'put', key: 'foo', value: 'bar' },
{ type: 'put', key: 'bam', value: 'boom' },
{ type: 'del', key: 'w00t' }
], { ttl: 1000 * 60 * 5 }, (err) => {})
```

If you put the same entry twice, you **refresh** the TTL to the _last_ put operation. In this way you can build utilities like [session managers](https://github.com/rvagg/node-level-session/) for your web application where the user's session is refreshed with each visit but expires after a set period of time since their last visit.

Alternatively, for a lower write-footprint you can use the `ttl()` method that is added to your `levelup` instance which can serve to insert or update a ttl for any given key in the database (even if that key doesn't exist but may in the future! Crazy!).
Alternatively, for a lower write-footprint you can use the `ttl()` method that is added to your `levelup` instance which can serve to insert or update a ttl for any given key in the database - even if that key doesn't exist but may in the future!

```js
db.put('foo', 'bar', function (err) { /* .. */ })
db.ttl('foo', 1000 * 60 * 60, function (err) { /* .. */ })
db.put('foo', 'bar', (err) => {})
db.ttl('foo', 1000 * 60 * 60, (err) => {})
```

`level-ttl` uses an internal scan every 10 seconds by default, this limits the available resolution of your TTL values, possibly delaying a delete for up to 10 seconds. The resolution can be tuned by passing the `'checkFrequency'` option to the `ttl()` initialiser.
`level-ttl` uses an internal scan every 10 seconds by default, this limits the available resolution of your TTL values, possibly delaying a delete for up to 10 seconds. The resolution can be tuned by passing the `checkFrequency` option to the `ttl()` initialiser.

```js
var db = levelup('/tmp/foo.db')
// scan for deletables every second
db = ttl(db, { checkFrequency: 1000 })

/* .. */
// Scan every second
const db = ttl(level('./db'), {
checkFrequency: 1000
})
```

Of course, a scan takes some resources, particularly on a data store that makes heavy use of TTLs. If you don't require high accuracy for actual deletions then you can increase the `'checkFrequency'`. Note though that a scan only involves invoking a `levelup` ReadStream that returns _only the entries due to expire_, so it doesn't have to manually check through all entries with a TTL. As usual, it's best to not do too much tuning until you have you have something worth tuning!
Of course, a scan takes some resources, particularly on a data store that makes heavy use of TTLs. If you don't require high accuracy for actual deletions then you can increase the `checkFrequency`. Note though that a scan only involves invoking a `levelup` ReadStream that returns _only the entries due to expire_, so it doesn't have to manually check through all entries with a TTL. As usual, it's best to not do too much tuning until you have you have something worth tuning!

### Default TTL

You can set a default ttl value for all your keys by passing the `'defaultTTL'` option to the `ttl()` initialiser. This can be overridden by explicitly setting the ttl value.

In the following examle `'foo'` will expire in 15 minutes while `'beep'` will expire in one minute.
You can set a default ttl value for all your keys by passing the `defaultTTL` option to the `ttl()` initialiser. This can be overridden per operation. In the following example A will expire in 15 minutes while B will expire in one minute.

```js
var db = levelup('/tmp/foo.db')
db = ttl(db, { defaultTTL: 15 * 60 * 1000 })
db.put('foo', 'bar', function (err) { /* .. */ })
db.put('beep', 'boop', { ttl: 60 * 1000 }, function (err) { /* .. */ })
const db = ttl(level('./db'), {
defaultTTL: 15 * 60 * 1000
})

db.put('A', 'beep', (err) => {})
db.put('B', 'boop', { ttl: 60 * 1000 }, (err) => {})
```

### `opts.sub`
Expand All @@ -93,14 +89,16 @@ You can provide a custom storage for the meta data by using the `opts.sub` prope
A db for the data and a separate to store the meta data:

```js
var level = require('level')
, ttl = require('level-ttl')
, meta = level('./meta')
, db = ttl(level('./db'), { sub: meta })
, batch = [
{ type: 'put', key: 'foo', value: 'foovalue' }
, { type: 'put', key: 'bar', value: 'barvalue' }
]
const level = require('level')
const ttl = require('level-ttl')
const meta = level('./meta')

const db = ttl(level('./db'), { sub: meta })

const batch = [
{ type: 'put', key: 'foo', value: 'foo value' },
{ type: 'put', key: 'bar', value: 'bar value' }
]

db.batch(batch, { ttl: 100 }, function (err) {
db.createReadStream()
Expand All @@ -116,11 +114,9 @@ db.batch(batch, { ttl: 100 }, function (err) {
})
```

For more examples on this please check the tests involving `level-sublevel`.

### Shutting down

`level-ttl` uses a timer to regularly check for expiring entries (don't worry, the whole data store isn't scanned, it's very efficient!). The `db.close()` method is automatically wired to stop the timer but there is also a more explicit <b><code>db.stop()</code></b> method that will stop the timer and not pass on to a `close()` underlying `levelup` instance.
`level-ttl` uses a timer to regularly check for expiring entries (don't worry, the whole data store isn't scanned, it's very efficient!). The `db.close()` method is automatically wired to stop the timer but there is also a more explicit `db.stop()` method that will stop the timer and not close the underlying `levelup` instance.

## Contributing

Expand All @@ -144,4 +140,4 @@ Support us with a monthly donation on [Open Collective](https://opencollective.c

[level]: https://github.com/Level/level

[level-hyper]: https://github.com/Level/level-hyper
[level-rocksdb]: https://github.com/Level/level-rocksdb
15 changes: 15 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Upgrade Guide

This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [changelog](CHANGELOG.md).

## 3.0.0

Removed use of `level-spaces` internally and dropped support for `options.sublevel`. You can still use `level-spaces` by setting `options.sub`, which should work fine as long as you don't use `options.defaultTTL`.

## 2.0.0

Switched to `level-spaces`.

## 1.0.0

Version 1.0.0 stores are not backwards compatible with previous versions. If you have unexpired entries in a store managed by < 1.0.0, don't expect them to expire if you upgrade to 1.0.0. This is due to a `level-sublevel` change. It is also recommended that you only use `level-sublevel` >= 6.0.0 with `level-ttl`.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
"name": "level-ttl",
"version": "3.1.1",
"description": "Adds a 'ttl' option to levelup for puts and batches",
"authors": [
"Rod Vagg <[email protected]> (https://github.com/rvagg)"
],
"author": "Rod Vagg <[email protected]> (https://github.com/rvagg)",
"license": "MIT",
"main": "./level-ttl.js",
"scripts": {
Expand Down

0 comments on commit 9754a90

Please sign in to comment.