npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

storage-lru

v0.1.1

Published

An LRU implementation that can be used with local storage, or other storage mechanisms that support a similar interface.

Downloads

59

Readme

StorageLRU Build Status Dependency Status Coverage Status

StorageLRU is a LRU implementation that can be used with local storage, or other storage mechanisms that support a similar interface.

Note: This library is written in CommonJS style. To use it in browser, please use tools like Browserify and Webpack.

Features

Pluggable Underline Storage

You can use your own storage of choice with StorageLRU, as long as it conforms to an asyncronous API.

For syncronous storage solutions (such as html5 localStorage), we also provide the asyncify util, which simply wraps your syncronous storage object inside an asyncronous interface.

Following is the async API details:

getItem : function (key, callback) - get the item with the associated key;
setItem : function (key, item, callback) - set an item to the passed in key;
removeItem : function (key, callback) - remove the item with the associated key;
keys : function (num, callback) - get `num` number of keys of items stored;

Note that your storage should return 'null' or 'undefined' when a requested key does not exist.

Examples:

// Example 1: async storage
var StorageLRU = require('storage-lru').StorageLRU;
// var myAsyncStorage = ...;
var lru = new StorageLRU(myAsyncStorage);

// Example 2: localStorage
var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage));

Max-Age and Stale-While-Revalidate

When you save an item to the StorageLRU, you are required to specify a cache control string with HTTP Cache-Control header syntax, in which max-age is required and stale-while-revalidate is optional.

The max-age defines when the item will expire. The stale-while-revalidate defines a time window after expiration, in which the item is marked as stale but still usable. If the time has passed this time window as well, this item will not be fetchable, and be purged.

If getItem() is called on an item when it is in the stale-while-revalidate time window, StorageLRU will try to refresh the data during this time window, assuming a revalidateFn was passed when the StorageLRU instance was created. The revalidateFn function will be used to fetch the stale item. If a fresh value is fetched successfully, StorageLRU will save the new value to the underline storage.

The revalidate success/failure count will be recorded in the Stats.

Example:

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
// Creating a StorageLRU instance with an item revalidation function
var lru = new StorageLRU(
    asyncify(localStorage), 
    {
        revalidateFn: function(key, callback) {
            var newValue = someFunctionToRefetchFromSomewhere(key); // most likely be async
            callback(null, newValue); // make sure callback is invoked
        }
    });
// Saving item 'fooJSON', which expires in 5 minutes and has a stale-while-revalidate time window of 1 day after expiration.
lru.setItem(
    'fooJSON',    // key
    {             // value
        foo: 'bar'
    },
    {             // options
        json: true,
        cacheControl:'max-age=300,stale-while-revalidate=86400'
    }, function (err) {
        if (err) {
            // something went wrong. Item not saved.
            console.log('Failed to save item: err=', err);
            return;
        }
    }
);

Priority

When you save an item to StorageLRU, you can assign a priority. Lower priority items get purged first, if all other conditions are the same.

| Priority | Description | |----------|--------------------------| | 1 | Critical - Last to purge | | 2 | Important | | 3 | Normal | | 4 | Low - First to purge |

Example:

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage));
lru.setItem('fooJSON', {foo: 'bar'}, {json: true, priority: 1}, function (err) {
    if (err) {
        // something went wrong. Item not saved.
        console.log('Failed to save item: err=', err);
    }
});

Automatic Purging

When the storage becomes full, StorageLRU will purge the existing items to make enough space. The default purging precendence order is as following:

  • bad entry (invalid meta info),
  • truly stale (passed stale-while-revaliate window),
  • lowest priority,
  • least recently accessed,
  • bigger byte size

Basically, the bad items will be purged first; next will be the items that have expired and passed stale-while-revaliate window; then the lowest priority items; then the least recently accessed items; if there happen to the two items with the same access time, the one takes more space will be purged first.

Customizable PurgeComparator

You can replace the default purging algorithm with your own, by specifying a purgeComparator function when creating the StorageLRU instance.

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage), {
    // always purge the largest item first
    purgeComparator: function (meta1, meta2) {
        if (meta1.size > meta2.size) {
            return 1;
        } else if (meta1.size === meta2.size){
            return 0;
        } else {
            return -1;
        }
    }
});

Configurable Purge Factor

You can configure how much extra space to purge, by providing a purgeFactor param when instantiating the StorageLRU instance. It should be a positive float number.

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage), {
    // purgeFactor controls amount of extra space to purge.
    // E.g. if space needed for a new item is 1000 characters, StorageLRU will actually
    //      try to purge (1000 + 1000 * purgeFactor) characters.
    purgeFactor: 0.5
});

Configurable Purge Attempts

In addition to how much extra space to purge, you can also configure how many items to retrieve from underlying storage in the event that purge is unable to find enough free space. By providing a maxPurgeAttempts param you can set how many times purge will attempt to free up space. Each attempt will increase the number of keys looked up by the purgeLoadIncrease param.

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage), {
    // maxPurgeAttempts controls the number of times to try purging,
    // each attempt will look through more items.
    maxPurgeAttempts: 3,
    // purgeLoadIncrease controls the number of additional keys to look up during each 
    // successive purge attempt.
    // E.g. if this is the second additional purge attempt, StorageLRU will attempt to load
    //      (2 * 500) keys.
    purgeLoadIncrease: 500
});

Purge Notification

If you want to be notified when items get purged from the storage, you can register a callback function when creating the StorageLRU instance.

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;
var lru = new StorageLRU(asyncify(localStorage), {
    // purgeFactor controls amount of extra space to purge.
    // E.g. if space needed for a new item is 1000 characters, StorageLRU will actually
    //      try to purge (1000 + 1000 * purgeFactor) characters.
    purgeFactor: 0.5,
    purgedFn: function (purgedKeys) {
        console.log('These keys were purged:', purgedKeys);
    }
});

Stats

StorageLRU collects statistics data for you to tune the LRU to work efficiently with the specific characteristics of your app data. For example, you can customize purgeFactor to be a bigger number if your app saves several items in a short time interval.

Currently stats data collected include the following:

| Name | Description | |-------|-------------------------------------------------------------------------------------------------------------------------------------| | hit | Number of cache hits | | miss | Number of cache misses | | stale | Number of times where stale items were returned (cache hit with data that expired but still within stale-while-revalidate window) | | error | Number of errors occurred during getItem | | revalidateSuccess | Success count for revalidating a stale item, if revalidateFn is provided when the StorageLRU instance is instantiated. | | revalidateFailure | Failure count for revalidating a stale item, if revalidateFn is provided when the StorageLRU instance is instantiated. |

Example:

var stats = lru.stats();

Usage

var StorageLRU = require('storage-lru').StorageLRU;
var asyncify = require('storage-lru').asyncify;

var lru = new StorageLRU(asyncify(localStorage), {
    purgeFactor: 0.5,  // this controls amount of extra space to purge.
    purgedFn: function (purgedKeys) {
        console.log('These keys were purged:', purgedKeys);
    }
});
console.log(lru.numItems()); // output 0, assuming the storage is clear

lru.setItem('foo', 'bar', {}, function (err) {
    if (err) {
        // something went wrong. Item not saved.
        console.log('Failed to save item: err=', err);
    }
});

lru.setItem('fooJSON', {foo: 'bar'}, {json: true}, function (err) {
    if (err) {
        // something went wrong. Item not saved.
        console.log('Failed to save item: err=', err);
    }
});

lru.getItem('foo', {json: false}, function (err, value) {
    if (err) {
        // something went wrong, for example, can't deserialize
        console.log('Failed to fetch item: err=', err);
        return;
    }
    console.log('The value of "foo" is: ', value);
});

lru.removeItem('foo', function (err) {
    if (err) {
        // something went wrong. Item not removed.
    }
});

var stats = lru.stats();

Error Codes

| Code | Message | Description | Sources | |------|--------------------|---------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------| | 1 | disabled | The underline storage (storage instance passed to StorageLRU) is disabled. | StorageLRU.setItem() | | 2 | cannot deserialize | Not able to deserialize the stored value. | | | 3 | cannot serialize | Not able to serialize the value for storage. | StorageLRU.setItem() | | 4 | bad cacheControl | Invalid cache control string was passed to StorageLRU.setItem(). For example, containing no-store, no-cache, negative max-age. | StorageLRU.setItem() | | 5 | invalid key | Invalid key was provided, e.g. empty string | StorageLRU.setItem(), StorageLRU.getItem(), StorageLRU.removeItem() | | 6 | not enough space | The underline storage does not have enough space for the item being saved, even after purging old items. | StorageLRU.setItem() | | 7 | revalidate failed | Revalidating a stale item failed. (Internal error, not exposed via public API.) | StorageLRU._revalidate() |

Polyfills

This library requires the following Polyfill:

License

This software is free to use under the Yahoo! Inc. BSD license. See the LICENSE file for license text and copyright information.

Third-pary open source code used are listed in our package.json file.