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

tsfoo

v0.3.0

Published

Timeseries Database

Downloads

83

Readme

Timeseries Foo

Well, just another database to store time-series data.

Concept

Some unordered thoughts:

  • Every database holds many series. No forced semantics in series names - just names. If you would like to have semantic information inside the series name, just put it in the way you like it.
  • Every series has many records. Every record has a timestamp (ms accuracy) and a value. The timestamps must be monotonically increasing but don't have to be equidistant. This decision should be beneficial to flexibility while ensuring seeking to a specific timestamp to be an inexpensive task.
  • Every record is stored in two different files: an index file idx-${seriesName} and a data file dat-${seriesName}. The index holds the timestamp together with an offset and a size that points to the data file. The value is stored serialised using CBOR inside the data file.
  • Every series can have one user writing to it (enforced by exclusive file locks) and many users reading from it.
  • The series can be read from while writing to it. The only connection between the writing and the reading task is the file system itself.
  • Reading and writing utilises that readable resp. writeable stream of node js in object mode.

API

const {openDB} = require('tsfoo');
openDB(dbPath).then((db) => {...});

Opens a database stored at dbPath.

Method: db.createWriter()

db.createWriter([series]).then((writer) => {
	writer.write(record).then(() => {...});
	writer.close().then(() => {...})
})

Creates a Writer instance writer. series is the series name the record is written to. If series is omitted, a series must be stated within each record. series.write(record) writes to the database and returns a Promise which is resolved once the record has been written to disk. record is an object with the following items:

  • value: The value written to the database.
  • timestamp: The timestamp when value has been recorded. Default: Date.now().
  • series: If no series has been stated during writer creation, this states the series, this record shall be written to.
  • ptr: A number representing the record number in the series.

series.close() closes the writer. Its returned Promise is resolved if the series has been closed.

Method: db.createWriteStream()

db.createWriteStream([series]).then((writer) => {})

Returns an instance of stream.Writable in object mode. series is the series streamed records are written to. If series is omitted, a series must be stated within record.

Method: db.createReader()

db.createReader(series[, opts]).then((reader) => {
	reader.read([ropts]).then((record) => {...});
	reader.close().then(() => {...})
})

Creates a Reader instance reader reading from series. opts can have the following properties:

  • ptr: Start reading after the given record.
  • from: A timestamp in ms. Start reading records after the given timestamp (i.e. excluding the record with the given timestamp).
  • to: A timestamp in ms. Start reading records until the given timestamp (i.e. including the record with the given timestamp.
  • follow: Boolean. If set to false the reader stops reading if it reached the end of the series. Default: true.

reader.read() returns a Promise which is resolved with:

  • null if the EOF is reached and follow is set to false or if the last record matching the to constraint has been streamed
  • or an Object containing the next record with the items timestamp, series, value.

ropts is an object with the following properties:

  • blocking: Boolean. If set to false, read() will reject with an Error if the EOF of the series has been reached. Default: true.

reader.close() closes the reader. Its returned promise is resolved if the series has been closed.

Method: db.createReadStream()

db.createReadStream(series[, opts]).then((reader) => {})

Returns an instance of stream.Readable in object mode. series is the series wich sources the read stream.

Example

const os = require('os');
const tsfoo = require('tsfoo');

// Everything is stored in a directory
tsfoo.openDB('db-dir').then(async (db) => {
	// Write current load into one series
	const writeLoadSeries = await db.createWriteStream('load');
	setInterval(() => writeLoadSeries.write({
		timestamp: Date.now(),
		value: os.loadavg()[0]
	}), 10000);

	// Read back written data
	const readLoadSeries = await db.createReadStream('load');
	readLoadSeries.on('data', (record) => console.log(record.timestamp, record.value));
});