提交 b70ccb3e authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore

上级 1db91147
......@@ -31,8 +31,8 @@ import org.h2.value.ValueNull;
*/
public class MVPrimaryIndex extends BaseIndex {
protected final MVTable mvTable;
protected MVMap<Long, Value[]> map;
private final MVTable mvTable;
private MVMap<Long, Value[]> map;
private long lastKey;
private int mainIndexColumn = -1;
......@@ -52,6 +52,11 @@ public class MVPrimaryIndex extends BaseIndex {
lastKey = k == null ? 0 : k;
}
/**
* Rename the index.
*
* @param newName the new name
*/
public void renameTable(String newName) {
rename(newName + "_DATA");
map.renameMap(newName + "_DATA_" + getId());
......
......@@ -32,9 +32,13 @@ import org.h2.value.ValueNull;
*/
public class MVSecondaryIndex extends BaseIndex {
protected final MVTable mvTable;
protected final int keyColumns;
protected MVMap<Value[], Long> map;
/**
* The multi-value table.
*/
final MVTable mvTable;
private final int keyColumns;
private MVMap<Value[], Long> map;
public MVSecondaryIndex(Database db, MVTable table, int id, String indexName,
IndexColumn[] columns, IndexType indexType) {
......@@ -131,6 +135,12 @@ public class MVSecondaryIndex extends BaseIndex {
return array;
}
/**
* Get the row with the given index key.
*
* @param array the index key
* @return the row
*/
SearchRow getRow(Value[] array) {
SearchRow searchRow = mvTable.getTemplateRow();
searchRow.setKey((array[array.length - 1]).getLong());
......
......@@ -81,6 +81,11 @@ public class MVTable extends TableBase {
traceLock = database.getTrace(Trace.LOCK);
}
/**
* Initialize the table.
*
* @param session the session
*/
void init(Session session) {
primaryIndex = new MVPrimaryIndex(session.getDatabase(),
this, getId(),
......@@ -342,6 +347,13 @@ public class MVTable extends TableBase {
MVTableEngine.closeTable(storeName, this);
}
/**
* Get the given row.
*
* @param session the session
* @param key the primary key
* @return the row
*/
Row getRow(Session session, long key) {
return primaryIndex.getRow(session, key);
}
......
......@@ -27,6 +27,11 @@ public class MVTableEngine implements TableEngine {
static final Map<String, Store> STORES = new WeakHashMap<String, Store>();
/**
* Flush all changes.
*
* @param db the database
*/
public static void flush(Database db) {
String storeName = db.getDatabasePath();
if (storeName == null) {
......@@ -38,7 +43,7 @@ public class MVTableEngine implements TableEngine {
return;
}
// TODO this stores uncommitted transactions as well
store(store.store);
store(store.getStore());
}
}
......@@ -77,26 +82,38 @@ public class MVTableEngine implements TableEngine {
}
}
}
MVTable table = new MVTable(data, storeName, store.store);
MVTable table = new MVTable(data, storeName, store.getStore());
store.openTables.add(table);
table.init(data.session);
return table;
}
/**
* Close the table, and close the store if there are no remaining open
* tables.
*
* @param storeName the store name
* @param table the table
*/
static void closeTable(String storeName, MVTable table) {
synchronized (STORES) {
Store store = STORES.get(storeName);
if (store != null) {
store.openTables.remove(table);
if (store.openTables.size() == 0) {
store(store.store);
store.store.close();
store(store.getStore());
store.getStore().close();
STORES.remove(storeName);
}
}
}
}
/**
* Store the data if needed.
*
* @param store the store
*/
static void store(MVStore store) {
store.compact(50);
store.store();
......@@ -107,10 +124,21 @@ public class MVTableEngine implements TableEngine {
*/
public static class Store {
/**
* The database.
*/
final Database db;
final MVStore store;
/**
* The list of open tables.
*/
final ArrayList<MVTable> openTables = New.arrayList();
/**
* The store.
*/
private final MVStore store;
public Store(Database db, MVStore store) {
this.db = db;
this.store = store;
......
......@@ -126,7 +126,7 @@ public class ValueArrayDataType implements DataType {
return comp;
}
public int compareTypeSave(Value a, Value b) {
private int compareTypeSave(Value a, Value b) {
if (a == b) {
return 0;
}
......
......@@ -301,7 +301,8 @@ public class TestMVTableEngine extends TestBase {
";DEFAULT_TABLE_ENGINE=org.h2.mvstore.db.MVTableEngine";
Connection conn = getConnection(dbName);
Statement stat = conn.createStatement();
// create table test(id int, name varchar) engine "org.h2.mvstore.db.MVStoreTableEngine"
// create table test(id int, name varchar)
// engine "org.h2.mvstore.db.MVStoreTableEngine"
stat.execute("create table test(id int primary key, name varchar)");
stat.execute("insert into test values(1, 'Hello'), (2, 'World')");
ResultSet rs = stat.executeQuery("select *, _rowid_ from test");
......
......@@ -15,13 +15,14 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.StreamStore;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
import org.h2.util.New;
import org.h2.util.StringUtils;
// import org.junit.Test;
// import static org.junit.Assert.*;
/**
* Test the stream store.
......@@ -39,6 +40,7 @@ public class TestStreamStore extends TestBase {
@Override
public void test() throws IOException {
testVeryLarge();
testDetectIllegalId();
testTreeStructure();
testFormat();
......@@ -47,6 +49,67 @@ public class TestStreamStore extends TestBase {
testLoop();
}
private void testVeryLarge() throws IOException {
String fileName = getBaseDir() + "/testVeryLarge.h3";
FileUtils.delete(fileName);
final MVStore s = new MVStore.Builder().
fileName(fileName).
open();
MVMap<Long, byte[]> map = s.openMap("data");
final AtomicInteger count = new AtomicInteger();
StreamStore streamStore = new StreamStore(map) {
@Override
protected void onStore(int len) {
count.incrementAndGet();
s.store();
}
};
long size = 1 * 1024 * 1024;
streamStore.put(new RandomStream(size, 0));
s.store();
s.close();
assertEquals(4, count.get());
}
/**
* A stream of incompressible data.
*/
static class RandomStream extends InputStream {
private long pos, size;
private int seed;
RandomStream(long size, int seed) {
this.size = size;
this.seed = seed;
}
public int read() {
byte[] data = new byte[1];
int len = read(data, 0, 1);
return len <= 0 ? len : data[0] & 255;
}
public int read(byte[] b, int off, int len) {
if (pos >= size) {
return -1;
}
len = (int) Math.min(size - pos, len);
int x = seed, end = off + len;
// a very simple pseudo-random number generator
// with a period length of 4 GB
// also good: x * 9 + 1, shift 6; x * 11 + 1, shift 7
while (off < end) {
x = (x << 4) + x + 1;
b[off++] = (byte) (x >> 8);
}
seed = x;
pos += len;
return len;
}
}
private void testDetectIllegalId() throws IOException {
Map<Long, byte[]> map = New.hashMap();
StreamStore store = new StreamStore(map);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论