mvstore.html 22.1 KB
Newer Older
1 2
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Thomas Mueller's avatar
Thomas Mueller committed
3
Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License, Version 1.0,
4 5 6 7 8 9
and under the Eclipse Public License, Version 1.0
(http://h2database.com/html/license.html).
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
10
MVStore
11 12 13 14 15 16 17 18 19 20 21 22
</title><link rel="stylesheet" type="text/css" href="stylesheet.css" />
<!-- [search] { -->
<script type="text/javascript" src="navigation.js"></script>
</head><body onload="frameMe();">
<table class="content"><tr class="content"><td class="content"><div class="contentDiv">
<!-- } -->

<h1>MVStore</h1>
<a href="#overview">
    Overview</a><br />
<a href="#example_code">
    Example Code</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
23 24 25 26
<a href="#store_builder">
    Store Builder</a><br />
<a href="#r_tree">
    R-Tree</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
27

28 29
<a href="#features">
    Features</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
30 31 32 33 34 35 36 37 38
<a href="#maps">- Maps</a><br />
<a href="#versions">- Versions</a><br />
<a href="#transactions">- Transactions</a><br />
<a href="#inMemory">- In-Memory Performance and Usage</a><br />
<a href="#dataTypes">- Pluggable Data Types</a><br />
<a href="#blob">- BLOB Support</a><br />
<a href="#pluggableMap">- R-Tree and Pluggable Map Implementations</a><br />
<a href="#caching">- Concurrent Operations and Caching</a><br />
<a href="#logStructured">- Log Structured Storage</a><br />
39
<a href="#offHeap">- Off-Heap and Pluggable Storage</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
40 41 42 43
<a href="#fileSystem">- File System Abstraction, File Locking and Online Backup</a><br />
<a href="#encryption">- Encrypted Files</a><br />
<a href="#tools">- Tools</a><br />
<a href="#exceptionHandling">- Exception Handling</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
44
<a href="#storageEngine">- Storage Engine for H2</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
45

46 47 48 49 50 51 52 53
<a href="#differences">
    Similar Projects and Differences to Other Storage Engines</a><br />
<a href="#current_state">
    Current State</a><br />
<a href="#requirements">
    Requirements</a><br />

<h2 id="overview">Overview</h2>
54 55
<p>
The MVStore is work in progress, and is planned to be the next storage subsystem of H2.
Thomas Mueller's avatar
Thomas Mueller committed
56
But it can also be used directly within an application, without using JDBC or SQL.
57
</p>
58
<ul><li>MVStore stands for "multi-version store".
Thomas Mueller's avatar
Thomas Mueller committed
59
</li><li>Each store contains a number of maps that can be accessed using the <code>java.util.Map</code> interface.
60
</li><li>Both file-based persistence and in-memory operation are supported.
61 62
</li><li>It is intended to be fast, simple to use, and small.
</li><li>Old versions of the data can be read concurrently with all other operations.
63
</li><li>Transaction are supported (including concurrent transactions and 2-phase commit).
Thomas Mueller's avatar
Thomas Mueller committed
64
</li><li>The tool is very modular.
Thomas Mueller's avatar
Thomas Mueller committed
65
    It supports pluggable data types and serialization,
Thomas Mueller's avatar
Thomas Mueller committed
66
    pluggable storage (to a file, to off-heap memory),
Thomas Mueller's avatar
Thomas Mueller committed
67
    pluggable map implementations (B-tree, R-tree, concurrent B-tree currently),
Thomas Mueller's avatar
Thomas Mueller committed
68
    BLOB storage,
69
    and a file system abstraction to support encrypted files and zip files.
70 71 72
</li></ul>

<h2 id="example_code">Example Code</h2>
73
<p>
Thomas Mueller's avatar
Thomas Mueller committed
74
The following sample code show how to use the tool:
75
</p>
76
<pre>
Thomas Mueller's avatar
Thomas Mueller committed
77 78
import org.h2.mvstore.*;

79 80 81
// open the store (in-memory if fileName is null)
MVStore s = MVStore.open(fileName);

82
// create/get the map named "data"
83
MVMap&lt;Integer, String&gt; map = s.openMap("data");
84

Thomas Mueller's avatar
Thomas Mueller committed
85 86 87
// add and read some data
map.put(1, "Hello World");
System.out.println(map.get(1));
88

Thomas Mueller's avatar
Thomas Mueller committed
89
// close the store (this will persist changes)
90 91 92
s.close();
</pre>

Thomas Mueller's avatar
Thomas Mueller committed
93
<h2 id="store_builder">Store Builder</h2>
94
<p>
95
The <code>MVStore.Builder</code> provides a fluid interface
Thomas Mueller's avatar
Thomas Mueller committed
96
to build a store if more complex configuration options are used.
Thomas Mueller's avatar
Thomas Mueller committed
97
Example usage:
98 99
</p>
<pre>
100
MVStore s = new MVStore.Builder().
Thomas Mueller's avatar
Thomas Mueller committed
101
    fileName(fileName).
Thomas Mueller's avatar
Thomas Mueller committed
102 103
    encryptionKey("007".toCharArray()).
    compressData().
104 105
    open();
</pre>
Thomas Mueller's avatar
Thomas Mueller committed
106 107 108 109 110 111
<p>
The list of available options is:
</p>
<ul><li>autoCommitBufferSize: the size of the write buffer.
</li><li>autoCommitDisabled: to disable auto-commit.
</li><li>backgroundExceptionHandler: specify a handler for
Thomas Mueller's avatar
Thomas Mueller committed
112 113
    exceptions that could occur while writing in the background.
</li><li>cacheSize: the cache size in MB.
Thomas Mueller's avatar
Thomas Mueller committed
114 115 116
</li><li>compressData: compress the data when storing.
</li><li>encryptionKey: the encryption key for file encryption.
</li><li>fileName: the name of the file, for file based stores.
Thomas Mueller's avatar
Thomas Mueller committed
117
</li><li>fileStore: the storage implementation to use.
Thomas Mueller's avatar
Thomas Mueller committed
118
</li><li>pageSplitSize: the point where pages are split.
Thomas Mueller's avatar
Thomas Mueller committed
119 120
</li><li>readOnly: open the file in read-only mode.
</li></ul>
121

Thomas Mueller's avatar
Thomas Mueller committed
122
<h2 id="r_tree">R-Tree</h2>
123 124
<p>
The <code>MVRTreeMap</code> is an R-tree implementation
125
that supports fast spatial queries. It can be used as follows:
126 127 128 129 130
</p>
<pre>
// create an in-memory store
MVStore s = MVStore.open(null);

131
// open an R-tree map
132 133
MVRTreeMap&lt;String&gt; r = s.openMap("data",
        new MVRTreeMap.Builder&lt;String&gt;());
134 135 136 137 138 139 140 141

// add two key-value pairs
// the first value is the key id (to make the key unique)
// then the min x, max x, min y, max y
r.add(new SpatialKey(0, -3f, -2f, 2f, 3f), "left");
r.add(new SpatialKey(1, 3f, 4f, 4f, 5f), "right");

// iterate over the intersecting keys
142
Iterator&lt;SpatialKey&gt; it =
143 144 145 146 147 148 149
        r.findIntersectingKeys(new SpatialKey(0, 0f, 9f, 3f, 6f));
for (SpatialKey k; it.hasNext();) {
    k = it.next();
    System.out.println(k + ": " + r.get(k));
}
s.close();
</pre>
Thomas Mueller's avatar
Thomas Mueller committed
150 151
<p>
The default number of dimensions is 2. To use a different number of dimensions,
Thomas Mueller's avatar
Thomas Mueller committed
152
call <code>new MVRTreeMap.Builder&lt;String&gt;().dimensions(3)</code>.
Thomas Mueller's avatar
Thomas Mueller committed
153 154
The minimum number of dimensions is 1, the maximum is 255.
</p>
155 156 157

<h2 id="features">Features</h2>

158
<h3 id="maps">Maps</h3>
159
<p>
Thomas Mueller's avatar
Thomas Mueller committed
160
Each store contains a set of named maps.
161
A map is sorted by key, and supports the common lookup operations,
162 163
including access to the first and last key, iterate over some or all keys, and so on.
</p><p>
Thomas Mueller's avatar
Thomas Mueller committed
164
Also supported, and very uncommon for maps, is fast index lookup:
Thomas Mueller's avatar
Thomas Mueller committed
165 166 167 168
the entries of the map can be be efficiently accessed like a random-access list
(get the entry at the given index), and the index of a key can be calculated efficiently.
That also means getting the median of two keys is very fast,
and a range of keys can be counted very quickly.
169 170
The iterator supports fast skipping.
This is possible because internally, each map is organized in the form of a counted B+-tree.
171
</p><p>
172
In database terms, a map can be used like a table, where the key of the map is the primary key of the table,
173
and the value is the row. A map can also represent an index, where the key of the map is the key
Thomas Mueller's avatar
Thomas Mueller committed
174
of the index, and the value of the map is the primary key of the table (for non-unique indexes,
175
the key of the map must also contain the primary key).
176 177
</p>

178
<h3 id="versions">Versions</h3>
179 180
<p>
A version is a snapshot of all the data of all maps at a given point in time.
Thomas Mueller's avatar
Thomas Mueller committed
181
Creating a snapshot is fast: only those pages that are changed after a snapshot are copied.
Thomas Mueller's avatar
Thomas Mueller committed
182
This behavior is also called COW (copy on write).
Thomas Mueller's avatar
Thomas Mueller committed
183
Rollback to an old version is supported.
Thomas Mueller's avatar
Thomas Mueller committed
184
Old versions are readable until old data is purged.
Thomas Mueller's avatar
Thomas Mueller committed
185 186 187
</p><p>
The following sample code show how to create a store, open a map, add some data,
and access the current and an old version:
188
</p>
Thomas Mueller's avatar
Thomas Mueller committed
189 190 191 192 193 194 195 196 197 198 199 200
<pre>
// create/get the map named "data"
MVMap&lt;Integer, String&gt; map = s.openMap("data");

// add some data
map.put(1, "Hello");
map.put(2, "World");

// get the current version, for later use
long oldVersion = s.getCurrentVersion();

// from now on, the old version is read-only
Thomas Mueller's avatar
Thomas Mueller committed
201
s.commit();
Thomas Mueller's avatar
Thomas Mueller committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221

// more changes, in the new version
// changes can be rolled back if required
// changes always go into "head" (the newest version)
map.put(1, "Hi");
map.remove(2);

// access the old data (before incrementVersion)
MVMap&lt;Integer, String&gt; oldMap =
        map.openVersion(oldVersion);

// print the old version (can be done
// concurrently with further modifications)
// this will print "Hello" and "World":
System.out.println(oldMap.get(1));
System.out.println(oldMap.get(2));

// print the newest version ("Hi")
System.out.println(map.get(1));
</pre>
222

223 224 225 226
<h3 id="transactions">Transactions</h3>
<p>
To support multiple concurrent open transactions, a transaction utility is included,
the <code>TransactionStore</code>.
Thomas Mueller's avatar
Thomas Mueller committed
227 228 229 230 231 232 233 234 235
The tool supports PostgreSQL style "read committed" transaction isolation
with savepoints, two-phase commit, and other features typically available in a database.
There is no limit on the size of a transaction
(the log is written to disk for large or long running transactions).
</p><p>
Internally, this utility stores the old versions of changed entries in a separate map, similar to a transaction log
(except that entries of a closed transaction are removed,
and the log is usually not stored for short transactions).
For common use cases, the storage overhead of this utility is very small compared to the overhead of a regular transaction log.
236 237 238
</p>

<h3 id="inMemory">In-Memory Performance and Usage</h3>
239
<p>
Thomas Mueller's avatar
Thomas Mueller committed
240 241
Performance of in-memory operations is comparable with <code>java.util.TreeMap</code>,
but usually slower than <code>java.util.HashMap</code>.
242 243
</p><p>
The memory overhead for large maps is slightly better than for the regular
244
map implementations, but there is a higher overhead per map.
Thomas Mueller's avatar
Thomas Mueller committed
245
For maps with less than about 25 entries, the regular map implementations need less memory.
Thomas Mueller's avatar
Thomas Mueller committed
246 247 248 249 250 251
</p><p>
If no file name is specified, the store operates purely in memory.
Except for persisting data, all features are supported in this mode
(multi-versioning, index lookup, R-tree and so on).
If a file name is specified, all operations occur in memory (with the same
performance characteristics) until data is persisted.
Thomas Mueller's avatar
Thomas Mueller committed
252
</p><p>
Thomas Mueller's avatar
Thomas Mueller committed
253 254
As in all map implementations, keys need to be immutable, that means
changing the key object after an entry has been added is not allowed.
Thomas Mueller's avatar
Thomas Mueller committed
255
If a file name is specified, the value may also not be changed after
Thomas Mueller's avatar
Thomas Mueller committed
256 257
adding an entry, because it might be serialized 
(which could happen at any time when autocommit is enabled).
258 259
</p>

260
<h3 id="dataTypes">Pluggable Data Types</h3>
261
<p>
262
Serialization is pluggable. The default serialization currently supports many common data types,
263 264
and uses Java serialization for other objects. The following classes are currently directly supported:
<code>Boolean, Byte, Short, Character, Integer, Long, Float, Double, BigInteger, BigDecimal,
Thomas Mueller's avatar
Thomas Mueller committed
265
String, UUID, Date</code> and arrays (both primitive arrays and object arrays).
266 267
</p><p>
Parameterized data types are supported
Thomas Mueller's avatar
Thomas Mueller committed
268
(for example one could build a string data type that limits the length).
269
</p><p>
270
The storage engine itself does not have any length limits, so that keys, values,
271 272 273 274 275
pages, and chunks can be very big (as big as fits in memory).
Also, there is no inherent limit to the number of maps and chunks.
Due to using a log structured storage, there is no special case handling for large keys or pages.
</p>

276
<h3 id="blob">BLOB Support</h3>
277
<p>
278
There is a mechanism that stores large binary objects by splitting them into smaller blocks.
279 280
This allows to store objects that don't fit in memory.
Streaming as well as random access reads on such objects are supported.
Thomas Mueller's avatar
Thomas Mueller committed
281
This tool is written on top of the store, using only the map interface.
282 283
</p>

284
<h3 id="pluggableMap">R-Tree and Pluggable Map Implementations</h3>
285 286
<p>
The map implementation is pluggable.
Thomas Mueller's avatar
Thomas Mueller committed
287
In addition to the default <code>MVMap</code> (multi-version map),
Thomas Mueller's avatar
Thomas Mueller committed
288 289
there is a map that supports concurrent write operations,
and a multi-version R-tree map implementation for spatial operations.
290 291
</p>

292
<h3 id="caching">Concurrent Operations and Caching</h3>
293
<p>
294
The default map implementation supports concurrent reads on old versions of the data.
295
All such read operations can occur in parallel. Concurrent reads from the page cache,
296
as well as concurrent reads from the file system are supported.
Thomas Mueller's avatar
Thomas Mueller committed
297 298
Writing changes to the file can occur concurrently to modifying the data,
as writing operates on a snapshot.
299
</p><p>
300
Caching is done on the page level.
301
The page cache is a concurrent LIRS cache, which should be resistant against scan operations.
302
</p><p>
303
The default map implementation does not support concurrent modification
304
operations on a map (the same as <code>HashMap</code> and <code>TreeMap</code>).
305
Similar to those classes, the map tries to detect concurrent modification.
306
</p><p>
307
With the <code>MVMapConcurrent</code> implementation,
308 309
read operations even on the newest version can happen concurrently with all other
operations, without risk of corruption.
310
This comes with slightly reduced speed in single threaded mode,
311 312 313 314 315
the same as with other <code>ConcurrentHashMap</code> implementations.
Write operations first read the relevant area from disk to memory
(this can happen concurrently), and only then modify the data. The in-memory part of write
operations is synchronized.
</p><p>
316 317
For fully scalable concurrent write operations to a map (in-memory and to disk),
the map could be split into multiple maps in different stores ('sharding').
318
The plan is to add such a mechanism later when needed.
319 320
</p>

321
<h3 id="logStructured">Log Structured Storage</h3>
Thomas Mueller's avatar
Thomas Mueller committed
322
<p>
Thomas Mueller's avatar
Thomas Mueller committed
323
Internally, changes are buffered in memory, and once enough changes have accumulated,
Thomas Mueller's avatar
Thomas Mueller committed
324
they are written in one continuous disk write operation.
Thomas Mueller's avatar
Thomas Mueller committed
325 326 327
Compared to traditional database storage engines,
this should improve write performance for file systems and storage systems
that do not efficiently support small random writes, such as Btrfs, as well as SSDs.
Thomas Mueller's avatar
Thomas Mueller committed
328
(According to a test, write throughput of a common SSD increases with write block size,
329
until a block size of 2 MB, and then does not further increase.)
Thomas Mueller's avatar
Thomas Mueller committed
330 331 332
By default, changes are automatically written when more than a number of pages are modified, 
and once every second in a background thread, even if only little data was changed.
Changes can also be written explicitly by calling <code>commit()</code>.
Thomas Mueller's avatar
Thomas Mueller committed
333 334
</p><p>
When storing, all changed pages are serialized,
335
optionally compressed using the LZF algorithm,
Thomas Mueller's avatar
Thomas Mueller committed
336 337 338 339
and written sequentially to a free area of the file.
Each such change set is called a chunk.
All parent pages of the changed B-trees are stored in this chunk as well,
so that each chunk also contains the root of each changed map
Thomas Mueller's avatar
Thomas Mueller committed
340
(which is the entry point for reading this version of the data).
Thomas Mueller's avatar
Thomas Mueller committed
341
There is no separate index: all data is stored as a list of pages.
Thomas Mueller's avatar
Thomas Mueller committed
342
Per store, there is one additional map that contains the metadata (the list of
Thomas Mueller's avatar
Thomas Mueller committed
343 344
maps, where the root page of each map is stored, and the list of chunks).
</p><p>
345 346 347
There are usually two write operations per chunk:
one to store the chunk data (the pages), and one to update the file header (so it points to the latest chunk).
If the chunk is appended at the end of the file, the file header is only written at the end of the chunk.
Thomas Mueller's avatar
Thomas Mueller committed
348
There is no transaction log, no undo log,
Thomas Mueller's avatar
Thomas Mueller committed
349
and there are no in-place updates (however, unused chunks are overwritten by default).
Thomas Mueller's avatar
Thomas Mueller committed
350
</p><p>
351
Old data is kept for at least 45 seconds (configurable),
Thomas Mueller's avatar
Thomas Mueller committed
352 353
so that there are no explicit sync operations required to guarantee data consistency.
An application can also sync explicitly when needed.
Thomas Mueller's avatar
Thomas Mueller committed
354
To reuse disk space, the chunks with the lowest amount of live data are compacted
Thomas Mueller's avatar
Thomas Mueller committed
355
(the live data is stored again in the next chunk).
Thomas Mueller's avatar
Thomas Mueller committed
356 357
To improve data locality and disk space usage, the plan is to automatically defragment and compact data.
</p><p>
Thomas Mueller's avatar
Thomas Mueller committed
358
Compared to traditional storage engines (that use a transaction log, undo log, and main storage area),
Thomas Mueller's avatar
Thomas Mueller committed
359 360 361 362 363 364 365
the log structured storage is simpler, more flexible, and typically needs less disk operations per change,
as data is only written once instead of twice or 3 times, and because the B-tree pages are
always full (they are stored next to each other) and can be easily compressed.
But temporarily, disk space usage might actually be a bit higher than for a regular database,
as disk space is not immediately re-used (there are no in-place updates).
</p>

366 367 368 369 370 371 372 373 374 375
<h3 id="offHeap">Off-Heap and Pluggable Storage</h3>
<p>
Storage is pluggable. The default storage is to a single file (unless pure in-memory operation is used).
</p>
<p>
An off-heap storage implementation is available. This storage keeps the data in the off-heap memory,
meaning outside of the regular garbage collected heap. This allows to use very large in-memory
stores without having to increase the JVM heap (which would increase Java garbage collection
pauses a lot). Memory is allocated using <code>ByteBuffer.allocateDirect</code>.
One chunk is allocated at a time (each chunk is usually a few MB large), so that
376
allocation cost is low. To use the off-heap storage, call:
377
</p>
378 379 380 381 382
<pre>
OffHeapStore offHeap = new OffHeapStore();
MVStore s = new MVStore.Builder().
        fileStore(offHeap).open();
</pre>
383

384
<h3 id="fileSystem">File System Abstraction, File Locking and Online Backup</h3>
385 386
<p>
The file system is pluggable (the same file system abstraction is used as H2 uses).
387
The file can be encrypted using a encrypting file system wrapper.
Thomas Mueller's avatar
Thomas Mueller committed
388
Other file system implementations support reading from a compressed zip or jar file.
389
The file system abstraction closely matches the Java 7 file system API.
390 391 392 393 394 395 396 397
</p>
<p>
Each store may only be opened once within a JVM.
When opening a store, the file is locked in exclusive mode, so that
the file can only be changed from within one process.
Files can be opened in read-only mode, in which case a shared lock is used.
</p>
<p>
398
The persisted data can be backed up at any time,
399
even during write operations (online backup).
400
To do that, automatic disk space reuse needs to be first disabled, so that
401
new data is always appended at the end of the file.
402
Then, the file can be copied (the file handle is available to the application).
403
It is recommended to use the utility class <code>FileChannelInputStream</code> to do this.
Thomas Mueller's avatar
Thomas Mueller committed
404
For encrypted databases, both the encrypted (raw) file content,
405
as well as the clear text content, can be backed up.
406 407
</p>

408
<h3 id="encryption">Encrypted Files</h3>
409
<p>
410
File encryption ensures the data can only be read with the correct password.
411 412 413 414 415 416 417 418 419
Data can be encrypted as follows:
</p>
<pre>
MVStore s = new MVStore.Builder().
    fileName(fileName).
    encryptionKey("007".toCharArray()).
    open();
</pre>
<p>
420
</p><p>
Thomas Mueller's avatar
Thomas Mueller committed
421
The following algorithms and settings are used:
422
</p>
423
<ul><li>The password char array is cleared after use,
424 425
    to reduce the risk that the password is stolen
    even if the attacker has access to the main memory.
426
</li><li>The password is hashed according to the PBKDF2 standard,
427
    using the SHA-256 hash algorithm.
Thomas Mueller's avatar
Thomas Mueller committed
428
</li><li>The length of the salt is 64 bits,
429
    so that an attacker can not use a pre-calculated password hash table (rainbow table).
Thomas Mueller's avatar
Thomas Mueller committed
430 431 432 433 434 435 436
    It is generated using a cryptographically secure random number generator.
</li><li>To speed up opening an encrypted stores on Android,
    the number of PBKDF2 iterations is 10.
    The higher the value, the better the protection against brute-force password cracking attacks,
    but the slower is opening a file.
</li><li>The file itself is encrypted using the standardized disk encryption mode XTS-AES.
    Only little more than one AES-128 round per block is needed.
437
</li></ul>
438

439
<h3 id="tools">Tools</h3>
440 441 442
<p>
There is a tool (<code>MVStoreTool</code>) to dump the contents of a file.
</p>
443

444
<h3 id="exceptionHandling">Exception Handling</h3>
445
<p>
446 447
This tool does not throw checked exceptions.
Instead, unchecked exceptions are thrown if needed.
448 449 450
The error message always contains the version of the tool.
The following exceptions can occur:
</p>
451
<ul><li><code>IllegalStateException</code> if a map was already closed or
452 453 454
    an IO exception occurred, for example if the file was locked, is already closed,
    could not be opened or closed, if reading or writing failed,
    if the file is corrupt, or if there is an internal error in the tool.
Thomas Mueller's avatar
Thomas Mueller committed
455 456
    For such exceptions, an error code is added to the exception
    so that the application can distinguish between different error cases.
457 458
</li><li><code>IllegalArgumentException</code> if a method was called with an illegal argument.
</li><li><code>UnsupportedOperationException</code> if a method was called that is not supported,
Thomas Mueller's avatar
Thomas Mueller committed
459 460
    for example trying to modify a read-only map.
</li><li><code>ConcurrentModificationException</code> if a map is modified concurrently.
461
</li></ul>
462

Thomas Mueller's avatar
Thomas Mueller committed
463
<h3 id="storageEngine">Storage Engine for H2</h3>
Thomas Mueller's avatar
Thomas Mueller committed
464 465 466 467
<p>
The plan is to use the MVStore as the default storage engine for the H2 database
in the future (supporting SQL, JDBC, transactions, MVCC, and so on).
This is work in progress. To try it out, append
Thomas Mueller's avatar
Thomas Mueller committed
468
<code>;MV_STORE=TRUE</code>
Thomas Mueller's avatar
Thomas Mueller committed
469 470
to the database URL. In general, functionality and performance should be
similar than the current default storage engine (the page store).
471
There are a few features that have not been implemented yet or are not complete,
Thomas Mueller's avatar
Thomas Mueller committed
472
for example there is still a file named <code>.h2.db</code>,
473 474
and the <code>.lock.db</code> file is still used to lock a database
(long term, the plan is to no longer use those files).
Thomas Mueller's avatar
Thomas Mueller committed
475 476
</p>

477 478
<h2 id="differences">Similar Projects and Differences to Other Storage Engines</h2>
<p>
479
Unlike similar storage engines like LevelDB and Kyoto Cabinet,
Thomas Mueller's avatar
Thomas Mueller committed
480 481
the MVStore is written in Java
and can easily be embedded in a Java and Android application.
482
</p><p>
483
The MVStore is somewhat similar to the Berkeley DB Java Edition
Thomas Mueller's avatar
Thomas Mueller committed
484
because it is also written in Java,
485
and is also a log structured storage, but the H2 license is more liberal.
486
</p><p>
Thomas Mueller's avatar
Thomas Mueller committed
487 488 489 490
Like SQLite 3, the MVStore keeps all data in one file.
Unlike SQLite 3, the MVStore uses is a log structured storage.
The plan is to make the MVStore both easier to use as well as faster than SQLite 3.
In a recent (very simple) test, the MVStore was about twice as fast as SQLite 3 on Android.
491 492
</p><p>
The API of the MVStore is similar to MapDB (previously known as JDBM) from Jan Kotek,
Thomas Mueller's avatar
Thomas Mueller committed
493
and some code is shared between MVStore and MapDB.
494
However, unlike MapDB, the MVStore uses is a log structured storage.
Thomas Mueller's avatar
Thomas Mueller committed
495
The MVStore does not have a record size limit.
496 497 498 499
</p>

<h2 id="current_state">Current State</h2>
<p>
Thomas Mueller's avatar
Thomas Mueller committed
500 501
The code is still experimental at this stage.
The API as well as the behavior may partially change.
502 503 504 505 506
Features may be added and removed (even thought the main features will stay).
</p>

<h2 id="requirements">Requirements</h2>
<p>
Thomas Mueller's avatar
Thomas Mueller committed
507 508 509
The MVStore is included in the latest H2 jar file.
</p><p>
There are no special requirements to use it.
Thomas Mueller's avatar
Thomas Mueller committed
510
The MVStore should run on any JVM as well as on Android.
511 512 513 514 515 516 517 518
</p><p>
To build just the MVStore (without the database engine), run:
</p>
<pre>
./build.sh jarMVStore
</pre>
<p>
This will create the file <code>bin/h2mvstore-${version}.jar</code> (about 130 KB).
519 520 521
</p>

<!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html>