提交 23cd2f75 authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore changes: abstract storage to support off-heap storage; rename getSize to…

MVStore changes: abstract storage to support off-heap storage; rename getSize to sizeAsLong; avoid importing java.beans package to speed up starting the JVM
上级 380b76a5
...@@ -232,12 +232,12 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex { ...@@ -232,12 +232,12 @@ public class SpatialTreeIndex extends BaseIndex implements SpatialIndex {
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
return treeMap.getSize(); return treeMap.sizeAsLong();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
return treeMap.getSize(); return treeMap.sizeAsLong();
} }
@Override @Override
......
...@@ -11,6 +11,7 @@ import java.io.IOException; ...@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -121,6 +122,11 @@ public class DataUtils { ...@@ -121,6 +122,11 @@ public class DataUtils {
* The estimated number of bytes used per child entry. * The estimated number of bytes used per child entry.
*/ */
public static final int PAGE_MEMORY_CHILD = 16; public static final int PAGE_MEMORY_CHILD = 16;
/**
* Name of the character encoding format.
*/
public static final Charset UTF8 = Charset.forName("UTF-8");
/** /**
* An 0-size byte array. * An 0-size byte array.
...@@ -131,7 +137,7 @@ public class DataUtils { ...@@ -131,7 +137,7 @@ public class DataUtils {
* The maximum byte to grow a buffer at a time. * The maximum byte to grow a buffer at a time.
*/ */
private static final int MAX_GROW = 16 * 1024 * 1024; private static final int MAX_GROW = 16 * 1024 * 1024;
/** /**
* Get the length of the variable size int. * Get the length of the variable size int.
* *
...@@ -731,7 +737,7 @@ public class DataUtils { ...@@ -731,7 +737,7 @@ public class DataUtils {
* @return the error code, or 0 if none * @return the error code, or 0 if none
*/ */
public static int getErrorCode(String m) { public static int getErrorCode(String m) {
if (m.endsWith("]")) { if (m != null && m.endsWith("]")) {
int dash = m.lastIndexOf('/'); int dash = m.lastIndexOf('/');
if (dash >= 0) { if (dash >= 0) {
String s = m.substring(dash + 1, m.length() - 1); String s = m.substring(dash + 1, m.length() - 1);
...@@ -797,4 +803,43 @@ public class DataUtils { ...@@ -797,4 +803,43 @@ public class DataUtils {
return temp; return temp;
} }
/**
* Parse a string as a number.
*
* @param x the number
* @param defaultValue if x is null
* @return the parsed value
* @throws IllegalStateException if parsing fails
*/
public static long parseLong(String x, long defaultValue) {
if (x == null) {
return defaultValue;
}
try {
return Long.parseLong(x);
} catch (NumberFormatException e) {
throw newIllegalStateException(ERROR_FILE_CORRUPT,
"Error parsing the value {0} as a long", x, e);
}
}
/**
* Try to parse a string as a number.
*
* @param x the number
* @param defaultValue if x is null
* @param errorValue if parsing fails
* @return the parsed value if parsing is possible
*/
public static long parseLong(String x, long defaultValue, long errorValue) {
if (x == null) {
return defaultValue;
}
try {
return Long.parseLong(x);
} catch (NumberFormatException e) {
return errorValue;
}
}
} }
/*
* Copyright 2004-2013 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.mvstore;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import org.h2.mvstore.cache.FilePathCache;
import org.h2.store.fs.FilePath;
import org.h2.store.fs.FilePathCrypt;
import org.h2.store.fs.FilePathNio;
/**
* The storage mechanism of the MVStore.
*/
public class FileStore {
private final String fileName;
private boolean readOnly;
private FileChannel file;
private FileLock fileLock;
private long fileSize;
private long readCount;
private long writeCount;
public FileStore(String fileName, boolean readOnly) {
if (fileName != null && fileName.indexOf(':') < 0) {
// NIO is used, unless a different file system is specified
// the following line is to ensure the NIO file system is compiled
FilePathNio.class.getName();
fileName = "nio:" + fileName;
}
this.fileName = fileName;
this.readOnly = readOnly;
}
@Override
public String toString() {
return fileName;
}
public void readFully(long pos, ByteBuffer dst) {
readCount++;
DataUtils.readFully(file, pos, dst);
}
public void writeFully(long pos, ByteBuffer src) {
writeCount++;
fileSize = Math.max(fileSize, pos + src.remaining());
DataUtils.writeFully(file, pos, src);
}
/**
* Mark the space within the file as unused.
*
* @param pos
* @param length
*/
public void free(long pos, int length) {
}
public void open(char[] encryptionKey) {
FilePath f = FilePath.get(fileName);
FilePath parent = f.getParent();
if (!parent.exists()) {
throw DataUtils.newIllegalArgumentException("Directory does not exist: {0}", parent);
}
if (f.exists() && !f.canWrite()) {
readOnly = true;
}
try {
file = f.open(readOnly ? "r" : "rw");
if (encryptionKey != null) {
byte[] password = FilePathCrypt.getPasswordBytes(encryptionKey);
file = new FilePathCrypt.FileCrypt(fileName, password, file);
}
file = FilePathCache.wrap(file);
fileSize = file.size();
try {
if (readOnly) {
fileLock = file.tryLock(0, Long.MAX_VALUE, true);
} else {
fileLock = file.tryLock();
}
} catch (OverlappingFileLockException e) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_LOCKED, "The file is locked: {0}", fileName, e);
}
if (fileLock == null) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_LOCKED, "The file is locked: {0}", fileName);
}
} catch (IOException e) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_READING_FAILED,
"Could not open file {0}", fileName, e);
}
}
public void close() {
try {
if (fileLock != null) {
fileLock.release();
fileLock = null;
}
file.close();
} catch (Exception e) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_WRITING_FAILED,
"Closing failed for file {0}", fileName, e);
} finally {
file = null;
}
}
public void sync() {
try {
file.force(true);
} catch (IOException e) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_WRITING_FAILED,
"Could not sync file {0}", fileName, e);
}
}
public long size() {
return fileSize;
}
public void truncate(long size) {
try {
file.truncate(size);
fileSize = Math.min(fileSize, size);
} catch (IOException e) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_WRITING_FAILED,
"Could not truncate file {0} to size {1}",
fileName, size, e);
}
}
/**
* Get the file instance in use. The application may read from the file (for
* example for online backup), but not write to it or truncate it.
*
* @return the file
*/
public FileChannel getFile() {
return file;
}
/**
* Get the number of write operations since this store was opened.
* For file based stores, this is the number of file write operations.
*
* @return the number of write operations
*/
public long getWriteCount() {
return writeCount;
}
/**
* Get the number of read operations since this store was opened.
* For file based stores, this is the number of file read operations.
*
* @return the number of read operations
*/
public long getReadCount() {
return readCount;
}
public boolean isReadOnly() {
return readOnly;
}
}
...@@ -982,11 +982,27 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -982,11 +982,27 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return this == o; return this == o;
} }
/**
* Get the number of entries, as a integer. Integer.MAX_VALUE is returned if
* there are more than this entries.
*
* @return the number of entries, as an integer
*/
@Override @Override
public int size() { public int size() {
long size = getSize(); long size = sizeAsLong();
return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) size; return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) size;
} }
/**
* Get the number of entries, as a long.
*
* @return the number of entries
*/
public long sizeAsLong() {
checkOpen();
return root.getTotalCount();
}
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
...@@ -994,11 +1010,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -994,11 +1010,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return 0 == (root.isLeaf() ? root.getKeyCount() : root.getChildPageCount()); return 0 == (root.isLeaf() ? root.getKeyCount() : root.getChildPageCount());
} }
public long getSize() {
checkOpen();
return root.getTotalCount();
}
public long getCreateVersion() { public long getCreateVersion() {
return createVersion; return createVersion;
} }
...@@ -1033,7 +1044,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1033,7 +1044,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
(version == writeVersion || (version == writeVersion ||
r.getVersion() >= 0 || r.getVersion() >= 0 ||
version <= createVersion || version <= createVersion ||
store.getFile() == null)) { store.getFileStore() == null)) {
newest = r; newest = r;
} else { } else {
// find the newest page that has a getVersion() <= version // find the newest page that has a getVersion() <= version
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
package org.h2.mvstore; package org.h2.mvstore;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays; import java.util.Arrays;
import org.h2.compress.Compressor; import org.h2.compress.Compressor;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
...@@ -163,7 +162,7 @@ public class Page { ...@@ -163,7 +162,7 @@ public class Page {
* @param fileSize the file size (to avoid reading past EOF) * @param fileSize the file size (to avoid reading past EOF)
* @return the page * @return the page
*/ */
static Page read(FileChannel file, MVMap<?, ?> map, static Page read(FileStore fileStore, MVMap<?, ?> map,
long pos, long filePos, long fileSize) { long pos, long filePos, long fileSize) {
ByteBuffer buff; ByteBuffer buff;
int maxLength = DataUtils.getPageMaxLength(pos); int maxLength = DataUtils.getPageMaxLength(pos);
...@@ -171,12 +170,12 @@ public class Page { ...@@ -171,12 +170,12 @@ public class Page {
int length = maxLength; int length = maxLength;
if (maxLength == Integer.MAX_VALUE) { if (maxLength == Integer.MAX_VALUE) {
buff = ByteBuffer.allocate(128); buff = ByteBuffer.allocate(128);
DataUtils.readFully(file, filePos, buff); fileStore.readFully(filePos, buff);
maxLength = buff.getInt(); maxLength = buff.getInt();
//read the first bytes again //read the first bytes again
} }
buff = ByteBuffer.allocate(length); buff = ByteBuffer.allocate(length);
DataUtils.readFully(file, filePos, buff); fileStore.readFully(filePos, buff);
Page p = new Page(map, 0); Page p = new Page(map, 0);
p.pos = pos; p.pos = pos;
int chunkId = DataUtils.getPageChunkId(pos); int chunkId = DataUtils.getPageChunkId(pos);
......
...@@ -198,7 +198,7 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -198,7 +198,7 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try { try {
long cost = 10 * (dataMap.map.getSize() + Constants.COST_ROW_OFFSET); long cost = 10 * (dataMap.map.sizeAsLong() + Constants.COST_ROW_OFFSET);
return cost; return cost;
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
...@@ -256,13 +256,13 @@ public class MVPrimaryIndex extends BaseIndex { ...@@ -256,13 +256,13 @@ public class MVPrimaryIndex extends BaseIndex {
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return map.getSize(); return map.sizeAsLong();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
try { try {
return dataMap.map.getSize(); return dataMap.map.sizeAsLong();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
} }
......
...@@ -165,7 +165,7 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -165,7 +165,7 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) { public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try { try {
return 10 * getCostRangeIndex(masks, dataMap.map.getSize(), filter, sortOrder); return 10 * getCostRangeIndex(masks, dataMap.map.sizeAsLong(), filter, sortOrder);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
} }
...@@ -213,7 +213,7 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -213,7 +213,7 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public boolean needRebuild() { public boolean needRebuild() {
try { try {
return dataMap.map.getSize() == 0; return dataMap.map.sizeAsLong() == 0;
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
} }
...@@ -222,13 +222,13 @@ public class MVSecondaryIndex extends BaseIndex { ...@@ -222,13 +222,13 @@ public class MVSecondaryIndex extends BaseIndex {
@Override @Override
public long getRowCount(Session session) { public long getRowCount(Session session) {
TransactionMap<Value, Value> map = getMap(session); TransactionMap<Value, Value> map = getMap(session);
return map.getSize(); return map.sizeAsLong();
} }
@Override @Override
public long getRowCountApproximation() { public long getRowCountApproximation() {
try { try {
return dataMap.map.getSize(); return dataMap.map.sizeAsLong();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED); throw DbException.get(ErrorCode.OBJECT_CLOSED);
} }
......
...@@ -6,9 +6,8 @@ ...@@ -6,9 +6,8 @@
*/ */
package org.h2.mvstore.db; package org.h2.mvstore.db;
import java.beans.ExceptionListener;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
...@@ -72,10 +71,10 @@ public class MVTableEngine implements TableEngine { ...@@ -72,10 +71,10 @@ public class MVTableEngine implements TableEngine {
} }
builder.encryptionKey(password); builder.encryptionKey(password);
} }
builder.backgroundExceptionListener(new ExceptionListener() { builder.backgroundExceptionHandler(new UncaughtExceptionHandler() {
@Override @Override
public void exceptionThrown(Exception e) { public void uncaughtException(Thread t, Throwable e) {
db.setBackgroundException(DbException.convert(e)); db.setBackgroundException(DbException.convert(e));
} }
...@@ -168,7 +167,7 @@ public class MVTableEngine implements TableEngine { ...@@ -168,7 +167,7 @@ public class MVTableEngine implements TableEngine {
* Store all pending changes. * Store all pending changes.
*/ */
public void store() { public void store() {
if (store.isReadOnly()) { if (store.getFileStore().isReadOnly()) {
return; return;
} }
store.commit(); store.commit();
...@@ -230,7 +229,7 @@ public class MVTableEngine implements TableEngine { ...@@ -230,7 +229,7 @@ public class MVTableEngine implements TableEngine {
} }
public InputStream getInputStream() { public InputStream getInputStream() {
return new FileChannelInputStream(store.getFile(), false); return new FileChannelInputStream(store.getFileStore().getFile(), false);
} }
/** /**
...@@ -238,11 +237,7 @@ public class MVTableEngine implements TableEngine { ...@@ -238,11 +237,7 @@ public class MVTableEngine implements TableEngine {
*/ */
public void sync() { public void sync() {
store(); store();
try { store.sync();
store.getFile().force(true);
} catch (IOException e) {
throw DbException.convertIOException(e, "Could not sync");
}
} }
/** /**
...@@ -257,7 +252,7 @@ public class MVTableEngine implements TableEngine { ...@@ -257,7 +252,7 @@ public class MVTableEngine implements TableEngine {
store.setRetentionTime(0); store.setRetentionTime(0);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
while (store.compact(90)) { while (store.compact(90)) {
store.syncFile(); store.sync();
long time = System.currentTimeMillis() - start; long time = System.currentTimeMillis() - start;
if (time > maxCompactTime) { if (time > maxCompactTime) {
break; break;
...@@ -275,7 +270,7 @@ public class MVTableEngine implements TableEngine { ...@@ -275,7 +270,7 @@ public class MVTableEngine implements TableEngine {
*/ */
public void close(long maxCompactTime) { public void close(long maxCompactTime) {
if (!store.isClosed()) { if (!store.isClosed()) {
if (!store.isReadOnly()) { if (!store.getFileStore().isReadOnly()) {
store.store(); store.store();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
while (store.compact(90)) { while (store.compact(90)) {
......
...@@ -111,10 +111,8 @@ public class TransactionStore { ...@@ -111,10 +111,8 @@ public class TransactionStore {
private synchronized void init() { private synchronized void init() {
String s = settings.get(LAST_TRANSACTION_ID); String s = settings.get(LAST_TRANSACTION_ID);
if (s != null) { lastTransactionId = DataUtils.parseLong(s, 0);
lastTransactionId = Long.parseLong(s); lastTransactionIdStored = lastTransactionId;
lastTransactionIdStored = lastTransactionId;
}
Long lastKey = preparedTransactions.lastKey(); Long lastKey = preparedTransactions.lastKey();
if (lastKey != null && lastKey.longValue() > lastTransactionId) { if (lastKey != null && lastKey.longValue() > lastTransactionId) {
throw DataUtils.newIllegalStateException( throw DataUtils.newIllegalStateException(
...@@ -789,7 +787,7 @@ public class TransactionStore { ...@@ -789,7 +787,7 @@ public class TransactionStore {
* *
* @return the size * @return the size
*/ */
public long getSize() { public long sizeAsLong() {
// TODO this method is very slow // TODO this method is very slow
long size = 0; long size = 0;
Cursor<K> cursor = map.keyIterator(null); Cursor<K> cursor = map.keyIterator(null);
......
...@@ -14,12 +14,10 @@ import java.sql.ResultSetMetaData; ...@@ -14,12 +14,10 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
import org.h2.store.Data;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.LobStorageFrontend; import org.h2.store.LobStorageFrontend;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
...@@ -155,7 +153,6 @@ public class ValueDataType implements DataType { ...@@ -155,7 +153,6 @@ public class ValueDataType implements DataType {
} }
private ByteBuffer writeValue(ByteBuffer buff, Value v) { private ByteBuffer writeValue(ByteBuffer buff, Value v) {
int start = buff.position();
if (v == ValueNull.INSTANCE) { if (v == ValueNull.INSTANCE) {
buff.put((byte) 0); buff.put((byte) 0);
return buff; return buff;
...@@ -426,12 +423,6 @@ public class ValueDataType implements DataType { ...@@ -426,12 +423,6 @@ public class ValueDataType implements DataType {
default: default:
DbException.throwInternalError("type=" + v.getType()); DbException.throwInternalError("type=" + v.getType());
} }
if (SysProperties.CHECK2) {
if (buff.position() - start != Data.getValueLen(v, handler)) {
throw DbException
.throwInternalError("value size error: got " + (buff.position() - start) + " expected " + Data.getValueLen(v, handler));
}
}
return buff; return buff;
} }
......
...@@ -121,7 +121,7 @@ public class TestConcurrent extends TestMVStore { ...@@ -121,7 +121,7 @@ public class TestConcurrent extends TestMVStore {
s.store(); s.store();
map.clear(); map.clear();
s.store(); s.store();
long len = s.getFile().size(); long len = s.getFileStore().size();
if (len > 1024 * 1024) { if (len > 1024 * 1024) {
// slow down writing a lot // slow down writing a lot
Thread.sleep(200); Thread.sleep(200);
...@@ -136,7 +136,7 @@ public class TestConcurrent extends TestMVStore { ...@@ -136,7 +136,7 @@ public class TestConcurrent extends TestMVStore {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
// System.out.println("test " + i); // System.out.println("test " + i);
s.setReuseSpace(false); s.setReuseSpace(false);
byte[] buff = readFileSlowly(s.getFile(), s.getFile().size()); byte[] buff = readFileSlowly(s.getFileStore().getFile(), s.getFileStore().size());
s.setReuseSpace(true); s.setReuseSpace(true);
FileOutputStream out = new FileOutputStream(fileNameRestore); FileOutputStream out = new FileOutputStream(fileNameRestore);
out.write(buff); out.write(buff);
......
...@@ -5,8 +5,7 @@ ...@@ -5,8 +5,7 @@
*/ */
package org.h2.test.store; package org.h2.test.store;
import java.beans.ExceptionListener; import java.lang.Thread.UncaughtExceptionHandler;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.Iterator; import java.util.Iterator;
...@@ -96,13 +95,11 @@ public class TestMVStore extends TestBase { ...@@ -96,13 +95,11 @@ public class TestMVStore extends TestBase {
private void testNewerWriteVersion() throws Exception { private void testNewerWriteVersion() throws Exception {
String fileName = getBaseDir() + "/testNewerWriteVersion.h3"; String fileName = getBaseDir() + "/testNewerWriteVersion.h3";
FileUtils.delete(fileName); FileUtils.delete(fileName);
char[] passwordChars;
passwordChars = "007".toCharArray();
MVStore s = new MVStore.Builder(). MVStore s = new MVStore.Builder().
encryptionKey(passwordChars). encryptionKey("007".toCharArray()).
fileName(fileName). fileName(fileName).
open(); open();
Map<String, String> header = s.getFileHeader(); Map<String, String> header = s.getStoreHeader();
assertEquals("1", header.get("format")); assertEquals("1", header.get("format"));
header.put("formatRead", "1"); header.put("formatRead", "1");
header.put("format", "2"); header.put("format", "2");
...@@ -111,15 +108,36 @@ public class TestMVStore extends TestBase { ...@@ -111,15 +108,36 @@ public class TestMVStore extends TestBase {
s.store(); s.store();
s.close(); s.close();
passwordChars = "007".toCharArray(); try {
s = new MVStore.Builder().
encryptionKey("007".toCharArray()).
fileName(fileName).
open();
fail();
} catch (IllegalStateException e) {
assertEquals(DataUtils.ERROR_UNSUPPORTED_FORMAT,
DataUtils.getErrorCode(e.getMessage()));
}
s = new MVStore.Builder(). s = new MVStore.Builder().
encryptionKey(passwordChars). encryptionKey("007".toCharArray()).
readOnly().
fileName(fileName).
open();
assertTrue(s.getFileStore().isReadOnly());
m = s.openMap("data");
assertEquals("Hello World", m.get(0));
s.close();
FileUtils.setReadOnly(fileName);
s = new MVStore.Builder().
encryptionKey("007".toCharArray()).
fileName(fileName). fileName(fileName).
open(); open();
assertTrue(s.isReadOnly()); assertTrue(s.getFileStore().isReadOnly());
m = s.openMap("data"); m = s.openMap("data");
assertEquals("Hello World", m.get(0)); assertEquals("Hello World", m.get(0));
s.close(); s.close();
} }
private void testCompactFully() throws Exception { private void testCompactFully() throws Exception {
...@@ -139,9 +157,9 @@ public class TestMVStore extends TestBase { ...@@ -139,9 +157,9 @@ public class TestMVStore extends TestBase {
m.removeMap(); m.removeMap();
s.store(); s.store();
} }
long sizeOld = s.getFile().size(); long sizeOld = s.getFileStore().size();
s.compactMoveChunks(); s.compactMoveChunks();
long sizeNew = s.getFile().size(); long sizeNew = s.getFileStore().size();
assertTrue("old: " + sizeOld + " new: " + sizeNew, sizeNew < sizeOld); assertTrue("old: " + sizeOld + " new: " + sizeNew, sizeNew < sizeOld);
s.close(); s.close();
} }
...@@ -150,13 +168,13 @@ public class TestMVStore extends TestBase { ...@@ -150,13 +168,13 @@ public class TestMVStore extends TestBase {
String fileName = getBaseDir() + "/testBackgroundExceptionListener.h3"; String fileName = getBaseDir() + "/testBackgroundExceptionListener.h3";
FileUtils.delete(fileName); FileUtils.delete(fileName);
MVStore s; MVStore s;
final AtomicReference<Exception> exRef = new AtomicReference<Exception>(); final AtomicReference<Throwable> exRef = new AtomicReference<Throwable>();
s = new MVStore.Builder(). s = new MVStore.Builder().
fileName(fileName). fileName(fileName).
backgroundExceptionListener(new ExceptionListener() { backgroundExceptionHandler(new UncaughtExceptionHandler() {
@Override @Override
public void exceptionThrown(Exception e) { public void uncaughtException(Thread t, Throwable e) {
exRef.set(e); exRef.set(e);
} }
...@@ -165,7 +183,7 @@ public class TestMVStore extends TestBase { ...@@ -165,7 +183,7 @@ public class TestMVStore extends TestBase {
s.setWriteDelay(2); s.setWriteDelay(2);
MVMap<Integer, String> m; MVMap<Integer, String> m;
m = s.openMap("data"); m = s.openMap("data");
s.getFile().close(); s.getFileStore().getFile().close();
m.put(1, "Hello"); m.put(1, "Hello");
s.commit(); s.commit();
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
...@@ -174,7 +192,7 @@ public class TestMVStore extends TestBase { ...@@ -174,7 +192,7 @@ public class TestMVStore extends TestBase {
} }
Thread.sleep(1); Thread.sleep(1);
} }
Exception e = exRef.get(); Throwable e = exRef.get();
assertTrue(e != null); assertTrue(e != null);
assertEquals(DataUtils.ERROR_WRITING_FAILED, DataUtils.getErrorCode(e.getMessage())); assertEquals(DataUtils.ERROR_WRITING_FAILED, DataUtils.getErrorCode(e.getMessage()));
...@@ -217,7 +235,7 @@ public class TestMVStore extends TestBase { ...@@ -217,7 +235,7 @@ public class TestMVStore extends TestBase {
FileUtils.delete(fileName); FileUtils.delete(fileName);
} }
private void testWriteBuffer() throws IOException { private void testWriteBuffer() {
String fileName = getBaseDir() + "/testWriteBuffer.h3"; String fileName = getBaseDir() + "/testWriteBuffer.h3";
FileUtils.delete(fileName); FileUtils.delete(fileName);
MVStore s; MVStore s;
...@@ -234,7 +252,7 @@ public class TestMVStore extends TestBase { ...@@ -234,7 +252,7 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
m.put(i, data); m.put(i, data);
} }
long size = s.getFile().size(); long size = s.getFileStore().size();
assertTrue("last:" + lastSize + " now: " + size, size > lastSize); assertTrue("last:" + lastSize + " now: " + size, size > lastSize);
lastSize = size; lastSize = size;
s.close(); s.close();
...@@ -379,7 +397,7 @@ public class TestMVStore extends TestBase { ...@@ -379,7 +397,7 @@ public class TestMVStore extends TestBase {
s = new MVStore.Builder(). s = new MVStore.Builder().
fileName(fileName). fileName(fileName).
encryptionKey(passwordChars).open(); encryptionKey(passwordChars).open();
assertTrue(s.isReadOnly()); assertTrue(s.getFileStore().isReadOnly());
FileUtils.delete(fileName); FileUtils.delete(fileName);
assertFalse(FileUtils.exists(fileName)); assertFalse(FileUtils.exists(fileName));
...@@ -393,7 +411,7 @@ public class TestMVStore extends TestBase { ...@@ -393,7 +411,7 @@ public class TestMVStore extends TestBase {
s = openStore(fileName); s = openStore(fileName);
m = s.openMap("test"); m = s.openMap("test");
m.put(1, 1); m.put(1, 1);
Map<String, String> header = s.getFileHeader(); Map<String, String> header = s.getStoreHeader();
int format = Integer.parseInt(header.get("format")); int format = Integer.parseInt(header.get("format"));
assertEquals(1, format); assertEquals(1, format);
header.put("format", Integer.toString(format + 1)); header.put("format", Integer.toString(format + 1));
...@@ -483,7 +501,7 @@ public class TestMVStore extends TestBase { ...@@ -483,7 +501,7 @@ public class TestMVStore extends TestBase {
} }
} }
assertEquals(expectedReadsForCacheSize[cacheSize], assertEquals(expectedReadsForCacheSize[cacheSize],
s.getFileReadCount()); s.getFileStore().getReadCount());
s.close(); s.close();
} }
...@@ -506,10 +524,10 @@ public class TestMVStore extends TestBase { ...@@ -506,10 +524,10 @@ public class TestMVStore extends TestBase {
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
// expected // expected
} }
assertFalse(s.isReadOnly()); assertFalse(s.getFileStore().isReadOnly());
s.close(); s.close();
s = new MVStore.Builder().fileName(fileName).readOnly().open(); s = new MVStore.Builder().fileName(fileName).readOnly().open();
assertTrue(s.isReadOnly()); assertTrue(s.getFileStore().isReadOnly());
s.close(); s.close();
} }
...@@ -517,17 +535,17 @@ public class TestMVStore extends TestBase { ...@@ -517,17 +535,17 @@ public class TestMVStore extends TestBase {
String fileName = getBaseDir() + "/testFileHeader.h3"; String fileName = getBaseDir() + "/testFileHeader.h3";
MVStore s = openStore(fileName); MVStore s = openStore(fileName);
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
assertEquals("3", s.getFileHeader().get("H")); assertEquals("3", s.getStoreHeader().get("H"));
long creationTime = Long.parseLong(s.getFileHeader() long creationTime = Long.parseLong(s.getStoreHeader()
.get("creationTime")); .get("creationTime"));
assertTrue(Math.abs(time - creationTime) < 100); assertTrue(Math.abs(time - creationTime) < 100);
s.getFileHeader().put("test", "123"); s.getStoreHeader().put("test", "123");
MVMap<Integer, Integer> map = s.openMap("test"); MVMap<Integer, Integer> map = s.openMap("test");
map.put(10, 100); map.put(10, 100);
s.store(); s.store();
s.close(); s.close();
s = openStore(fileName); s = openStore(fileName);
assertEquals("123", s.getFileHeader().get("test")); assertEquals("123", s.getStoreHeader().get("test"));
s.close(); s.close();
} }
...@@ -545,7 +563,7 @@ public class TestMVStore extends TestBase { ...@@ -545,7 +563,7 @@ public class TestMVStore extends TestBase {
s.compact(50); s.compact(50);
map.put(10, 100); map.put(10, 100);
s.store(); s.store();
FilePath f = FilePath.get(s.getFileName()); FilePath f = FilePath.get(fileName);
s.close(); s.close();
int blockSize = 4 * 1024; int blockSize = 4 * 1024;
// test corrupt file headers // test corrupt file headers
...@@ -990,7 +1008,7 @@ public class TestMVStore extends TestBase { ...@@ -990,7 +1008,7 @@ public class TestMVStore extends TestBase {
assertEquals(1000, m.size()); assertEquals(1000, m.size());
assertEquals(286, s.getUnsavedPageCount()); assertEquals(286, s.getUnsavedPageCount());
s.store(); s.store();
assertEquals(2, s.getFileWriteCount()); assertEquals(2, s.getFileStore().getWriteCount());
s.close(); s.close();
s = openStore(fileName); s = openStore(fileName);
...@@ -999,8 +1017,8 @@ public class TestMVStore extends TestBase { ...@@ -999,8 +1017,8 @@ public class TestMVStore extends TestBase {
assertEquals(0, m.size()); assertEquals(0, m.size());
s.store(); s.store();
// ensure only nodes are read, but not leaves // ensure only nodes are read, but not leaves
assertEquals(42, s.getFileReadCount()); assertEquals(42, s.getFileStore().getReadCount());
assertEquals(1, s.getFileWriteCount()); assertEquals(1, s.getFileStore().getWriteCount());
s.close(); s.close();
} }
...@@ -1574,7 +1592,7 @@ public class TestMVStore extends TestBase { ...@@ -1574,7 +1592,7 @@ public class TestMVStore extends TestBase {
s.close(); s.close();
} }
private void testLargerThan2G() throws IOException { private void testLargerThan2G() {
if (!config.big) { if (!config.big) {
return; return;
} }
...@@ -1592,7 +1610,7 @@ public class TestMVStore extends TestBase { ...@@ -1592,7 +1610,7 @@ public class TestMVStore extends TestBase {
store.setRetainVersion(version); store.setRetainVersion(version);
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
if (time - last > 2000) { if (time - last > 2000) {
long mb = store.getFile().size() / 1024 / 1024; long mb = store.getFileStore().size() / 1024 / 1024;
trace(mb + "/4500"); trace(mb + "/4500");
if (mb > 4500) { if (mb > 4500) {
break; break;
......
...@@ -530,7 +530,7 @@ public class TestMVTableEngine extends TestBase { ...@@ -530,7 +530,7 @@ public class TestMVTableEngine extends TestBase {
FileUtils.setReadOnly(getBaseDir() + "/mvstore.h2.db"); FileUtils.setReadOnly(getBaseDir() + "/mvstore.h2.db");
conn = getConnection(dbName); conn = getConnection(dbName);
Database db = (Database) ((JdbcConnection) conn).getSession().getDataHandler(); Database db = (Database) ((JdbcConnection) conn).getSession().getDataHandler();
assertTrue(db.getMvStore().getStore().isReadOnly()); assertTrue(db.getMvStore().getStore().getFileStore().isReadOnly());
conn.close(); conn.close();
FileUtils.deleteRecursive(getBaseDir(), true); FileUtils.deleteRecursive(getBaseDir(), true);
} }
......
...@@ -487,8 +487,8 @@ public class TestTransactionStore extends TestBase { ...@@ -487,8 +487,8 @@ public class TestTransactionStore extends TestBase {
size++; size++;
} }
buff.append('\n'); buff.append('\n');
if (size != map.getSize()) { if (size != map.sizeAsLong()) {
assertEquals(size, map.getSize()); assertEquals(size, map.sizeAsLong());
} }
} }
int x = r.nextInt(rowCount); int x = r.nextInt(rowCount);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论