Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
871b0a8e
提交
871b0a8e
authored
11月 28, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map: prepare initial release
上级
f2afe926
隐藏空白字符变更
内嵌
并排
正在显示
26 个修改的文件
包含
474 行增加
和
316 行删除
+474
-316
fragments.html
h2/src/docsrc/html/fragments.html
+1
-0
mvstore.html
h2/src/docsrc/html/mvstore.html
+95
-28
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+114
-114
IntegerType.java
h2/src/test/org/h2/test/store/IntegerType.java
+0
-45
RowType.java
h2/src/test/org/h2/test/store/RowType.java
+7
-5
SampleTypeFactory.java
h2/src/test/org/h2/test/store/SampleTypeFactory.java
+41
-0
SequenceMap.java
h2/src/test/org/h2/test/store/SequenceMap.java
+9
-9
TestConcurrent.java
h2/src/test/org/h2/test/store/TestConcurrent.java
+3
-2
TestMVRTree.java
h2/src/test/org/h2/test/store/TestMVRTree.java
+33
-17
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+48
-49
TestObjectType.java
h2/src/test/org/h2/test/store/TestObjectType.java
+1
-0
MVMap.java
h2/src/tools/org/h2/dev/store/btree/MVMap.java
+9
-4
MVStore.java
h2/src/tools/org/h2/dev/store/btree/MVStore.java
+40
-21
MVStoreBuilder.java
h2/src/tools/org/h2/dev/store/btree/MVStoreBuilder.java
+1
-0
MVStoreTool.java
h2/src/tools/org/h2/dev/store/btree/MVStoreTool.java
+1
-1
Page.java
h2/src/tools/org/h2/dev/store/btree/Page.java
+1
-0
CacheLongKeyLIRS.java
h2/src/tools/org/h2/dev/store/cache/CacheLongKeyLIRS.java
+1
-1
FilePathCache.java
h2/src/tools/org/h2/dev/store/cache/FilePathCache.java
+1
-2
MVRTreeMap.java
h2/src/tools/org/h2/dev/store/rtree/MVRTreeMap.java
+5
-5
SpatialKey.java
h2/src/tools/org/h2/dev/store/rtree/SpatialKey.java
+1
-1
SpatialType.java
h2/src/tools/org/h2/dev/store/rtree/SpatialType.java
+2
-2
DataType.java
h2/src/tools/org/h2/dev/store/type/DataType.java
+4
-1
DataTypeFactory.java
h2/src/tools/org/h2/dev/store/type/DataTypeFactory.java
+14
-5
ObjectType.java
h2/src/tools/org/h2/dev/store/type/ObjectType.java
+2
-3
ObjectTypeFactory.java
h2/src/tools/org/h2/dev/store/type/ObjectTypeFactory.java
+38
-0
StringType.java
h2/src/tools/org/h2/dev/store/type/StringType.java
+2
-1
没有找到文件。
h2/src/docsrc/html/fragments.html
浏览文件 @
871b0a8e
...
...
@@ -94,6 +94,7 @@ translate -->
<a
href=
"build.html"
>
Build
</a><br
/>
<a
href=
"links.html"
>
Links
</a><br
/>
<a
href=
"jaqu.html"
>
JaQu
</a><br
/>
<a
href=
"mvstore.html"
>
MVStore
</a><br
/>
<br
/>
</div>
...
...
h2/src/docsrc/html/mvstore.html
浏览文件 @
871b0a8e
...
...
@@ -7,7 +7,7 @@ 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>
JaQu
MVStore
</title><link
rel=
"stylesheet"
type=
"text/css"
href=
"stylesheet.css"
/>
<!-- [search] { -->
<script
type=
"text/javascript"
src=
"navigation.js"
></script>
...
...
@@ -34,33 +34,38 @@ JaQu
Future Plans
</a><br
/>
<h2
id=
"overview"
>
Overview
</h2>
<p>
The MVStore is work in progress, and is planned to be the next storage subsystem of H2.
</p>
<ul><li>
MVStore stands for multi-version store.
</li><li>
Each store contains a number of maps (using the
<code>
java.util.Map
</code>
interface).
</li><li>
The data can be persisted to disk (like a key-value store or a database).
</li><li>
Fully in-memory operation is supported.
</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.
</li><li>
Transaction are supported (currently only one transaction
can be open at any
time).
</li><li>
Transaction are supported (currently only one transaction
at a
time).
</li><li>
Transactions (even if they are persisted) can be rolled back.
</li><li>
The tool is very modular. It supports pluggable data types / serialization,
pluggable map implementations (B-tree and R-tree currently), BLOB storage,
and a file system abstraction that supports encryption and compressed
read-only files.
and a file system abstraction to support encryption and compressed read-only files.
</li></ul>
<h2
id=
"example_code"
>
Example Code
</h2>
<h3>
Map Operations and Versioning
</h3>
<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.
</p>
<pre>
// open the store (in-memory if fileName is null)
MVStore s = MVStore.open(fileName);
// create/get the map "data"
// the String.class, String.class will be optional later
MVMap
<String
,
String
>
map = s.openMap("data",
String.class, String.class);
// create/get the map named "data"
MVMap
<Integer
,
String
>
map = s.openMap("data");
// add some data
map.put(
"1"
, "Hello");
map.put(
"2"
, "World");
map.put(
1
, "Hello");
map.put(
2
, "World");
// get the current version, for later use
long oldVersion = s.getCurrentVersion();
...
...
@@ -71,11 +76,11 @@ s.incrementVersion();
// 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"
);
map.put(
1
, "Hi");
map.remove(
2
);
// access the old data (before incrementVersion)
MVMap
<
String
,
String
>
oldMap =
MVMap
<
Integer
,
String
>
oldMap =
map.openVersion(oldVersion);
// store the newest data to disk
...
...
@@ -84,16 +89,62 @@ s.store();
// print the old version (can be done
// concurrently with further modifications)
// this will print Hello World
System.out.println(oldMap.get("1"));
System.out.println(oldMap.get("2"));
System.out.println(oldMap.get(1));
System.out.println(oldMap.get(2));
oldMap.close();
// print the newest version ("Hi")
System.out.println(map.get(
"1"
));
System.out.println(map.get(
1
));
// close the store - this doesn't write to disk
s.close();
</pre>
<h3>
Store Builder
</h3>
<p>
The
<code>
MVStoreBuilder
</code>
provides a fluid interface
to build a store if more complex configuration options are used.
</p>
<pre>
MVStore s = MVStoreBuilder.
fileBased(fileName).
cacheSizeMB(10).
readOnly().
open();
</pre>
<h3>
R-Tree
</h3>
<p>
The
<code>
MVRTreeMap
</code>
is an R-tree implementation
that supports fast spatial queries.
</p>
<pre>
// create an in-memory store
MVStore s = MVStore.open(null);
// create an R-tree map
// the key has 2 dimensions, the value is a string
MVRTreeMap
<String>
r = MVRTreeMap.create(2, new ObjectType());
// open the map
r = s.openMap("data", r);
// 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
Iterator
<SpatialKey>
it =
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>
<h2
id=
"features"
>
Features
</h2>
...
...
@@ -103,13 +154,18 @@ Each store supports a set of named maps.
A map is sorted by key, and supports the common lookup operations,
including access to the first and last key, iterate over some or all keys, and so on.
</p><p>
Also supported, and unusual for maps, is fast index lookup, as if the map would be a list
(get the key at the given index, get the index of a certain key), and fast skipping within an iterator.
Internally, each map is organized in the form of a counted B+-tree.
Also supported, and very uncommon for maps, is fast index lookup.
The keys of the map can be accessed like a list
(get the key at the given index, get the index of a certain key).
That means getting the median of two keys is trivial,
and it allows to very quickly count ranges.
The iterator supports fast skipping.
This is possible because internally, each map is organized in the form of a counted B+-tree.
</p><p>
In database terms, a map can be a table, where the key of the map is the primary key of the table,
In database terms, a map can be
used like
a table, where the key of the map is the primary key of the table,
and the value is the row. A map can also represent an index, where the key of the map is the key
of the index, and the value of the map is the primary key of the table.
of the index, and the value of the map is the primary key of the table (for non-unique indexes
the key of the map must also contain the primary key).
</p>
<h3>
Versions / Transactions
</h3>
...
...
@@ -189,9 +245,11 @@ use less memory on average.
<h3>
Pluggable Data Types
</h3>
<p>
Serialization is pluggable. The default serialization currently only supports string values and keys,
but there is a sample plugin that supports many common data types,
and uses Java serialization for other objects.
Serialization is pluggable. The default serialization currently supports many common data types,
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,
byte[], char[], int[], long[], String, UUID
</code>
.
The plan is to add more common classes (date, time, timestamp, object array).
</p><p>
Parameterized data types are supported
(for example one could build a string data type that limits the length for some reason).
...
...
@@ -232,7 +290,7 @@ which should be resistant against scan operations.
Concurrent modification operations on the maps are currently not supported,
however it is planned to support an additional map implementation
that supports concurrent writes
(at the cost of speed if used in a single thread, same as
ConcurrentHashMap
).
(at the cost of speed if used in a single thread, same as
<code>
ConcurrentHashMap
</code>
).
</p>
<h3>
File System Abstraction, File Locking and Online Backup
</h3>
...
...
@@ -251,9 +309,18 @@ Files can be opened in read-only mode, in which case a shared lock is used.
The persisted data can be backed up to a different file at any time,
even during write operations (online backup).
To do that, automatic disk space reuse needs to be first disabled, so that
new data is always appended at the end of the file. Then, the file
new data is always appended at the end of the file.
Then, the file can be copied (the file handle is available to the application).
</p>
<h3>
Tools
</h3>
<p>
There is a builder for store instances (
<code>
MVStoreBuilder
</code>
)
with a fluent API to simplify building a store instance.
</p>
<p>
There is a tool (
<code>
MVStoreTool
</code>
) to dump the contents of a file.
</p>
<h2
id=
"differences"
>
Similar Projects and Differences to Other Storage Engines
</h2>
<p>
...
...
@@ -261,7 +328,7 @@ Unlike similar storage engines like LevelDB and Kyoto Cabinet, the MVStore is wr
and can easily be embedded in a Java application.
</p><p>
The MVStore is somewhat similar to the Berkeley DB Java Edition because it is also written in Java,
and
also a log structured storage, but the MVStore licensing
is more liberal.
and
is also a log structured storage, but the H2 license
is more liberal.
</p><p>
Like SQLite, the MVStore keeps all data in one file.
The plan is to make the MVStore easier to use and faster than SQLite on Android
...
...
@@ -269,7 +336,7 @@ The plan is to make the MVStore easier to use and faster than SQLite on Android
</p><p>
The API of the MVStore is similar to MapDB (previously known as JDBM) from Jan Kotek,
and some code is shared between MapDB and JDBM.
However,
the MVStore
is a log structured storage.
However,
unlike MapDB, the MVStore uses
is a log structured storage.
</p>
<h2
id=
"current_state"
>
Current State
</h2>
...
...
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
871b0a8e
...
...
@@ -555,120 +555,120 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
beforeTest
();
// db
new
TestScriptSimple
().
runTest
(
this
);
new
TestScript
().
runTest
(
this
);
new
TestAlter
().
runTest
(
this
);
new
TestAlterSchemaRename
().
runTest
(
this
);
new
TestAutoRecompile
().
runTest
(
this
);
new
TestBitField
().
runTest
(
this
);
new
TestBackup
().
runTest
(
this
);
new
TestBigDb
().
runTest
(
this
);
new
TestBigResult
().
runTest
(
this
);
new
TestCases
().
runTest
(
this
);
new
TestCheckpoint
().
runTest
(
this
);
new
TestCluster
().
runTest
(
this
);
new
TestCompatibility
().
runTest
(
this
);
new
TestCsv
().
runTest
(
this
);
new
TestDateStorage
().
runTest
(
this
);
new
TestDeadlock
().
runTest
(
this
);
new
TestEncryptedDb
().
runTest
(
this
);
new
TestExclusive
().
runTest
(
this
);
new
TestFullText
().
runTest
(
this
);
new
TestFunctionOverload
().
runTest
(
this
);
new
TestFunctions
().
runTest
(
this
);
new
TestInit
().
runTest
(
this
);
new
TestIndex
().
runTest
(
this
);
new
TestLargeBlob
().
runTest
(
this
);
new
TestLinkedTable
().
runTest
(
this
);
new
TestListener
().
runTest
(
this
);
new
TestLob
().
runTest
(
this
);
new
TestMemoryUsage
().
runTest
(
this
);
new
TestMultiConn
().
runTest
(
this
);
new
TestMultiDimension
().
runTest
(
this
);
new
TestMultiThread
().
runTest
(
this
);
new
TestMultiThreadedKernel
().
runTest
(
this
);
new
TestOpenClose
().
runTest
(
this
);
new
TestOptimizations
().
runTest
(
this
);
new
TestOutOfMemory
().
runTest
(
this
);
new
TestPowerOff
().
runTest
(
this
);
new
TestQueryCache
().
runTest
(
this
);
new
TestReadOnly
().
runTest
(
this
);
new
TestRecursiveQueries
().
runTest
(
this
);
new
TestRights
().
runTest
(
this
);
new
TestRunscript
().
runTest
(
this
);
new
TestSQLInjection
().
runTest
(
this
);
new
TestSessionsLocks
().
runTest
(
this
);
new
TestSelectCountNonNullColumn
().
runTest
(
this
);
new
TestSequence
().
runTest
(
this
);
new
TestSpaceReuse
().
runTest
(
this
);
new
TestSpeed
().
runTest
(
this
);
new
TestTableEngines
().
runTest
(
this
);
new
TestTempTables
().
runTest
(
this
);
new
TestTransaction
().
runTest
(
this
);
new
TestTriggersConstraints
().
runTest
(
this
);
new
TestTwoPhaseCommit
().
runTest
(
this
);
new
TestView
().
runTest
(
this
);
new
TestViewAlterTable
().
runTest
(
this
);
new
TestViewDropView
().
runTest
(
this
);
// jaqu
new
AliasMapTest
().
runTest
(
this
);
new
AnnotationsTest
().
runTest
(
this
);
new
ClobTest
().
runTest
(
this
);
new
ModelsTest
().
runTest
(
this
);
new
SamplesTest
().
runTest
(
this
);
new
UpdateTest
().
runTest
(
this
);
// jdbc
new
TestBatchUpdates
().
runTest
(
this
);
new
TestCallableStatement
().
runTest
(
this
);
new
TestCancel
().
runTest
(
this
);
new
TestDatabaseEventListener
().
runTest
(
this
);
new
TestDriver
().
runTest
(
this
);
new
TestJavaObject
().
runTest
(
this
);
new
TestLimitUpdates
().
runTest
(
this
);
new
TestLobApi
().
runTest
(
this
);
new
TestManyJdbcObjects
().
runTest
(
this
);
new
TestMetaData
().
runTest
(
this
);
new
TestNativeSQL
().
runTest
(
this
);
new
TestPreparedStatement
().
runTest
(
this
);
new
TestResultSet
().
runTest
(
this
);
new
TestStatement
().
runTest
(
this
);
new
TestTransactionIsolation
().
runTest
(
this
);
new
TestUpdatableResultSet
().
runTest
(
this
);
new
TestZloty
().
runTest
(
this
);
// jdbcx
new
TestConnectionPool
().
runTest
(
this
);
new
TestDataSource
().
runTest
(
this
);
new
TestXA
().
runTest
(
this
);
new
TestXASimple
().
runTest
(
this
);
// server
new
TestAutoServer
().
runTest
(
this
);
new
TestNestedLoop
().
runTest
(
this
);
new
TestWeb
().
runTest
(
this
);
// mvcc & row level locking
new
TestMvcc1
().
runTest
(
this
);
new
TestMvcc2
().
runTest
(
this
);
new
TestMvcc3
().
runTest
(
this
);
new
TestMvccMultiThreaded
().
runTest
(
this
);
new
TestRowLocks
().
runTest
(
this
);
// synth
new
TestBtreeIndex
().
runTest
(
this
);
new
TestDiskFull
().
runTest
(
this
);
new
TestCrashAPI
().
runTest
(
this
);
new
TestFuzzOptimizations
().
runTest
(
this
);
new
TestLimit
().
runTest
(
this
);
new
TestRandomSQL
().
runTest
(
this
);
new
TestRandomCompare
().
runTest
(
this
);
new
TestKillRestart
().
runTest
(
this
);
new
TestKillRestartMulti
().
runTest
(
this
);
new
TestMultiThreaded
().
runTest
(
this
);
new
TestOuterJoins
().
runTest
(
this
);
new
TestNestedJoins
().
runTest
(
this
);
//
new TestScriptSimple().runTest(this);
//
new TestScript().runTest(this);
//
new TestAlter().runTest(this);
//
new TestAlterSchemaRename().runTest(this);
//
new TestAutoRecompile().runTest(this);
//
new TestBitField().runTest(this);
//
new TestBackup().runTest(this);
//
new TestBigDb().runTest(this);
//
new TestBigResult().runTest(this);
//
new TestCases().runTest(this);
//
new TestCheckpoint().runTest(this);
//
new TestCluster().runTest(this);
//
new TestCompatibility().runTest(this);
//
new TestCsv().runTest(this);
//
new TestDateStorage().runTest(this);
//
new TestDeadlock().runTest(this);
//
new TestEncryptedDb().runTest(this);
//
new TestExclusive().runTest(this);
//
new TestFullText().runTest(this);
//
new TestFunctionOverload().runTest(this);
//
new TestFunctions().runTest(this);
//
new TestInit().runTest(this);
//
new TestIndex().runTest(this);
//
new TestLargeBlob().runTest(this);
//
new TestLinkedTable().runTest(this);
//
new TestListener().runTest(this);
//
new TestLob().runTest(this);
//
new TestMemoryUsage().runTest(this);
//
new TestMultiConn().runTest(this);
//
new TestMultiDimension().runTest(this);
//
new TestMultiThread().runTest(this);
//
new TestMultiThreadedKernel().runTest(this);
//
new TestOpenClose().runTest(this);
//
new TestOptimizations().runTest(this);
//
new TestOutOfMemory().runTest(this);
//
new TestPowerOff().runTest(this);
//
new TestQueryCache().runTest(this);
//
new TestReadOnly().runTest(this);
//
new TestRecursiveQueries().runTest(this);
//
new TestRights().runTest(this);
//
new TestRunscript().runTest(this);
//
new TestSQLInjection().runTest(this);
//
new TestSessionsLocks().runTest(this);
//
new TestSelectCountNonNullColumn().runTest(this);
//
new TestSequence().runTest(this);
//
new TestSpaceReuse().runTest(this);
//
new TestSpeed().runTest(this);
//
new TestTableEngines().runTest(this);
//
new TestTempTables().runTest(this);
//
new TestTransaction().runTest(this);
//
new TestTriggersConstraints().runTest(this);
//
new TestTwoPhaseCommit().runTest(this);
//
new TestView().runTest(this);
//
new TestViewAlterTable().runTest(this);
//
new TestViewDropView().runTest(this);
//
//
// jaqu
//
new AliasMapTest().runTest(this);
//
new AnnotationsTest().runTest(this);
//
new ClobTest().runTest(this);
//
new ModelsTest().runTest(this);
//
new SamplesTest().runTest(this);
//
new UpdateTest().runTest(this);
//
//
// jdbc
//
new TestBatchUpdates().runTest(this);
//
new TestCallableStatement().runTest(this);
//
new TestCancel().runTest(this);
//
new TestDatabaseEventListener().runTest(this);
//
new TestDriver().runTest(this);
//
new TestJavaObject().runTest(this);
//
new TestLimitUpdates().runTest(this);
//
new TestLobApi().runTest(this);
//
new TestManyJdbcObjects().runTest(this);
//
new TestMetaData().runTest(this);
//
new TestNativeSQL().runTest(this);
//
new TestPreparedStatement().runTest(this);
//
new TestResultSet().runTest(this);
//
new TestStatement().runTest(this);
//
new TestTransactionIsolation().runTest(this);
//
new TestUpdatableResultSet().runTest(this);
//
new TestZloty().runTest(this);
//
//
// jdbcx
//
new TestConnectionPool().runTest(this);
//
new TestDataSource().runTest(this);
//
new TestXA().runTest(this);
//
new TestXASimple().runTest(this);
//
//
// server
//
new TestAutoServer().runTest(this);
//
new TestNestedLoop().runTest(this);
//
new TestWeb().runTest(this);
//
//
// mvcc & row level locking
//
new TestMvcc1().runTest(this);
//
new TestMvcc2().runTest(this);
//
new TestMvcc3().runTest(this);
//
new TestMvccMultiThreaded().runTest(this);
//
new TestRowLocks().runTest(this);
//
//
// synth
//
new TestBtreeIndex().runTest(this);
//
new TestDiskFull().runTest(this);
//
new TestCrashAPI().runTest(this);
//
new TestFuzzOptimizations().runTest(this);
//
new TestLimit().runTest(this);
//
new TestRandomSQL().runTest(this);
//
new TestRandomCompare().runTest(this);
//
new TestKillRestart().runTest(this);
//
new TestKillRestartMulti().runTest(this);
//
new TestMultiThreaded().runTest(this);
//
new TestOuterJoins().runTest(this);
//
new TestNestedJoins().runTest(this);
afterTest
();
}
...
...
h2/src/test/org/h2/test/store/IntegerType.java
deleted
100644 → 0
浏览文件 @
f2afe926
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
store
;
import
java.nio.ByteBuffer
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.DataUtils
;
/**
* An integer type.
*/
class
IntegerType
implements
DataType
{
public
static
final
IntegerType
INSTANCE
=
new
IntegerType
();
public
int
compare
(
Object
a
,
Object
b
)
{
return
((
Integer
)
a
).
compareTo
((
Integer
)
b
);
}
public
int
getMaxLength
(
Object
obj
)
{
return
DataUtils
.
MAX_VAR_INT_LEN
;
}
public
int
getMemory
(
Object
obj
)
{
return
20
;
}
public
Integer
read
(
ByteBuffer
buff
)
{
return
DataUtils
.
readVarInt
(
buff
);
}
public
void
write
(
ByteBuffer
buff
,
Object
x
)
{
DataUtils
.
writeVarInt
(
buff
,
(
Integer
)
x
);
}
public
String
asString
()
{
return
"i"
;
}
}
h2/src/test/org/h2/test/store/RowType.java
浏览文件 @
871b0a8e
...
...
@@ -7,9 +7,9 @@
package
org
.
h2
.
test
.
store
;
import
java.nio.ByteBuffer
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.DataUtils
;
import
org.h2.dev.store.btree.DataTypeFactory
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.dev.store.type.DataTypeFactory
;
import
org.h2.util.StringUtils
;
/**
...
...
@@ -17,6 +17,8 @@ import org.h2.util.StringUtils;
*/
public
class
RowType
implements
DataType
{
static
final
String
PREFIX
=
"org.h2.test.store.row"
;
private
final
DataType
[]
types
;
RowType
(
DataType
[]
types
)
{
...
...
@@ -86,7 +88,7 @@ public class RowType implements DataType {
public
String
asString
()
{
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
'r'
);
buff
.
append
(
PREFIX
);
buff
.
append
(
'('
);
for
(
int
i
=
0
;
i
<
types
.
length
;
i
++)
{
if
(
i
>
0
)
{
...
...
@@ -106,10 +108,10 @@ public class RowType implements DataType {
* @return the row type
*/
static
RowType
fromString
(
String
t
,
DataTypeFactory
factory
)
{
if
(!
t
.
startsWith
(
"r("
)
||
!
t
.
endsWith
(
")"
))
{
if
(!
t
.
startsWith
(
PREFIX
)
||
!
t
.
endsWith
(
")"
))
{
throw
new
RuntimeException
(
"Unknown type: "
+
t
);
}
t
=
t
.
substring
(
2
,
t
.
length
()
-
1
);
t
=
t
.
substring
(
PREFIX
.
length
()
,
t
.
length
()
-
1
);
String
[]
array
=
StringUtils
.
arraySplit
(
t
,
','
,
false
);
DataType
[]
types
=
new
DataType
[
array
.
length
];
for
(
int
i
=
0
;
i
<
array
.
length
;
i
++)
{
...
...
h2/src/test/org/h2/test/store/SampleTypeFactory.java
0 → 100644
浏览文件 @
871b0a8e
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, Version
* 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
store
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.dev.store.type.DataTypeFactory
;
/**
* A data type factory.
*/
public
class
SampleTypeFactory
implements
DataTypeFactory
{
private
DataTypeFactory
parent
;
@Override
public
void
setParent
(
DataTypeFactory
parent
)
{
this
.
parent
=
parent
;
}
@Override
public
DataType
buildDataType
(
String
s
)
{
// if ("org.h2.test.store.int".equals(s)) {
// return new IntegerType();
// } else
if
(
s
.
startsWith
(
RowType
.
PREFIX
))
{
return
RowType
.
fromString
(
s
,
this
);
}
return
parent
.
buildDataType
(
s
);
}
@Override
public
String
getDataType
(
Class
<?>
objectClass
)
{
// if (objectClass == Integer.class) {
// return "org.h2.test.store.int";
// }
return
parent
.
getDataType
(
objectClass
);
}
}
h2/src/test/org/h2/test/store/SequenceMap.java
浏览文件 @
871b0a8e
...
...
@@ -16,7 +16,7 @@ import org.h2.dev.store.btree.MVStore;
/**
* A custom map returning the keys and values values 1 .. 10.
*/
public
class
SequenceMap
extends
MVMap
<
Integer
,
Stri
ng
>
{
public
class
SequenceMap
extends
MVMap
<
Long
,
Lo
ng
>
{
/**
* The minimum value.
...
...
@@ -29,7 +29,7 @@ public class SequenceMap extends MVMap<Integer, String> {
int
max
=
10
;
public
SequenceMap
()
{
super
(
IntegerType
.
INSTANCE
,
IntegerType
.
INSTANCE
);
super
(
null
,
null
);
}
public
void
open
(
MVStore
store
,
HashMap
<
String
,
String
>
config
)
{
...
...
@@ -37,14 +37,14 @@ public class SequenceMap extends MVMap<Integer, String> {
setReadOnly
(
true
);
}
public
Set
<
Integer
>
keySet
()
{
return
new
AbstractSet
<
Integer
>()
{
public
Set
<
Long
>
keySet
()
{
return
new
AbstractSet
<
Long
>()
{
@Override
public
Iterator
<
Integer
>
iterator
()
{
return
new
Iterator
<
Integer
>()
{
public
Iterator
<
Long
>
iterator
()
{
return
new
Iterator
<
Long
>()
{
int
x
=
min
;
long
x
=
min
;
@Override
public
boolean
hasNext
()
{
...
...
@@ -52,8 +52,8 @@ public class SequenceMap extends MVMap<Integer, String> {
}
@Override
public
Integer
next
()
{
return
Integer
.
valueOf
(
x
++);
public
Long
next
()
{
return
Long
.
valueOf
(
x
++);
}
@Override
...
...
h2/src/test/org/h2/test/store/TestConcurrent.java
浏览文件 @
871b0a8e
...
...
@@ -17,6 +17,7 @@ import java.util.Random;
import
org.h2.dev.store.btree.MVMap
;
import
org.h2.dev.store.btree.MVStore
;
import
org.h2.dev.store.btree.MVStoreBuilder
;
import
org.h2.dev.store.type.ObjectTypeFactory
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.util.Task
;
...
...
@@ -132,8 +133,8 @@ public class TestConcurrent extends TestMVStore {
private
void
testConcurrentIterate
()
{
MVStore
s
=
MVStoreBuilder
.
inMemory
().
with
(
new
SampleData
TypeFactory
()).
open
();
s
.
set
Max
PageSize
(
3
);
with
(
new
Object
TypeFactory
()).
open
();
s
.
setPageSize
(
3
);
final
MVMap
<
Integer
,
Integer
>
map
=
s
.
openMap
(
"test"
);
final
int
len
=
10
;
final
Random
r
=
new
Random
();
...
...
h2/src/test/org/h2/test/store/TestMVRTree.java
浏览文件 @
871b0a8e
...
...
@@ -21,7 +21,10 @@ import javax.imageio.ImageIO;
import
javax.imageio.ImageWriter
;
import
javax.imageio.stream.FileImageOutputStream
;
import
org.h2.dev.store.btree.MVStore
;
import
org.h2.dev.store.btree.StringType
;
import
org.h2.dev.store.rtree.MVRTreeMap
;
import
org.h2.dev.store.rtree.SpatialKey
;
import
org.h2.dev.store.type.ObjectType
;
import
org.h2.dev.store.type.StringType
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
import
org.h2.util.New
;
...
...
@@ -41,10 +44,38 @@ public class TestMVRTree extends TestMVStore {
}
public
void
test
()
{
testExample
();
testMany
();
testSimple
();
testRandom
();
testCustomMapType
();
}
private
void
testExample
()
{
// create an in-memory store
MVStore
s
=
MVStore
.
open
(
null
);
// create an R-tree map
// the key has 2 dimensions, the value is a string
MVRTreeMap
<
String
>
r
=
MVRTreeMap
.
create
(
2
,
new
ObjectType
());
// open the map
r
=
s
.
openMap
(
"data"
,
r
);
// 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
,
-
3
f
,
-
2
f
,
2
f
,
3
f
),
"left"
);
r
.
add
(
new
SpatialKey
(
1
,
3
f
,
4
f
,
4
f
,
5
f
),
"right"
);
// iterate over the intersecting keys
Iterator
<
SpatialKey
>
it
=
r
.
findIntersectingKeys
(
new
SpatialKey
(
0
,
0
f
,
9
f
,
3
f
,
6
f
));
for
(
SpatialKey
k
;
it
.
hasNext
();)
{
k
=
it
.
next
();
// System.out.println(k + ": " + r.get(k));
assertTrue
(
k
!=
null
);
}
s
.
close
();
}
private
void
testMany
()
{
...
...
@@ -276,19 +307,4 @@ public class TestMVRTree extends TestMVStore {
s
.
close
();
}
private
void
testCustomMapType
()
{
String
fileName
=
getBaseDir
()
+
"/testMapType.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
;
s
=
openStore
(
fileName
);
SequenceMap
seq
=
new
SequenceMap
();
seq
=
s
.
openMap
(
"data"
,
seq
);
StringBuilder
buff
=
new
StringBuilder
();
for
(
int
x
:
seq
.
keySet
())
{
buff
.
append
(
x
).
append
(
';'
);
}
assertEquals
(
"1;2;3;4;5;6;7;8;9;10;"
,
buff
.
toString
());
s
.
close
();
}
}
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
871b0a8e
...
...
@@ -14,11 +14,13 @@ import java.util.Map;
import
java.util.Random
;
import
java.util.TreeMap
;
import
org.h2.dev.store.btree.Cursor
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.MVMap
;
import
org.h2.dev.store.btree.MVStore
;
import
org.h2.dev.store.btree.MVStoreBuilder
;
import
org.h2.dev.store.btree.StringType
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.dev.store.type.ObjectType
;
import
org.h2.dev.store.type.ObjectTypeFactory
;
import
org.h2.dev.store.type.StringType
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.test.TestBase
;
...
...
@@ -40,6 +42,7 @@ public class TestMVStore extends TestBase {
public
void
test
()
throws
Exception
{
FileUtils
.
deleteRecursive
(
getBaseDir
(),
true
);
testCustomMapType
();
testCacheSize
();
testConcurrentOpen
();
testFileHeader
();
...
...
@@ -70,12 +73,27 @@ public class TestMVStore extends TestBase {
testSimple
();
}
private
void
testCustomMapType
()
{
String
fileName
=
getBaseDir
()
+
"/testMapType.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
;
s
=
openStore
(
fileName
);
SequenceMap
seq
=
new
SequenceMap
();
seq
=
s
.
openMap
(
"data"
,
seq
);
StringBuilder
buff
=
new
StringBuilder
();
for
(
long
x
:
seq
.
keySet
())
{
buff
.
append
(
x
).
append
(
';'
);
}
assertEquals
(
"1;2;3;4;5;6;7;8;9;10;"
,
buff
.
toString
());
s
.
close
();
}
private
void
testCacheSize
()
{
String
fileName
=
getBaseDir
()
+
"/testCacheSize.h3"
;
MVStore
s
;
MVMap
<
Integer
,
String
>
map
;
s
=
MVStoreBuilder
.
fileBased
(
fileName
).
with
(
new
SampleData
TypeFactory
()).
open
();
with
(
new
Object
TypeFactory
()).
open
();
map
=
s
.
openMap
(
"test"
);
// add 10 MB of data
for
(
int
i
=
0
;
i
<
1024
;
i
++)
{
...
...
@@ -89,7 +107,7 @@ public class TestMVStore extends TestBase {
for
(
int
cacheSize
=
0
;
cacheSize
<=
6
;
cacheSize
+=
4
)
{
s
=
MVStoreBuilder
.
fileBased
(
fileName
).
cacheSizeMB
(
1
+
3
*
cacheSize
).
with
(
new
SampleData
TypeFactory
()).
open
();
with
(
new
Object
TypeFactory
()).
open
();
map
=
s
.
openMap
(
"test"
);
for
(
int
i
=
0
;
i
<
1024
;
i
+=
128
)
{
for
(
int
j
=
0
;
j
<
i
;
j
++)
{
...
...
@@ -179,7 +197,7 @@ public class TestMVStore extends TestBase {
private
void
testIndexSkip
()
{
MVStore
s
=
openStore
(
null
);
s
.
set
Max
PageSize
(
4
);
s
.
setPageSize
(
4
);
MVMap
<
Integer
,
Integer
>
map
=
s
.
openMap
(
"test"
);
for
(
int
i
=
0
;
i
<
100
;
i
+=
2
)
{
map
.
put
(
i
,
10
*
i
);
...
...
@@ -240,7 +258,7 @@ public class TestMVStore extends TestBase {
for
(
int
i
=
3
;
i
<
20
;
i
++)
{
s
=
openStore
(
null
);
s
.
set
Max
PageSize
(
4
);
s
.
setPageSize
(
4
);
map
=
s
.
openMap
(
"test"
);
for
(
int
j
=
3
;
j
<
i
;
j
++)
{
map
.
put
(
j
*
2
,
j
*
20
);
...
...
@@ -310,7 +328,7 @@ public class TestMVStore extends TestBase {
MVStore
s
;
Map
<
Integer
,
Integer
>
map
;
s
=
MVStoreBuilder
.
inMemory
().
with
(
new
SampleData
TypeFactory
()).
open
();
with
(
new
Object
TypeFactory
()).
open
();
map
=
s
.
openMap
(
"test"
);
int
len
=
100
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
...
...
@@ -336,7 +354,7 @@ public class TestMVStore extends TestBase {
MVStore
s
;
Map
<
Object
,
Object
>
map
;
s
=
MVStoreBuilder
.
fileBased
(
fileName
).
with
(
new
SampleData
TypeFactory
()).
open
();
with
(
new
Object
TypeFactory
()).
open
();
map
=
s
.
openMap
(
"test"
);
map
.
put
(
1
,
"Hello"
);
map
.
put
(
"2"
,
200
);
...
...
@@ -344,7 +362,7 @@ public class TestMVStore extends TestBase {
s
.
store
();
s
.
close
();
s
=
MVStoreBuilder
.
fileBased
(
fileName
).
with
(
new
SampleData
TypeFactory
()).
open
();
with
(
new
Object
TypeFactory
()).
open
();
map
=
s
.
openMap
(
"test"
);
assertEquals
(
"Hello"
,
map
.
get
(
1
).
toString
());
assertEquals
(
200
,
((
Integer
)
map
.
get
(
"2"
)).
intValue
());
...
...
@@ -362,14 +380,12 @@ public class TestMVStore extends TestBase {
// open the store (in-memory if fileName is null)
MVStore
s
=
MVStore
.
open
(
fileName
);
// create/get the map "data"
// the String.class, String.class will be optional later
MVMap
<
String
,
String
>
map
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
// create/get the map named "data"
MVMap
<
Integer
,
String
>
map
=
s
.
openMap
(
"data"
);
// add some data
map
.
put
(
"1"
,
"Hello"
);
map
.
put
(
"2"
,
"World"
);
map
.
put
(
1
,
"Hello"
);
map
.
put
(
2
,
"World"
);
// get the current version, for later use
long
oldVersion
=
s
.
getCurrentVersion
();
...
...
@@ -380,11 +396,11 @@ public class TestMVStore extends TestBase {
// 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"
);
map
.
put
(
1
,
"Hi"
);
map
.
remove
(
2
);
// access the old data (before incrementVersion)
MVMap
<
String
,
String
>
oldMap
=
MVMap
<
Integer
,
String
>
oldMap
=
map
.
openVersion
(
oldVersion
);
// store the newest data to disk
...
...
@@ -393,12 +409,12 @@ public class TestMVStore extends TestBase {
// print the old version (can be done
// concurrently with further modifications)
// this will print Hello World
// System.out.println(oldMap.get(
"1"
));
// System.out.println(oldMap.get(
"2"
));
// System.out.println(oldMap.get(
1
));
// System.out.println(oldMap.get(
2
));
oldMap
.
close
();
// print the newest version ("Hi")
// System.out.println(map.get(
"1"
));
// System.out.println(map.get(
1
));
// close the store - this doesn't write to disk
s
.
close
();
...
...
@@ -429,7 +445,7 @@ public class TestMVStore extends TestBase {
String
fileName
=
getBaseDir
()
+
"/testIterate.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
s
.
set
Max
PageSize
(
6
);
s
.
setPageSize
(
6
);
MVMap
<
Integer
,
String
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
String
.
class
);
for
(
int
i
=
0
;
i
<
100
;
i
++)
{
m
.
put
(
i
,
"Hi"
);
...
...
@@ -538,14 +554,14 @@ public class TestMVStore extends TestBase {
MVStore
s
;
MVMap
<
Integer
,
String
>
m
;
s
=
openStore
(
fileName
);
s
.
set
Max
PageSize
(
700
);
s
.
setPageSize
(
700
);
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
String
.
class
);
for
(
int
i
=
0
;
i
<
1000
;
i
++)
{
m
.
put
(
i
,
"Hello World"
);
assertEquals
(
i
+
1
,
m
.
size
());
}
assertEquals
(
1000
,
m
.
size
());
assertEquals
(
2
79
,
s
.
getUnsavedPageCount
());
assertEquals
(
2
84
,
s
.
getUnsavedPageCount
());
s
.
store
();
assertEquals
(
3
,
s
.
getFileWriteCount
());
s
.
close
();
...
...
@@ -556,7 +572,7 @@ public class TestMVStore extends TestBase {
assertEquals
(
0
,
m
.
size
());
s
.
store
();
// ensure only nodes are read, but not leaves
assertEquals
(
36
,
s
.
getFileReadCount
());
assertEquals
(
41
,
s
.
getFileReadCount
());
assertEquals
(
2
,
s
.
getFileWriteCount
());
s
.
close
();
}
...
...
@@ -652,7 +668,7 @@ public class TestMVStore extends TestBase {
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
assertEquals
(
0
,
s
.
getCurrentVersion
());
s
.
set
Max
PageSize
(
5
);
s
.
setPageSize
(
5
);
MVMap
<
String
,
String
>
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
s
.
rollbackTo
(
0
);
assertTrue
(
m
.
isClosed
());
...
...
@@ -753,11 +769,11 @@ public class TestMVStore extends TestBase {
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
// s.setCompressor(null);
s
.
set
Max
PageSize
(
40
);
s
.
setPageSize
(
40
);
MVMap
<
Integer
,
Object
[]>
m
=
new
MVMap
<
Integer
,
Object
[]>(
IntegerType
.
INSTANCE
,
new
ObjectType
()
,
new
RowType
(
new
DataType
[]
{
IntegerType
.
INSTANCE
,
new
ObjectType
()
,
StringType
.
INSTANCE
,
StringType
.
INSTANCE
})
...
...
@@ -965,26 +981,9 @@ public class TestMVStore extends TestBase {
}
private
void
testKeyValueClasses
()
{
MVStore
s
;
s
=
MVStore
.
open
(
null
);
s
.
openMap
(
"test"
,
String
.
class
,
String
.
class
);
try
{
s
.
openMap
(
"unsupportedKey"
,
ArrayList
.
class
,
String
.
class
);
fail
();
}
catch
(
RuntimeException
e
)
{
// expected
}
try
{
s
.
openMap
(
"unsupportedValue"
,
String
.
class
,
ArrayList
.
class
);
fail
();
}
catch
(
RuntimeException
e
)
{
// expected
}
s
.
close
();
String
fileName
=
getBaseDir
()
+
"/testKeyValueClasses.h3"
;
FileUtils
.
delete
(
fileName
);
s
=
openStore
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
MVMap
<
Integer
,
String
>
is
=
s
.
openMap
(
"intString"
,
Integer
.
class
,
String
.
class
);
is
.
put
(
1
,
"Hello"
);
MVMap
<
Integer
,
Integer
>
ii
=
s
.
openMap
(
"intInt"
,
Integer
.
class
,
Integer
.
class
);
...
...
@@ -1089,8 +1088,8 @@ public class TestMVStore extends TestBase {
*/
protected
static
MVStore
openStore
(
String
fileName
)
{
MVStore
store
=
MVStoreBuilder
.
fileBased
(
fileName
).
with
(
new
Sample
Data
TypeFactory
()).
open
();
store
.
set
Max
PageSize
(
1000
);
with
(
new
SampleTypeFactory
()).
open
();
store
.
setPageSize
(
1000
);
return
store
;
}
...
...
h2/src/test/org/h2/test/store/TestObjectType.java
浏览文件 @
871b0a8e
...
...
@@ -13,6 +13,7 @@ import java.sql.Timestamp;
import
java.util.Arrays
;
import
java.util.Random
;
import
java.util.UUID
;
import
org.h2.dev.store.type.ObjectType
;
import
org.h2.test.TestBase
;
/**
...
...
h2/src/tools/org/h2/dev/store/btree/MVMap.java
浏览文件 @
871b0a8e
...
...
@@ -16,6 +16,7 @@ import java.util.List;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentMap
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.util.New
;
/**
...
...
@@ -72,7 +73,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
root
.
copyOnWrite
(
writeVersion
);
if
(
p
.
getMemory
()
>
store
.
get
Max
PageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
if
(
p
.
getMemory
()
>
store
.
getPageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
int
at
=
p
.
getKeyCount
()
/
2
;
long
totalCount
=
p
.
getTotalCount
();
Object
k
=
p
.
getKey
(
at
);
...
...
@@ -118,7 +119,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
index
++;
}
Page
c
=
p
.
getChildPage
(
index
).
copyOnWrite
(
writeVersion
);
if
(
c
.
getMemory
()
>
store
.
get
Max
PageSize
()
&&
c
.
getKeyCount
()
>
1
)
{
if
(
c
.
getMemory
()
>
store
.
getPageSize
()
&&
c
.
getKeyCount
()
>
1
)
{
// split on the way down
int
at
=
c
.
getKeyCount
()
/
2
;
Object
k
=
c
.
getKey
(
at
);
...
...
@@ -957,8 +958,12 @@ public class MVMap<K, V> extends AbstractMap<K, V>
DataUtils
.
appendMap
(
buff
,
"name"
,
name
);
DataUtils
.
appendMap
(
buff
,
"type"
,
getType
());
DataUtils
.
appendMap
(
buff
,
"createVersion"
,
createVersion
);
DataUtils
.
appendMap
(
buff
,
"key"
,
keyType
.
asString
());
DataUtils
.
appendMap
(
buff
,
"value"
,
valueType
.
asString
());
if
(
keyType
!=
null
)
{
DataUtils
.
appendMap
(
buff
,
"key"
,
keyType
.
asString
());
}
if
(
valueType
!=
null
)
{
DataUtils
.
appendMap
(
buff
,
"value"
,
valueType
.
asString
());
}
return
buff
.
toString
();
}
...
...
h2/src/tools/org/h2/dev/store/btree/MVStore.java
浏览文件 @
871b0a8e
...
...
@@ -19,8 +19,12 @@ import java.util.Iterator;
import
java.util.Map
;
import
org.h2.compress.CompressLZF
;
import
org.h2.compress.Compressor
;
import
org.h2.dev.store.FilePathCache
;
import
org.h2.dev.store.cache.CacheLongKeyLIRS
;
import
org.h2.dev.store.cache.FilePathCache
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.dev.store.type.DataTypeFactory
;
import
org.h2.dev.store.type.ObjectTypeFactory
;
import
org.h2.dev.store.type.StringType
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
import
org.h2.util.New
;
...
...
@@ -36,6 +40,9 @@ header:
H:3,...
TODO:
- support serialization by default
- build script
- test concurrent storing in a background thread
- store store creation in file header, and seconds since creation in chunk header (plus a counter)
- recovery: keep some old chunks; don't overwritten for 5 minutes (configurable)
- allocate memory with Utils.newBytes and so on
...
...
@@ -69,9 +76,13 @@ TODO:
- triggers (can be implemented with a custom map)
- store write operations per page (maybe defragment if much different than count)
- r-tree: nearest neighbor search
- use FileChannel by default (nio file system)
- use FileChannel by default (nio file system)
, but: an interrupt close the FileChannel
- auto-save temporary data if it uses too much memory, but revert it on startup if needed.
- map and chunk metadata: do not store default values
- support maps without values (non-unique indexes), and maps without keys (counted b-tree)
- use a small object cache (StringCache)
- dump values
- tool to import / manipulate CSV files
*/
...
...
@@ -92,7 +103,7 @@ public class MVStore {
private
final
String
fileName
;
private
final
DataTypeFactory
dataTypeFactory
;
private
int
maxPageSize
=
4
*
1024
;
private
int
pageSize
=
6
*
1024
;
private
FileChannel
file
;
private
FileLock
fileLock
;
...
...
@@ -104,8 +115,7 @@ public class MVStore {
* split in 16 segments. The stack move distance is 2% of the expected
* number of entries.
*/
private
final
CacheLongKeyLIRS
<
Page
>
cache
=
CacheLongKeyLIRS
.
newInstance
(
16
*
1024
*
1024
,
2048
,
16
,
16
*
1024
*
1024
/
2048
*
2
/
100
);
private
CacheLongKeyLIRS
<
Page
>
cache
;
private
int
lastChunkId
;
private
final
HashMap
<
Integer
,
Chunk
>
chunks
=
New
.
hashMap
();
...
...
@@ -145,12 +155,21 @@ public class MVStore {
MVStore
(
HashMap
<
String
,
Object
>
config
)
{
this
.
config
=
config
;
this
.
fileName
=
(
String
)
config
.
get
(
"fileName"
);
this
.
dataTypeFactory
=
(
DataTypeFactory
)
config
.
get
(
"dataTypeFactory"
);
DataTypeFactory
parent
=
new
ObjectTypeFactory
();
DataTypeFactory
f
=
(
DataTypeFactory
)
config
.
get
(
"dataTypeFactory"
);
if
(
f
==
null
)
{
f
=
parent
;
}
else
{
f
.
setParent
(
parent
);
}
this
.
dataTypeFactory
=
f
;
this
.
readOnly
=
"r"
.
equals
(
config
.
get
(
"openMode"
));
this
.
compressor
=
"0"
.
equals
(
config
.
get
(
"compression"
))
?
null
:
new
CompressLZF
();
Object
s
=
config
.
get
(
"cacheSize"
);
if
(
s
!=
null
)
{
cache
.
setMaxMemory
(
Integer
.
parseInt
(
s
.
toString
())
*
1024
*
1024
);
if
(
fileName
!=
null
)
{
Object
s
=
config
.
get
(
"cacheSize"
);
int
mb
=
s
==
null
?
16
:
Integer
.
parseInt
(
s
.
toString
());
cache
=
CacheLongKeyLIRS
.
newInstance
(
mb
*
1024
*
1024
,
2048
,
16
,
mb
*
1024
*
1024
/
2048
*
2
/
100
);
}
}
...
...
@@ -519,7 +538,7 @@ public class MVStore {
return
currentVersion
;
}
// the last chunk was not completely correct in the last s
av
e()
// the last chunk was not completely correct in the last s
tor
e()
// this needs to be updated now (it's better not to update right after
// storing, because that would modify the meta map again)
Chunk
c
=
chunks
.
get
(
lastChunkId
);
...
...
@@ -944,24 +963,24 @@ public class MVStore {
}
/**
* Set the
maximum amount of memory a page should contain
, in bytes. Larger
* pages are split. The default is
4
KB. This is not a limit in the page
* size
, as pages with one entry can be larger. As a rule of thumb, pages
*
should not be larger than 1 MB, for caching to work efficiently
.
* Set the
amount of memory a page should contain at most
, in bytes. Larger
* pages are split. The default is
6
KB. This is not a limit in the page
* size
(pages with one entry can get larger), it is just the point where
*
pages are split
.
*
* @param
maxP
ageSize the page size
* @param
p
ageSize the page size
*/
public
void
set
MaxPageSize
(
int
maxP
ageSize
)
{
this
.
maxPageSize
=
maxP
ageSize
;
public
void
set
PageSize
(
int
p
ageSize
)
{
this
.
pageSize
=
p
ageSize
;
}
/**
* Get the
maximum
page size, in bytes.
* Get the page size, in bytes.
*
* @return the
maximum
page size
* @return the page size
*/
public
int
get
Max
PageSize
()
{
return
maxP
ageSize
;
public
int
getPageSize
()
{
return
p
ageSize
;
}
Compressor
getCompressor
()
{
...
...
h2/src/tools/org/h2/dev/store/btree/MVStoreBuilder.java
浏览文件 @
871b0a8e
...
...
@@ -7,6 +7,7 @@
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.util.HashMap
;
import
org.h2.dev.store.type.DataTypeFactory
;
import
org.h2.util.New
;
/**
...
...
h2/src/tools/org/h2/dev/store/btree/MVStore
Utils
.java
→
h2/src/tools/org/h2/dev/store/btree/MVStore
Tool
.java
浏览文件 @
871b0a8e
...
...
@@ -19,7 +19,7 @@ import org.h2.store.fs.FileUtils;
/**
* Utility methods used in combination with the MVStore.
*/
public
class
MVStore
Utils
{
public
class
MVStore
Tool
{
/**
* Runs this tool.
...
...
h2/src/tools/org/h2/dev/store/btree/Page.java
浏览文件 @
871b0a8e
...
...
@@ -11,6 +11,7 @@ import java.nio.ByteBuffer;
import
java.nio.channels.FileChannel
;
import
java.util.Arrays
;
import
org.h2.compress.Compressor
;
import
org.h2.dev.store.type.DataType
;
/**
* A page (a node or a leaf).
...
...
h2/src/tools/org/h2/dev/store/cache/CacheLongKeyLIRS.java
浏览文件 @
871b0a8e
...
...
@@ -148,7 +148,7 @@ public class CacheLongKeyLIRS<V> {
* @param key the key (may not be null)
* @return the old value, or null if there was no resident entry
*/
public
synchronized
V
remove
(
long
key
)
{
public
V
remove
(
long
key
)
{
int
hash
=
getHash
(
key
);
return
getSegment
(
hash
).
remove
(
key
,
hash
);
}
...
...
h2/src/tools/org/h2/dev/store/FilePathCache.java
→
h2/src/tools/org/h2/dev/store/
cache/
FilePathCache.java
浏览文件 @
871b0a8e
...
...
@@ -4,13 +4,12 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
store
;
package
org
.
h2
.
dev
.
store
.
cache
;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
import
org.h2.dev.store.cache.CacheLongKeyLIRS
;
import
org.h2.store.fs.FileBase
;
import
org.h2.store.fs.FilePathWrapper
;
...
...
h2/src/t
est/org/h2/test/stor
e/MVRTreeMap.java
→
h2/src/t
ools/org/h2/dev/store/rtre
e/MVRTreeMap.java
浏览文件 @
871b0a8e
...
...
@@ -4,15 +4,15 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
stor
e
;
package
org
.
h2
.
dev
.
store
.
rtre
e
;
import
java.util.ArrayList
;
import
java.util.Iterator
;
import
org.h2.dev.store.btree.Cursor
;
import
org.h2.dev.store.btree.CursorPos
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.MVMap
;
import
org.h2.dev.store.btree.Page
;
import
org.h2.dev.store.type.DataType
;
import
org.h2.util.New
;
/**
...
...
@@ -50,7 +50,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
checkOpen
();
return
new
RTreeCursor
(
this
,
root
,
x
)
{
protected
boolean
check
(
boolean
leaf
,
SpatialKey
key
,
SpatialKey
test
)
{
return
keyType
.
contains
(
key
,
test
);
return
keyType
.
isOverlap
(
key
,
test
);
}
};
}
...
...
@@ -201,7 +201,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
Page
p
=
root
.
copyOnWrite
(
writeVersion
);
Object
result
;
if
(
alwaysAdd
||
get
(
key
)
==
null
)
{
if
(
p
.
getMemory
()
>
store
.
get
Max
PageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
if
(
p
.
getMemory
()
>
store
.
getPageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
// only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed)
long
totalCount
=
p
.
getTotalCount
();
...
...
@@ -283,7 +283,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
}
}
Page
c
=
p
.
getChildPage
(
index
).
copyOnWrite
(
writeVersion
);
if
(
c
.
getMemory
()
>
store
.
get
Max
PageSize
()
&&
c
.
getKeyCount
()
>
1
)
{
if
(
c
.
getMemory
()
>
store
.
getPageSize
()
&&
c
.
getKeyCount
()
>
1
)
{
// split on the way down
Page
split
=
split
(
c
,
writeVersion
);
p
=
p
.
copyOnWrite
(
writeVersion
);
...
...
h2/src/t
est/org/h2/test/stor
e/SpatialKey.java
→
h2/src/t
ools/org/h2/dev/store/rtre
e/SpatialKey.java
浏览文件 @
871b0a8e
...
...
@@ -4,7 +4,7 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
stor
e
;
package
org
.
h2
.
dev
.
store
.
rtre
e
;
import
java.util.Arrays
;
...
...
h2/src/t
est/org/h2/test/stor
e/SpatialType.java
→
h2/src/t
ools/org/h2/dev/store/rtre
e/SpatialType.java
浏览文件 @
871b0a8e
...
...
@@ -4,12 +4,12 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
stor
e
;
package
org
.
h2
.
dev
.
store
.
rtre
e
;
import
java.nio.ByteBuffer
;
import
java.util.ArrayList
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.DataUtils
;
import
org.h2.dev.store.type.DataType
;
/**
* A spatial data type. This class supports up to 255 dimensions. Each dimension
...
...
h2/src/tools/org/h2/dev/store/
btre
e/DataType.java
→
h2/src/tools/org/h2/dev/store/
typ
e/DataType.java
浏览文件 @
871b0a8e
...
...
@@ -4,7 +4,7 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
store
.
btre
e
;
package
org
.
h2
.
dev
.
store
.
typ
e
;
import
java.nio.ByteBuffer
;
...
...
@@ -58,6 +58,9 @@ public interface DataType {
/**
* Get the stable string representation that is used to build this data
* type.
* <p>
* To avoid conflict with the default factory, the returned string should
* start with the package name of the type factory.
*
* @return the string representation
*/
...
...
h2/src/tools/org/h2/dev/store/
btre
e/DataTypeFactory.java
→
h2/src/tools/org/h2/dev/store/
typ
e/DataTypeFactory.java
浏览文件 @
871b0a8e
...
...
@@ -4,27 +4,36 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
store
.
btree
;
package
org
.
h2
.
dev
.
store
.
type
;
/**
* A factory for maps and data types.
*/
public
interface
DataTypeFactory
{
/**
* Set the parent factory.
*
* @param parent the parent factory
*/
void
setParent
(
DataTypeFactory
parent
);
/**
* Parse the data type.
*
* @param dataType the string and type specific meta data
* @return the type
* @return the type
, or null if unknown
*/
DataType
buildDataType
(
String
dataType
);
/**
* Get the data type object for the given class.
* Get the data type identifier for the given class.
* <p>
* To avoid conflict with the default factory, the returned string should
* start with the package name of the type factory.
*
* @param objectClass the class
* @return the data type
object
* @return the data type
identifier, or null if not supported
*/
String
getDataType
(
Class
<?>
objectClass
);
...
...
h2/src/t
est/org/h2/test/stor
e/ObjectType.java
→
h2/src/t
ools/org/h2/dev/store/typ
e/ObjectType.java
浏览文件 @
871b0a8e
...
...
@@ -4,13 +4,12 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
stor
e
;
package
org
.
h2
.
dev
.
store
.
typ
e
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.nio.ByteBuffer
;
import
java.util.UUID
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.DataUtils
;
import
org.h2.util.Utils
;
...
...
@@ -652,7 +651,7 @@ public class ObjectType implements DataType {
/**
* The type for long objects.
*/
class
LongType
extends
AutoDetectDataType
{
public
class
LongType
extends
AutoDetectDataType
{
LongType
(
ObjectType
base
)
{
super
(
base
,
TYPE_LONG
);
...
...
h2/src/t
est/org/h2/test/store/SampleData
TypeFactory.java
→
h2/src/t
ools/org/h2/dev/store/type/Object
TypeFactory.java
浏览文件 @
871b0a8e
...
...
@@ -3,43 +3,36 @@
* 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
stor
e
;
package
org
.
h2
.
dev
.
store
.
typ
e
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.DataTypeFactory
;
import
org.h2.dev.store.btree.StringType
;
import
org.h2.dev.store.rtree.SpatialType
;
/**
* A data type factory.
*/
public
class
SampleDataTypeFactory
implements
DataTypeFactory
{
public
class
ObjectTypeFactory
implements
DataTypeFactory
{
@Override
public
void
setParent
(
DataTypeFactory
parent
)
{
// never called for this factory
}
@Override
public
DataType
buildDataType
(
String
s
)
{
if
(
s
.
length
()
==
0
)
{
return
new
StringType
();
}
switch
(
s
.
charAt
(
0
))
{
case
'i'
:
return
new
IntegerType
();
case
'r'
:
return
RowType
.
fromString
(
s
,
this
);
case
's'
:
if
(
"s"
.
equals
(
s
))
{
return
SpatialType
.
fromString
(
s
);
case
'o'
:
}
else
if
(
"o"
.
equals
(
s
))
{
return
new
ObjectType
();
}
throw
new
RuntimeException
(
"Unknown data type "
+
s
)
;
return
null
;
}
@Override
public
String
getDataType
(
Class
<?>
objectClass
)
{
if
(
objectClass
==
Integer
.
class
)
{
return
"i"
;
}
else
if
(
Object
.
class
==
Object
.
class
)
{
return
"o"
;
if
(
objectClass
==
SpatialType
.
class
)
{
return
"s"
;
}
throw
new
RuntimeException
(
"Unsupported object class "
+
objectClass
.
toString
())
;
return
"o"
;
}
}
h2/src/tools/org/h2/dev/store/
btre
e/StringType.java
→
h2/src/tools/org/h2/dev/store/
typ
e/StringType.java
浏览文件 @
871b0a8e
...
...
@@ -4,9 +4,10 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
dev
.
store
.
btre
e
;
package
org
.
h2
.
dev
.
store
.
typ
e
;
import
java.nio.ByteBuffer
;
import
org.h2.dev.store.btree.DataUtils
;
/**
* A string type.
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论