提交 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 {
@Override
public long getRowCount(Session session) {
return treeMap.getSize();
return treeMap.sizeAsLong();
}
@Override
public long getRowCountApproximation() {
return treeMap.getSize();
return treeMap.sizeAsLong();
}
@Override
......
......@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
......@@ -122,6 +123,11 @@ public class DataUtils {
*/
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.
*/
......@@ -731,7 +737,7 @@ public class DataUtils {
* @return the error code, or 0 if none
*/
public static int getErrorCode(String m) {
if (m.endsWith("]")) {
if (m != null && m.endsWith("]")) {
int dash = m.lastIndexOf('/');
if (dash >= 0) {
String s = m.substring(dash + 1, m.length() - 1);
......@@ -797,4 +803,43 @@ public class DataUtils {
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,21 +982,32 @@ public class MVMap<K, V> extends AbstractMap<K, V>
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
public int size() {
long size = getSize();
long size = sizeAsLong();
return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) size;
}
@Override
public boolean isEmpty() {
/**
* Get the number of entries, as a long.
*
* @return the number of entries
*/
public long sizeAsLong() {
checkOpen();
return 0 == (root.isLeaf() ? root.getKeyCount() : root.getChildPageCount());
return root.getTotalCount();
}
public long getSize() {
@Override
public boolean isEmpty() {
checkOpen();
return root.getTotalCount();
return 0 == (root.isLeaf() ? root.getKeyCount() : root.getChildPageCount());
}
public long getCreateVersion() {
......@@ -1033,7 +1044,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
(version == writeVersion ||
r.getVersion() >= 0 ||
version <= createVersion ||
store.getFile() == null)) {
store.getFileStore() == null)) {
newest = r;
} else {
// find the newest page that has a getVersion() <= version
......
......@@ -7,7 +7,6 @@
package org.h2.mvstore;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import org.h2.compress.Compressor;
import org.h2.mvstore.type.DataType;
......@@ -163,7 +162,7 @@ public class Page {
* @param fileSize the file size (to avoid reading past EOF)
* @return the page
*/
static Page read(FileChannel file, MVMap<?, ?> map,
static Page read(FileStore fileStore, MVMap<?, ?> map,
long pos, long filePos, long fileSize) {
ByteBuffer buff;
int maxLength = DataUtils.getPageMaxLength(pos);
......@@ -171,12 +170,12 @@ public class Page {
int length = maxLength;
if (maxLength == Integer.MAX_VALUE) {
buff = ByteBuffer.allocate(128);
DataUtils.readFully(file, filePos, buff);
fileStore.readFully(filePos, buff);
maxLength = buff.getInt();
//read the first bytes again
}
buff = ByteBuffer.allocate(length);
DataUtils.readFully(file, filePos, buff);
fileStore.readFully(filePos, buff);
Page p = new Page(map, 0);
p.pos = pos;
int chunkId = DataUtils.getPageChunkId(pos);
......
......@@ -198,7 +198,7 @@ public class MVPrimaryIndex extends BaseIndex {
@Override
public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try {
long cost = 10 * (dataMap.map.getSize() + Constants.COST_ROW_OFFSET);
long cost = 10 * (dataMap.map.sizeAsLong() + Constants.COST_ROW_OFFSET);
return cost;
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
......@@ -256,13 +256,13 @@ public class MVPrimaryIndex extends BaseIndex {
@Override
public long getRowCount(Session session) {
TransactionMap<Value, Value> map = getMap(session);
return map.getSize();
return map.sizeAsLong();
}
@Override
public long getRowCountApproximation() {
try {
return dataMap.map.getSize();
return dataMap.map.sizeAsLong();
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
......
......@@ -165,7 +165,7 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public double getCost(Session session, int[] masks, TableFilter filter, SortOrder sortOrder) {
try {
return 10 * getCostRangeIndex(masks, dataMap.map.getSize(), filter, sortOrder);
return 10 * getCostRangeIndex(masks, dataMap.map.sizeAsLong(), filter, sortOrder);
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
......@@ -213,7 +213,7 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public boolean needRebuild() {
try {
return dataMap.map.getSize() == 0;
return dataMap.map.sizeAsLong() == 0;
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
......@@ -222,13 +222,13 @@ public class MVSecondaryIndex extends BaseIndex {
@Override
public long getRowCount(Session session) {
TransactionMap<Value, Value> map = getMap(session);
return map.getSize();
return map.sizeAsLong();
}
@Override
public long getRowCountApproximation() {
try {
return dataMap.map.getSize();
return dataMap.map.sizeAsLong();
} catch (IllegalStateException e) {
throw DbException.get(ErrorCode.OBJECT_CLOSED);
}
......
......@@ -6,9 +6,8 @@
*/
package org.h2.mvstore.db;
import java.beans.ExceptionListener;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.List;
......@@ -72,10 +71,10 @@ public class MVTableEngine implements TableEngine {
}
builder.encryptionKey(password);
}
builder.backgroundExceptionListener(new ExceptionListener() {
builder.backgroundExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void exceptionThrown(Exception e) {
public void uncaughtException(Thread t, Throwable e) {
db.setBackgroundException(DbException.convert(e));
}
......@@ -168,7 +167,7 @@ public class MVTableEngine implements TableEngine {
* Store all pending changes.
*/
public void store() {
if (store.isReadOnly()) {
if (store.getFileStore().isReadOnly()) {
return;
}
store.commit();
......@@ -230,7 +229,7 @@ public class MVTableEngine implements TableEngine {
}
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 {
*/
public void sync() {
store();
try {
store.getFile().force(true);
} catch (IOException e) {
throw DbException.convertIOException(e, "Could not sync");
}
store.sync();
}
/**
......@@ -257,7 +252,7 @@ public class MVTableEngine implements TableEngine {
store.setRetentionTime(0);
long start = System.currentTimeMillis();
while (store.compact(90)) {
store.syncFile();
store.sync();
long time = System.currentTimeMillis() - start;
if (time > maxCompactTime) {
break;
......@@ -275,7 +270,7 @@ public class MVTableEngine implements TableEngine {
*/
public void close(long maxCompactTime) {
if (!store.isClosed()) {
if (!store.isReadOnly()) {
if (!store.getFileStore().isReadOnly()) {
store.store();
long start = System.currentTimeMillis();
while (store.compact(90)) {
......
......@@ -111,10 +111,8 @@ public class TransactionStore {
private synchronized void init() {
String s = settings.get(LAST_TRANSACTION_ID);
if (s != null) {
lastTransactionId = Long.parseLong(s);
lastTransactionId = DataUtils.parseLong(s, 0);
lastTransactionIdStored = lastTransactionId;
}
Long lastKey = preparedTransactions.lastKey();
if (lastKey != null && lastKey.longValue() > lastTransactionId) {
throw DataUtils.newIllegalStateException(
......@@ -789,7 +787,7 @@ public class TransactionStore {
*
* @return the size
*/
public long getSize() {
public long sizeAsLong() {
// TODO this method is very slow
long size = 0;
Cursor<K> cursor = map.keyIterator(null);
......
......@@ -14,12 +14,10 @@ import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.message.DbException;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.type.DataType;
import org.h2.result.SortOrder;
import org.h2.store.Data;
import org.h2.store.DataHandler;
import org.h2.store.LobStorageFrontend;
import org.h2.tools.SimpleResultSet;
......@@ -155,7 +153,6 @@ public class ValueDataType implements DataType {
}
private ByteBuffer writeValue(ByteBuffer buff, Value v) {
int start = buff.position();
if (v == ValueNull.INSTANCE) {
buff.put((byte) 0);
return buff;
......@@ -426,12 +423,6 @@ public class ValueDataType implements DataType {
default:
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;
}
......
......@@ -121,7 +121,7 @@ public class TestConcurrent extends TestMVStore {
s.store();
map.clear();
s.store();
long len = s.getFile().size();
long len = s.getFileStore().size();
if (len > 1024 * 1024) {
// slow down writing a lot
Thread.sleep(200);
......@@ -136,7 +136,7 @@ public class TestConcurrent extends TestMVStore {
for (int i = 0; i < 10; i++) {
// System.out.println("test " + i);
s.setReuseSpace(false);
byte[] buff = readFileSlowly(s.getFile(), s.getFile().size());
byte[] buff = readFileSlowly(s.getFileStore().getFile(), s.getFileStore().size());
s.setReuseSpace(true);
FileOutputStream out = new FileOutputStream(fileNameRestore);
out.write(buff);
......
......@@ -5,8 +5,7 @@
*/
package org.h2.test.store;
import java.beans.ExceptionListener;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
......@@ -96,13 +95,11 @@ public class TestMVStore extends TestBase {
private void testNewerWriteVersion() throws Exception {
String fileName = getBaseDir() + "/testNewerWriteVersion.h3";
FileUtils.delete(fileName);
char[] passwordChars;
passwordChars = "007".toCharArray();
MVStore s = new MVStore.Builder().
encryptionKey(passwordChars).
encryptionKey("007".toCharArray()).
fileName(fileName).
open();
Map<String, String> header = s.getFileHeader();
Map<String, String> header = s.getStoreHeader();
assertEquals("1", header.get("format"));
header.put("formatRead", "1");
header.put("format", "2");
......@@ -111,15 +108,36 @@ public class TestMVStore extends TestBase {
s.store();
s.close();
passwordChars = "007".toCharArray();
try {
s = new MVStore.Builder().
encryptionKey(passwordChars).
encryptionKey("007".toCharArray()).
fileName(fileName).
open();
fail();
} catch (IllegalStateException e) {
assertEquals(DataUtils.ERROR_UNSUPPORTED_FORMAT,
DataUtils.getErrorCode(e.getMessage()));
}
s = new MVStore.Builder().
encryptionKey("007".toCharArray()).
readOnly().
fileName(fileName).
open();
assertTrue(s.isReadOnly());
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).
open();
assertTrue(s.getFileStore().isReadOnly());
m = s.openMap("data");
assertEquals("Hello World", m.get(0));
s.close();
}
private void testCompactFully() throws Exception {
......@@ -139,9 +157,9 @@ public class TestMVStore extends TestBase {
m.removeMap();
s.store();
}
long sizeOld = s.getFile().size();
long sizeOld = s.getFileStore().size();
s.compactMoveChunks();
long sizeNew = s.getFile().size();
long sizeNew = s.getFileStore().size();
assertTrue("old: " + sizeOld + " new: " + sizeNew, sizeNew < sizeOld);
s.close();
}
......@@ -150,13 +168,13 @@ public class TestMVStore extends TestBase {
String fileName = getBaseDir() + "/testBackgroundExceptionListener.h3";
FileUtils.delete(fileName);
MVStore s;
final AtomicReference<Exception> exRef = new AtomicReference<Exception>();
final AtomicReference<Throwable> exRef = new AtomicReference<Throwable>();
s = new MVStore.Builder().
fileName(fileName).
backgroundExceptionListener(new ExceptionListener() {
backgroundExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void exceptionThrown(Exception e) {
public void uncaughtException(Thread t, Throwable e) {
exRef.set(e);
}
......@@ -165,7 +183,7 @@ public class TestMVStore extends TestBase {
s.setWriteDelay(2);
MVMap<Integer, String> m;
m = s.openMap("data");
s.getFile().close();
s.getFileStore().getFile().close();
m.put(1, "Hello");
s.commit();
for (int i = 0; i < 100; i++) {
......@@ -174,7 +192,7 @@ public class TestMVStore extends TestBase {
}
Thread.sleep(1);
}
Exception e = exRef.get();
Throwable e = exRef.get();
assertTrue(e != null);
assertEquals(DataUtils.ERROR_WRITING_FAILED, DataUtils.getErrorCode(e.getMessage()));
......@@ -217,7 +235,7 @@ public class TestMVStore extends TestBase {
FileUtils.delete(fileName);
}
private void testWriteBuffer() throws IOException {
private void testWriteBuffer() {
String fileName = getBaseDir() + "/testWriteBuffer.h3";
FileUtils.delete(fileName);
MVStore s;
......@@ -234,7 +252,7 @@ public class TestMVStore extends TestBase {
for (int i = 0; i < len; i++) {
m.put(i, data);
}
long size = s.getFile().size();
long size = s.getFileStore().size();
assertTrue("last:" + lastSize + " now: " + size, size > lastSize);
lastSize = size;
s.close();
......@@ -379,7 +397,7 @@ public class TestMVStore extends TestBase {
s = new MVStore.Builder().
fileName(fileName).
encryptionKey(passwordChars).open();
assertTrue(s.isReadOnly());
assertTrue(s.getFileStore().isReadOnly());
FileUtils.delete(fileName);
assertFalse(FileUtils.exists(fileName));
......@@ -393,7 +411,7 @@ public class TestMVStore extends TestBase {
s = openStore(fileName);
m = s.openMap("test");
m.put(1, 1);
Map<String, String> header = s.getFileHeader();
Map<String, String> header = s.getStoreHeader();
int format = Integer.parseInt(header.get("format"));
assertEquals(1, format);
header.put("format", Integer.toString(format + 1));
......@@ -483,7 +501,7 @@ public class TestMVStore extends TestBase {
}
}
assertEquals(expectedReadsForCacheSize[cacheSize],
s.getFileReadCount());
s.getFileStore().getReadCount());
s.close();
}
......@@ -506,10 +524,10 @@ public class TestMVStore extends TestBase {
} catch (IllegalStateException e) {
// expected
}
assertFalse(s.isReadOnly());
assertFalse(s.getFileStore().isReadOnly());
s.close();
s = new MVStore.Builder().fileName(fileName).readOnly().open();
assertTrue(s.isReadOnly());
assertTrue(s.getFileStore().isReadOnly());
s.close();
}
......@@ -517,17 +535,17 @@ public class TestMVStore extends TestBase {
String fileName = getBaseDir() + "/testFileHeader.h3";
MVStore s = openStore(fileName);
long time = System.currentTimeMillis();
assertEquals("3", s.getFileHeader().get("H"));
long creationTime = Long.parseLong(s.getFileHeader()
assertEquals("3", s.getStoreHeader().get("H"));
long creationTime = Long.parseLong(s.getStoreHeader()
.get("creationTime"));
assertTrue(Math.abs(time - creationTime) < 100);
s.getFileHeader().put("test", "123");
s.getStoreHeader().put("test", "123");
MVMap<Integer, Integer> map = s.openMap("test");
map.put(10, 100);
s.store();
s.close();
s = openStore(fileName);
assertEquals("123", s.getFileHeader().get("test"));
assertEquals("123", s.getStoreHeader().get("test"));
s.close();
}
......@@ -545,7 +563,7 @@ public class TestMVStore extends TestBase {
s.compact(50);
map.put(10, 100);
s.store();
FilePath f = FilePath.get(s.getFileName());
FilePath f = FilePath.get(fileName);
s.close();
int blockSize = 4 * 1024;
// test corrupt file headers
......@@ -990,7 +1008,7 @@ public class TestMVStore extends TestBase {
assertEquals(1000, m.size());
assertEquals(286, s.getUnsavedPageCount());
s.store();
assertEquals(2, s.getFileWriteCount());
assertEquals(2, s.getFileStore().getWriteCount());
s.close();
s = openStore(fileName);
......@@ -999,8 +1017,8 @@ public class TestMVStore extends TestBase {
assertEquals(0, m.size());
s.store();
// ensure only nodes are read, but not leaves
assertEquals(42, s.getFileReadCount());
assertEquals(1, s.getFileWriteCount());
assertEquals(42, s.getFileStore().getReadCount());
assertEquals(1, s.getFileStore().getWriteCount());
s.close();
}
......@@ -1574,7 +1592,7 @@ public class TestMVStore extends TestBase {
s.close();
}
private void testLargerThan2G() throws IOException {
private void testLargerThan2G() {
if (!config.big) {
return;
}
......@@ -1592,7 +1610,7 @@ public class TestMVStore extends TestBase {
store.setRetainVersion(version);
long time = System.currentTimeMillis();
if (time - last > 2000) {
long mb = store.getFile().size() / 1024 / 1024;
long mb = store.getFileStore().size() / 1024 / 1024;
trace(mb + "/4500");
if (mb > 4500) {
break;
......
......@@ -530,7 +530,7 @@ public class TestMVTableEngine extends TestBase {
FileUtils.setReadOnly(getBaseDir() + "/mvstore.h2.db");
conn = getConnection(dbName);
Database db = (Database) ((JdbcConnection) conn).getSession().getDataHandler();
assertTrue(db.getMvStore().getStore().isReadOnly());
assertTrue(db.getMvStore().getStore().getFileStore().isReadOnly());
conn.close();
FileUtils.deleteRecursive(getBaseDir(), true);
}
......
......@@ -487,8 +487,8 @@ public class TestTransactionStore extends TestBase {
size++;
}
buff.append('\n');
if (size != map.getSize()) {
assertEquals(size, map.getSize());
if (size != map.sizeAsLong()) {
assertEquals(size, map.sizeAsLong());
}
}
int x = r.nextInt(rowCount);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论