View on GitHub

whippet-db

Fast embedded key-value database engine for Java.

Whippet-db

An embedded key-value store for Java.

Overview

Whippet-db is a fast embedded local key-value store for Java, either in-memory or persistent - of your choice. The library is extremally low-footprint - less then 150 kb, with no dependencies, and is very simple to use. It is written in pure classic Java 1.8 with no use of Unsafe or native methods, so there are no problems with transition to newer Java versions.

Applications

Features

What Whippet DB is not

Setup

Maven dependency

not yet available

or download the jar

Documentation

See the API doc

Code samples

import io.github.whippetdb.db.api.DbBuilder;
import io.github.whippetdb.db.api.types.LongIO;
import io.github.whippetdb.db.api.types.CharsIO;

...

// in-memory Long:Long map
static Map<Long,Long>  = new DbBuilder(new LongIO(), new LongIO()).create().asMap();

// on-disk, synchronized Long:Long map
static Map<Long,Long>  = new DbBuilder(new LongIO(), new LongIO())
	.synchronize(true)
	.create("path/to/file").asMap();

// journaling on-disk synchronized Long:Long map
static Map<Long,Long>  = new DbBuilder(new LongIO(), new LongIO())
	.journaling(true)
	.synchronize(true)
	.create("path/to/file").asMap();

// journaling on-disk synchronized CharSequence:CharSequence map;
// for better performance provide expected average key and value sizes
static Map<CharSequence,CharSequence>  = new DbBuilder(new CharsIO(20,null), new CharsIO(50,null))
	.journaling(true)
	.synchronize(true)
	.create("path/to/file").asMap();

Performance

The important feature of Whipet, which may seem both as a problem and as a benefit, is that its performance is very sensitive to the randomness of the keys. In more exact terms, it’s sensitive to inter- and intra-correlation of bits in the keys. The more correlated are the keys, the better is performance, both in the terms of used space and speed. So Whippet shines when the keys are sequential numbers, and is modest when the keys are strongly random, the difference reaching 5-6 times in speed and 1.5-1.7 times in used space.

The following pictures compare the typical insertion speed and used space of 3 implementations of java.util.Map<Long,Long> - the Whippet DB, the Cronicle Map, and the java.util.HashMap. The implementations were run against the three sets of 50M keys - serial, moderately random and strongly random. The HashMap wasn’t able to insert more then 33M keys, it just got stuck in garbage collection.

Keys type # of inserted keys vs time Insertion speed vs time Used space vs # of inserted keys
Sequential image image image
Moderately random image image image
Strongly random image image image

The table below shows the typical figures for a workload consisting of 50M fresh inserts, followed by 50M reads, then 50M deletes, then 50M secondary inserts, against the three key sets described above. Both keys and values are 8-byte Longs. For comparison there are also figures for Cronicle Map.

Keys type Inserts, op/sec Reads, op/sec Deletes, op/sec Inserts, op/sec Average, op/sec
Whippet, sequential keys 5,921,364 (38 bytes/key) 9,626,492 9,044,862 7,257,947 (38 bytes/key) 7,676,069
Whippet, moderately random keys 2,526,528 (42 bytes/key) 3,243,383 3,118,373 2,169,009 (42 bytes/key) 2,692,079
Whippet, strongly random keys 1,768,581 (52 bytes/key) 2,182,096 2,204,707 1,633,853 (52 bytes/key) 1,914,493
Chronicle, sequential keys 2,606,610 (27 bytes/key) 4,689,551 2,506,391 2,713,998 (27 bytes/key) 2,931,863
Chronicle, moderately random keys 2,487,562 (27 bytes/key) 4,405,674 2,485,830 2,597,267 (27 bytes/key) 2,824,300
Chronicle, strongly random keys 2,469,867 (27 bytes/key) 4,368,338 2,451,340 2,583,445 (27 bytes/key) 2,799,512