H2 Database Engine - A very fast, open source, JDBC API database with embedded and server modes, transaction support, multi-version concurrency, browser-based console application, encrypted databases, fulltext search, and pure Java implementation with small footprint
—
MVStore is H2 Database's advanced storage engine that can be used independently as a high-performance, persistent key-value store. It provides ACID transactions, multi-version concurrency control (MVCC), and various specialized data structures including maps, trees, and spatial indexes.
The main store class that manages persistent key-value maps with ACID transactions.
public final class MVStore implements AutoCloseable {
// Static factory methods
public static MVStore open(String fileName);
public static Builder builder();
// Map management
public <K, V> MVMap<K, V> openMap(String name);
public <M extends MVMap<K, V>, K, V> M openMap(String name, MVMap.MapBuilder<M, K, V> builder);
public <K, V> MVMap<K, V> openMap(String name, DataType keyType, DataType valueType);
public void removeMap(String name);
public Set<String> getMapNames();
// Store information
public Map<String, String> getLayoutMap();
public long getCurrentVersion();
public int getFileStore().getReadCount();
public int getFileStore().getWriteCount();
public long getFileStore().size();
// Transaction and persistence
public void commit();
public long commitAndSave();
public void rollback();
public void save();
// Store lifecycle
public void close();
public void closeImmediately();
public boolean isClosed();
public MVStoreException getPanicException();
// Configuration
public int getCacheSizeUsed();
public void setCacheSize(int mb);
public void setVersionsToKeep(int count);
public void setAutoCommitDelay(int millis);
}Usage Examples:
// Create/open file-based store
MVStore store = MVStore.open("data.mv");
// Create in-memory store
MVStore store = new MVStore.Builder().open();
// Open map
MVMap<String, String> map = store.openMap("users");
// Store data
map.put("user1", "Alice");
map.put("user2", "Bob");
// Commit changes
store.commit();
// Close store
store.close();Builder pattern for configuring MVStore instances.
public static class Builder {
public Builder fileName(String fileName);
public Builder cacheSize(int mb);
public Builder autoCommitDisabled();
public Builder autoCommitBufferSize(int kb);
public Builder compress();
public Builder compressHigh();
public Builder encryptionKey(char[] encryptionKey);
public Builder readOnly();
public Builder cacheConcurrency(int concurrency);
public Builder backgroundExceptionHandler(Thread.UncaughtExceptionHandler handler);
public MVStore open();
}Usage Examples:
// Configure store with builder
MVStore store = new MVStore.Builder()
.fileName("mydata.mv")
.cacheSize(64) // 64 MB cache
.compress() // Enable compression
.autoCommitBufferSize(1024) // 1 MB auto-commit buffer
.open();
// In-memory compressed store
MVStore memStore = new MVStore.Builder()
.compress()
.cacheSize(32)
.open();
// Read-only store
MVStore readOnlyStore = new MVStore.Builder()
.fileName("readonly.mv")
.readOnly()
.open();
// Encrypted store
char[] password = "mySecretPassword".toCharArray();
MVStore encryptedStore = new MVStore.Builder()
.fileName("encrypted.mv")
.encryptionKey(password)
.open();Persistent map implementation with MVCC support.
public class MVMap<K, V> {
// Basic map operations
public V put(K key, V value);
public V get(Object key);
public V remove(Object key);
public boolean containsKey(Object key);
public boolean containsValue(Object value);
public boolean isEmpty();
public long size();
public void clear();
// Bulk operations
public void putAll(Map<? extends K, ? extends V> m);
public Set<K> keySet();
public Collection<V> values();
public Set<Map.Entry<K, V>> entrySet();
// Versioned operations
public V put(K key, V value, boolean tryReplace);
public boolean replace(K key, V oldValue, V newValue);
public V putIfAbsent(K key, V value);
public boolean remove(Object key, Object value);
// Range operations
public K firstKey();
public K lastKey();
public K lowerKey(K key);
public K floorKey(K key);
public K ceilingKey(K key);
public K higherKey(K key);
// Cursor operations
public Cursor<K, V> cursor(K from);
public Cursor<K, V> cursor(K from, K to, boolean includeKey);
// Versioning
public MVMap<K, V> openVersion(long version);
public long getVersion();
// Map information
public String getName();
public DataType getKeyType();
public DataType getValueType();
public boolean isReadOnly();
}Usage Examples:
MVStore store = MVStore.open("data.mv");
MVMap<Integer, String> map = store.openMap("customers");
// Basic operations
map.put(1, "Alice Johnson");
map.put(2, "Bob Smith");
String customer = map.get(1); // "Alice Johnson"
// Conditional operations
String oldValue = map.putIfAbsent(3, "Charlie Brown"); // null if inserted
boolean replaced = map.replace(1, "Alice Johnson", "Alice Williams");
// Range queries
Integer firstId = map.firstKey(); // 1
Integer lastId = map.lastKey(); // 3
// Iteration
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// Cursors for efficient range iteration
Cursor<Integer, String> cursor = map.cursor(2); // Start from key 2
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
store.close();MVStore provides built-in transaction support with MVCC.
// Transaction methods in MVStore
public long getCurrentVersion();
public void rollback();
public void rollbackTo(long version);
// Versioned map access
public MVMap<K, V> openVersion(long version);Usage Examples:
MVStore store = MVStore.open("transactional.mv");
MVMap<String, Integer> accounts = store.openMap("accounts");
// Initial balances
accounts.put("alice", 1000);
accounts.put("bob", 500);
store.commit();
// Start transaction
long version = store.getCurrentVersion();
try {
// Transfer money
int aliceBalance = accounts.get("alice");
int bobBalance = accounts.get("bob");
if (aliceBalance >= 100) {
accounts.put("alice", aliceBalance - 100);
accounts.put("bob", bobBalance + 100);
store.commit(); // Commit transaction
} else {
store.rollbackTo(version); // Rollback on insufficient funds
}
} catch (Exception e) {
store.rollbackTo(version); // Rollback on error
throw e;
}
store.close();// Custom data type configuration
public <K, V> MVMap<K, V> openMap(String name, DataType keyType, DataType valueType);
public static class MapBuilder<M extends MVMap<K, V>, K, V> {
public MapBuilder<M, K, V> keyType(DataType keyType);
public MapBuilder<M, K, V> valueType(DataType valueType);
public M create();
}Available Data Types:
public interface DataType {
// Built-in data types
DataType STRING_TYPE = new StringDataType();
DataType BYTE_ARRAY_TYPE = new ByteArrayDataType();
DataType OBJECT_TYPE = new ObjectDataType();
// Type operations
int compare(Object a, Object b);
int getMemory(Object obj);
void write(WriteBuffer buff, Object obj);
Object read(ByteBuffer buff);
}Usage Examples:
// String keys, Object values
MVMap<String, Object> objectMap = store.openMap("objects",
new StringDataType(), new ObjectDataType());
// Custom serializable objects
MVMap<String, Customer> customerMap = store.openMap("customers",
new StringDataType(), new ObjectDataType());
customerMap.put("cust1", new Customer("Alice", "alice@example.com"));
Customer customer = customerMap.get("cust1");MVStore includes spatial indexing support through R-tree implementation.
public class MVRTreeMap<V> extends MVMap<Spatial, V> {
public static <V> MVRTreeMap<V> create(MVStore store, String name, DataType valueType);
// Spatial queries
public Iterator<V> findIntersectingKeys(Spatial bounds);
public Iterator<V> findContainedKeys(Spatial bounds);
// Spatial operations
public V add(Spatial key, V value);
public boolean remove(Spatial key, V value);
}Usage Examples:
import org.h2.mvstore.rtree.*;
MVStore store = MVStore.open("spatial.mv");
MVRTreeMap<String> rtree = MVRTreeMap.create(store, "locations", new StringDataType());
// Add spatial objects (rectangles defined by min/max x,y coordinates)
rtree.add(new SpatialKey(0, 0, 10, 10), "Location A");
rtree.add(new SpatialKey(5, 5, 15, 15), "Location B");
rtree.add(new SpatialKey(20, 20, 30, 30), "Location C");
// Spatial queries
SpatialKey searchArea = new SpatialKey(0, 0, 12, 12);
Iterator<String> results = rtree.findIntersectingKeys(searchArea);
while (results.hasNext()) {
System.out.println("Found: " + results.next());
}
store.close();For storing large objects that don't fit efficiently in regular maps.
public class StreamStore {
public StreamStore(MVStore store);
// Store large objects
public byte[] put(byte[] data);
public InputStream put(InputStream in) throws IOException;
// Retrieve large objects
public byte[] get(byte[] id);
public InputStream get(byte[] id) throws IOException;
// Remove large objects
public boolean remove(byte[] id);
// Stream information
public long length(byte[] id);
}Usage Examples:
MVStore store = MVStore.open("blobs.mv");
StreamStore streamStore = new StreamStore(store);
// Store large file
File largeFile = new File("large_document.pdf");
try (FileInputStream fis = new FileInputStream(largeFile)) {
InputStream result = streamStore.put(fis);
byte[] id = IOUtils.toByteArray(result); // Get identifier
// Later retrieve the file
try (InputStream retrieved = streamStore.get(id);
FileOutputStream fos = new FileOutputStream("retrieved_document.pdf")) {
IOUtils.copy(retrieved, fos);
}
}
store.close();MVStore store = new MVStore.Builder()
.fileName("performance.mv")
.cacheSize(128) // 128 MB cache
.cacheConcurrency(16) // 16-way concurrent cache
.open();
// Runtime cache adjustments
store.setCacheSize(256); // Increase to 256 MBMVStore store = new MVStore.Builder()
.fileName("autocommit.mv")
.autoCommitBufferSize(2048) // 2 MB buffer before auto-commit
.open();
// Disable auto-commit for batch operations
MVStore batchStore = new MVStore.Builder()
.fileName("batch.mv")
.autoCommitDisabled()
.open();
// Manual commit control
MVMap<String, String> map = batchStore.openMap("data");
for (int i = 0; i < 100000; i++) {
map.put("key" + i, "value" + i);
if (i % 10000 == 0) {
batchStore.commit(); // Periodic commits
}
}
batchStore.commit();// Enable compression for space efficiency
MVStore compressedStore = new MVStore.Builder()
.fileName("compressed.mv")
.compress() // Default compression
.open();
// High compression (slower but smaller files)
MVStore highCompressStore = new MVStore.Builder()
.fileName("high_compress.mv")
.compressHigh()
.open();public class MVStoreException extends RuntimeException {
public int getErrorCode();
public static final int ERROR_WRITING_FAILED = 1;
public static final int ERROR_FILE_CORRUPT = 2;
public static final int ERROR_FILE_LOCKED = 3;
public static final int ERROR_READING_FAILED = 4;
// ... other error codes
}Usage Examples:
try {
MVStore store = MVStore.open("problematic.mv");
MVMap<String, String> map = store.openMap("data");
// Operations that might fail
map.put("key", "value");
store.commit();
} catch (MVStoreException e) {
switch (e.getErrorCode()) {
case MVStoreException.ERROR_FILE_LOCKED:
System.err.println("Database file is locked by another process");
break;
case MVStoreException.ERROR_FILE_CORRUPT:
System.err.println("Database file is corrupted");
break;
case MVStoreException.ERROR_WRITING_FAILED:
System.err.println("Failed to write to database file");
break;
default:
System.err.println("MVStore error: " + e.getMessage());
}
}MVStore store = MVStore.open("recovery.mv");
// Check for panic state
MVStoreException panicException = store.getPanicException();
if (panicException != null) {
System.err.println("Store is in panic mode: " + panicException.getMessage());
// Handle recovery or close immediately
store.closeImmediately();
return;
}
// Normal operations
MVMap<String, String> map = store.openMap("data");
// ... use map
store.close();public class MVStoreManager implements AutoCloseable {
private final MVStore store;
private final Map<String, MVMap<?, ?>> openMaps;
public MVStoreManager(String fileName) {
this.store = MVStore.open(fileName);
this.openMaps = new ConcurrentHashMap<>();
}
@SuppressWarnings("unchecked")
public <K, V> MVMap<K, V> getMap(String name, DataType keyType, DataType valueType) {
return (MVMap<K, V>) openMaps.computeIfAbsent(name,
n -> store.openMap(n, keyType, valueType));
}
public void commit() {
store.commit();
}
@Override
public void close() {
try {
store.close();
} catch (Exception e) {
System.err.println("Error closing MVStore: " + e.getMessage());
}
}
}
// Usage with try-with-resources
try (MVStoreManager manager = new MVStoreManager("app.mv")) {
MVMap<String, String> config = manager.getMap("config",
new StringDataType(), new StringDataType());
config.put("app.version", "1.0.0");
config.put("app.name", "MyApplication");
manager.commit();
} // Automatically closes storepublic class ConcurrentMVStore {
private final MVStore store;
private final MVMap<String, String> data;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public ConcurrentMVStore(String fileName) {
this.store = MVStore.open(fileName);
this.data = store.openMap("data");
}
public String get(String key) {
lock.readLock().lock();
try {
return data.get(key);
} finally {
lock.readLock().unlock();
}
}
public void put(String key, String value) {
lock.writeLock().lock();
try {
data.put(key, value);
store.commit();
} finally {
lock.writeLock().unlock();
}
}
public void close() {
lock.writeLock().lock();
try {
store.close();
} finally {
lock.writeLock().unlock();
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-h2database--h2