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

MVStore: unified exception handling; the version is included in the messages.…

MVStore: unified exception handling; the version is included in the messages. Old data is now retained for 45 seconds by default.
上级 9455decf
...@@ -18,7 +18,9 @@ Change Log ...@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>MVStore: compress is now disabled by default, and can be enabled on request. <ul><li>MVStore: unified exception handling; the version is included in the messages.
</li><li>MVStore: old data is now retained for 45 seconds by default.
</ul><li>MVStore: compress is now disabled by default, and can be enabled on request.
</li></ul> </li></ul>
<h2>Version 1.3.170 (2012-11-30)</h2> <h2>Version 1.3.170 (2012-11-30)</h2>
......
...@@ -138,7 +138,7 @@ encrypted using AES-128 and XTEA encryption algorithms ...@@ -138,7 +138,7 @@ encrypted using AES-128 and XTEA encryption algorithms
<h3>Other Features and Tools</h3> <h3>Other Features and Tools</h3>
<ul> <ul>
<li>Small footprint (smaller than 1 MB), low memory requirements <li>Small footprint (smaller than 1.5 MB), low memory requirements
</li><li>Multiple index types (b-tree, tree, hash) </li><li>Multiple index types (b-tree, tree, hash)
</li><li>Support for multi-dimensional indexes </li><li>Support for multi-dimensional indexes
</li><li>CSV (comma separated values) file support </li><li>CSV (comma separated values) file support
...@@ -350,9 +350,9 @@ H2 1.3, ...@@ -350,9 +350,9 @@ H2 1.3,
<td class="compareY">Yes</td> <td class="compareY">Yes</td>
</tr><tr> </tr><tr>
<td>Footprint (jar/dll size)</td> <td>Footprint (jar/dll size)</td>
<td>~1 MB *5</td> <td>~1.5 MB *5</td>
<td>~2 MB</td> <td>~3 MB</td>
<td>~1 MB</td> <td>~1.5 MB</td>
<td>~4 MB</td> <td>~4 MB</td>
<td>~6 MB</td> <td>~6 MB</td>
</tr> </tr>
......
...@@ -27,7 +27,7 @@ Welcome to H2, the Java SQL database. The main features of H2 are: ...@@ -27,7 +27,7 @@ Welcome to H2, the Java SQL database. The main features of H2 are:
<li>Very fast, open source, JDBC API <li>Very fast, open source, JDBC API
</li><li>Embedded and server modes; in-memory databases </li><li>Embedded and server modes; in-memory databases
</li><li>Browser based Console application </li><li>Browser based Console application
</li><li>Small footprint: around 1 MB jar file size </li><li>Small footprint: around 1.5 MB jar file size
</li></ul> </li></ul>
<table style="border: 0px; width: 470px;"> <table style="border: 0px; width: 470px;">
......
...@@ -327,6 +327,22 @@ with a fluent API to simplify building a store instance. ...@@ -327,6 +327,22 @@ with a fluent API to simplify building a store instance.
There is a tool (<code>MVStoreTool</code>) to dump the contents of a file. There is a tool (<code>MVStoreTool</code>) to dump the contents of a file.
</p> </p>
<h3>Exception Handling</h3>
<p>
This tool does not throw checked exceptions.
Instead, unchecked exceptions are thrown if needed.
The error message always contains the version of the tool.
The following exceptions can occur:
</p>
<ul><li><code>IllegalStateException</code> if a map was already closed,
in IO exception occurred, for example if the file was locked, is already closed,
could not be opened or closed, if reading or writing failed,
if the file is corrupt, or if there is an internal error in the tool.
</li><li><code>IllegalArgumentException</code> if a method was called with an illegal argument.
</li><li><code>UnsupportedOperationException</code> if a method was called that is not supported,
for example trying to modify a read-only map or view.
</ul>
<h2 id="differences">Similar Projects and Differences to Other Storage Engines</h2> <h2 id="differences">Similar Projects and Differences to Other Storage Engines</h2>
<p> <p>
Unlike similar storage engines like LevelDB and Kyoto Cabinet, the MVStore is written in Java Unlike similar storage engines like LevelDB and Kyoto Cabinet, the MVStore is written in Java
......
...@@ -53,7 +53,7 @@ public class ChangeCursor<K, V> implements Iterator<K> { ...@@ -53,7 +53,7 @@ public class ChangeCursor<K, V> implements Iterator<K> {
} }
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw DataUtils.unsupportedOperationException("Removing is not supported");
} }
private void fetchNext() { private void fetchNext() {
......
...@@ -89,7 +89,7 @@ public class Chunk { ...@@ -89,7 +89,7 @@ public class Chunk {
*/ */
static Chunk fromHeader(ByteBuffer buff, long start) { static Chunk fromHeader(ByteBuffer buff, long start) {
if (buff.get() != 'c') { if (buff.get() != 'c') {
throw new RuntimeException("File corrupt"); throw DataUtils.illegalStateException("File corrupt reading chunk at position " + start);
} }
int length = buff.getInt(); int length = buff.getInt();
int chunkId = buff.getInt(); int chunkId = buff.getInt();
......
...@@ -67,7 +67,7 @@ public class Cursor<K> implements Iterator<K> { ...@@ -67,7 +67,7 @@ public class Cursor<K> implements Iterator<K> {
} }
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw DataUtils.unsupportedOperationException("Removing is not supported");
} }
/** /**
......
...@@ -14,6 +14,7 @@ import java.nio.channels.FileChannel; ...@@ -14,6 +14,7 @@ import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import org.h2.engine.Constants;
import org.h2.util.New; import org.h2.util.New;
/** /**
...@@ -304,15 +305,19 @@ public class DataUtils { ...@@ -304,15 +305,19 @@ public class DataUtils {
* @param pos the absolute position within the file * @param pos the absolute position within the file
* @param dst the byte buffer * @param dst the byte buffer
*/ */
public static void readFully(FileChannel file, long pos, ByteBuffer dst) throws IOException { public static void readFully(FileChannel file, long pos, ByteBuffer dst) {
do { try {
int len = file.read(dst, pos); do {
if (len < 0) { int len = file.read(dst, pos);
throw new EOFException(); if (len < 0) {
} throw new EOFException();
pos += len; }
} while (dst.remaining() > 0); pos += len;
dst.rewind(); } while (dst.remaining() > 0);
dst.rewind();
} catch (IOException e) {
throw illegalStateException("Reading from " + file + " failed; length " + dst.remaining() + " at " + pos, e);
}
} }
/** /**
...@@ -322,12 +327,16 @@ public class DataUtils { ...@@ -322,12 +327,16 @@ public class DataUtils {
* @param pos the absolute position within the file * @param pos the absolute position within the file
* @param src the source buffer * @param src the source buffer
*/ */
public static void writeFully(FileChannel file, long pos, ByteBuffer src) throws IOException { public static void writeFully(FileChannel file, long pos, ByteBuffer src) {
int off = 0; try {
do { int off = 0;
int len = file.write(src, pos + off); do {
off += len; int len = file.write(src, pos + off);
} while (src.remaining() > 0); off += len;
} while (src.remaining() > 0);
} catch (IOException e) {
throw illegalStateException("Writing to " + file + " failed; length " + src.remaining() + " at " + pos, e);
}
} }
...@@ -544,4 +553,25 @@ public class DataUtils { ...@@ -544,4 +553,25 @@ public class DataUtils {
return (s2 << 16) | s1; return (s2 << 16) | s1;
} }
public static IllegalStateException illegalStateException(String message) {
return new IllegalStateException(message + version());
}
public static IllegalStateException illegalStateException(String message, Exception e) {
return new IllegalStateException(message + version(), e);
}
public static IllegalArgumentException illegalArgumentException(String message) {
return new IllegalArgumentException(message + version());
}
public static UnsupportedOperationException unsupportedOperationException(String message) {
return new UnsupportedOperationException(message + version());
}
private static String version() {
return " [" + Constants.VERSION_MAJOR + "." +
Constants.VERSION_MINOR + "." + Constants.BUILD_ID + "]";
}
} }
...@@ -839,7 +839,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -839,7 +839,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/ */
protected void checkOpen() { protected void checkOpen() {
if (closed) { if (closed) {
throw new IllegalStateException("This map is closed"); throw DataUtils.illegalStateException("This map is closed");
} }
} }
...@@ -851,7 +851,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -851,7 +851,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
protected void checkWrite() { protected void checkWrite() {
if (readOnly) { if (readOnly) {
checkOpen(); checkOpen();
throw new IllegalStateException("This map is read-only"); throw DataUtils.unsupportedOperationException("This map is read-only");
} }
} }
...@@ -893,10 +893,11 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -893,10 +893,11 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/ */
public MVMap<K, V> openVersion(long version) { public MVMap<K, V> openVersion(long version) {
if (readOnly) { if (readOnly) {
throw new IllegalArgumentException("This map is read-only - need to call the method on the writable map"); throw DataUtils.unsupportedOperationException(
"This map is read-only - need to call the method on the writable map");
} }
if (version < createVersion) { if (version < createVersion) {
throw new IllegalArgumentException("Unknown version"); throw DataUtils.illegalArgumentException("Unknown version");
} }
Page newest = null; Page newest = null;
// need to copy because it can change // need to copy because it can change
......
...@@ -39,7 +39,7 @@ public class MVStoreBuilder { ...@@ -39,7 +39,7 @@ public class MVStoreBuilder {
private MVStoreBuilder set(String key, Object value) { private MVStoreBuilder set(String key, Object value) {
if (config.containsKey(key)) { if (config.containsKey(key)) {
throw new IllegalArgumentException("Parameter " + config.get(key) + " is already set"); throw DataUtils.illegalArgumentException("Parameter " + config.get(key) + " is already set");
} }
config.put(key, value); config.put(key, value);
return this; return this;
......
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
*/ */
package org.h2.mvstore; package org.h2.mvstore;
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.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;
import org.h2.util.Utils;
/** /**
* A page (a node or a leaf). * A page (a node or a leaf).
...@@ -129,20 +129,16 @@ public class Page { ...@@ -129,20 +129,16 @@ public class Page {
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);
try { maxLength = (int) Math.min(fileSize - filePos, maxLength);
maxLength = (int) Math.min(fileSize - filePos, maxLength); 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);
maxLength = buff.getInt();
//read the first bytes again
}
buff = ByteBuffer.allocate(length);
DataUtils.readFully(file, filePos, buff); DataUtils.readFully(file, filePos, buff);
} catch (IOException e) { maxLength = buff.getInt();
throw new RuntimeException(e); //read the first bytes again
} }
buff = ByteBuffer.allocate(length);
DataUtils.readFully(file, 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);
...@@ -409,7 +405,7 @@ public class Page { ...@@ -409,7 +405,7 @@ public class Page {
} }
} }
if (check != totalCount) { if (check != totalCount) {
throw new AssertionError("Expected: " + check + " got: " throw DataUtils.illegalStateException("Expected: " + check + " got: "
+ totalCount); + totalCount);
} }
} }
...@@ -653,20 +649,20 @@ public class Page { ...@@ -653,20 +649,20 @@ public class Page {
int start = buff.position(); int start = buff.position();
int pageLength = buff.getInt(); int pageLength = buff.getInt();
if (pageLength > maxLength) { if (pageLength > maxLength) {
throw new RuntimeException("Length too large, expected =< " throw DataUtils.illegalStateException("File corrupted, expected length =< "
+ maxLength + " got " + pageLength); + maxLength + " got " + pageLength);
} }
short check = buff.getShort(); short check = buff.getShort();
int mapId = DataUtils.readVarInt(buff); int mapId = DataUtils.readVarInt(buff);
if (mapId != map.getId()) { if (mapId != map.getId()) {
throw new RuntimeException("Error reading page, expected map " throw DataUtils.illegalStateException("File corrupted, expected map id "
+ map.getId() + " got " + mapId); + map.getId() + " got " + mapId);
} }
int checkTest = DataUtils.getCheckValue(chunkId) int checkTest = DataUtils.getCheckValue(chunkId)
^ DataUtils.getCheckValue(offset) ^ DataUtils.getCheckValue(offset)
^ DataUtils.getCheckValue(pageLength); ^ DataUtils.getCheckValue(pageLength);
if (check != (short) checkTest) { if (check != (short) checkTest) {
throw new RuntimeException("Error in check value, expected " throw DataUtils.illegalStateException("File corrupted, expected check value "
+ checkTest + " got " + check); + checkTest + " got " + check);
} }
int len = DataUtils.readVarInt(buff); int len = DataUtils.readVarInt(buff);
...@@ -679,7 +675,7 @@ public class Page { ...@@ -679,7 +675,7 @@ public class Page {
Compressor compressor = map.getStore().getCompressor(); Compressor compressor = map.getStore().getCompressor();
int lenAdd = DataUtils.readVarInt(buff); int lenAdd = DataUtils.readVarInt(buff);
int compLen = pageLength + start - buff.position(); int compLen = pageLength + start - buff.position();
byte[] comp = new byte[compLen]; byte[] comp = Utils.newBytes(compLen);
buff.get(comp); buff.get(comp);
int l = compLen + lenAdd; int l = compLen + lenAdd;
buff = ByteBuffer.allocate(l); buff = ByteBuffer.allocate(l);
...@@ -865,7 +861,7 @@ public class Page { ...@@ -865,7 +861,7 @@ public class Page {
public int getMemory() { public int getMemory() {
if (MVStore.ASSERT) { if (MVStore.ASSERT) {
if (memory != calculateMemory()) { if (memory != calculateMemory()) {
throw new RuntimeException("Memory calculation error"); throw DataUtils.illegalStateException("Memory calculation error");
} }
} }
return memory; return memory;
......
...@@ -14,6 +14,7 @@ import java.nio.ByteBuffer; ...@@ -14,6 +14,7 @@ import java.nio.ByteBuffer;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.h2.util.IOUtils; import org.h2.util.IOUtils;
import org.h2.util.StringUtils;
/** /**
* A facility to store streams in a map. Streams are split into blocks, which * A facility to store streams in a map. Streams are split into blocks, which
...@@ -207,7 +208,7 @@ public class StreamStore { ...@@ -207,7 +208,7 @@ public class StreamStore {
map.remove(k2); map.remove(k2);
break; break;
default: default:
throw new IllegalArgumentException("Unsupported id"); throw DataUtils.illegalArgumentException("Unsupported id " + StringUtils.convertBytesToHex(id));
} }
} }
} }
...@@ -238,7 +239,7 @@ public class StreamStore { ...@@ -238,7 +239,7 @@ public class StreamStore {
DataUtils.readVarLong(idBuffer); DataUtils.readVarLong(idBuffer);
break; break;
default: default:
throw new IllegalArgumentException("Unsupported id"); throw DataUtils.illegalArgumentException("Unsupported id " + StringUtils.convertBytesToHex(id));
} }
} }
return length; return length;
...@@ -401,7 +402,8 @@ public class StreamStore { ...@@ -401,7 +402,8 @@ public class StreamStore {
return nextBuffer(); return nextBuffer();
} }
default: default:
throw new IllegalArgumentException("Unsupported id"); throw DataUtils.illegalArgumentException("Unsupported id " +
StringUtils.convertBytesToHex(idBuffer.array()));
} }
} }
return null; return null;
......
...@@ -12,6 +12,7 @@ import java.util.HashSet; ...@@ -12,6 +12,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.h2.mvstore.DataUtils;
/** /**
* A scan resistant cache that uses keys of type long. It is meant to cache * A scan resistant cache that uses keys of type long. It is meant to cache
...@@ -65,7 +66,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -65,7 +66,7 @@ public class CacheLongKeyLIRS<V> {
setMaxMemory(maxMemory); setMaxMemory(maxMemory);
setAverageMemory(averageMemory); setAverageMemory(averageMemory);
if (Integer.bitCount(segmentCount) != 1) { if (Integer.bitCount(segmentCount) != 1) {
throw new IllegalArgumentException("The segment count must be a power of 2, is " + segmentCount); throw DataUtils.illegalArgumentException("The segment count must be a power of 2, is " + segmentCount);
} }
this.segmentCount = segmentCount; this.segmentCount = segmentCount;
this.segmentMask = segmentCount - 1; this.segmentMask = segmentCount - 1;
...@@ -221,7 +222,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -221,7 +222,7 @@ public class CacheLongKeyLIRS<V> {
*/ */
public void setMaxMemory(long maxMemory) { public void setMaxMemory(long maxMemory) {
if (maxMemory <= 0) { if (maxMemory <= 0) {
throw new IllegalArgumentException("Max memory must be larger than 0"); throw DataUtils.illegalArgumentException("Max memory must be larger than 0");
} }
this.maxMemory = maxMemory; this.maxMemory = maxMemory;
if (segments != null) { if (segments != null) {
...@@ -240,7 +241,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -240,7 +241,7 @@ public class CacheLongKeyLIRS<V> {
*/ */
public void setAverageMemory(int averageMemory) { public void setAverageMemory(int averageMemory) {
if (averageMemory <= 0) { if (averageMemory <= 0) {
throw new IllegalArgumentException("Average memory must be larger than 0"); throw DataUtils.illegalArgumentException("Average memory must be larger than 0");
} }
this.averageMemory = averageMemory; this.averageMemory = averageMemory;
if (segments != null) { if (segments != null) {
...@@ -682,7 +683,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -682,7 +683,7 @@ public class CacheLongKeyLIRS<V> {
*/ */
synchronized V put(long key, int hash, V value, int memory) { synchronized V put(long key, int hash, V value, int memory) {
if (value == null) { if (value == null) {
throw new NullPointerException(); throw DataUtils.illegalArgumentException("The value may not be null");
} }
V old; V old;
Entry<V> e = find(key, hash); Entry<V> e = find(key, hash);
...@@ -947,7 +948,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -947,7 +948,7 @@ public class CacheLongKeyLIRS<V> {
*/ */
void setMaxMemory(long maxMemory) { void setMaxMemory(long maxMemory) {
if (maxMemory <= 0) { if (maxMemory <= 0) {
throw new IllegalArgumentException("Max memory must be larger than 0"); throw DataUtils.illegalArgumentException("Max memory must be larger than 0");
} }
this.maxMemory = maxMemory; this.maxMemory = maxMemory;
} }
...@@ -960,7 +961,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -960,7 +961,7 @@ public class CacheLongKeyLIRS<V> {
*/ */
void setAverageMemory(int averageMemory) { void setAverageMemory(int averageMemory) {
if (averageMemory <= 0) { if (averageMemory <= 0) {
throw new IllegalArgumentException("Average memory must be larger than 0"); throw DataUtils.illegalArgumentException("Average memory must be larger than 0");
} }
this.averageMemory = averageMemory; this.averageMemory = averageMemory;
} }
......
...@@ -22,7 +22,7 @@ public class SpatialDataType implements DataType { ...@@ -22,7 +22,7 @@ public class SpatialDataType implements DataType {
public SpatialDataType(int dimensions) { public SpatialDataType(int dimensions) {
if (dimensions <= 0 || dimensions > 255) { if (dimensions <= 0 || dimensions > 255) {
throw new IllegalArgumentException("Dimensions: " + dimensions); throw DataUtils.illegalArgumentException("Dimensions: " + dimensions);
} }
this.dimensions = dimensions; this.dimensions = dimensions;
} }
......
...@@ -143,7 +143,7 @@ public class ObjectDataType implements DataType { ...@@ -143,7 +143,7 @@ public class ObjectDataType implements DataType {
case TYPE_SERIALIZED_OBJECT: case TYPE_SERIALIZED_OBJECT:
return new SerializedObjectType(this); return new SerializedObjectType(this);
} }
throw new RuntimeException("Unsupported type: " + typeId); throw DataUtils.illegalStateException("Unsupported type: " + typeId);
} }
@Override @Override
...@@ -196,7 +196,7 @@ public class ObjectDataType implements DataType { ...@@ -196,7 +196,7 @@ public class ObjectDataType implements DataType {
} else if (tag >= TAG_BYTE_ARRAY_0_15 && tag <= TAG_BYTE_ARRAY_0_15 + 15) { } else if (tag >= TAG_BYTE_ARRAY_0_15 && tag <= TAG_BYTE_ARRAY_0_15 + 15) {
typeId = TYPE_BYTE_ARRAY; typeId = TYPE_BYTE_ARRAY;
} else { } else {
throw new RuntimeException("Unknown tag: " + tag); throw DataUtils.illegalStateException("Unknown tag: " + tag);
} }
} }
} }
...@@ -250,7 +250,7 @@ public class ObjectDataType implements DataType { ...@@ -250,7 +250,7 @@ public class ObjectDataType implements DataType {
return TYPE_CHARACTER; return TYPE_CHARACTER;
} }
if (obj == null) { if (obj == null) {
throw new NullPointerException(); throw DataUtils.illegalArgumentException("Null is not supported");
} }
return TYPE_SERIALIZED_OBJECT; return TYPE_SERIALIZED_OBJECT;
} }
...@@ -377,7 +377,7 @@ public class ObjectDataType implements DataType { ...@@ -377,7 +377,7 @@ public class ObjectDataType implements DataType {
@Override @Override
public final Object read(ByteBuffer buff) { public final Object read(ByteBuffer buff) {
throw new RuntimeException(); throw DataUtils.illegalStateException("Internal error");
} }
/** /**
...@@ -1232,13 +1232,14 @@ public class ObjectDataType implements DataType { ...@@ -1232,13 +1232,14 @@ public class ObjectDataType implements DataType {
@Override @Override
public Object read(ByteBuffer buff, int tag) { public Object read(ByteBuffer buff, int tag) {
int len; byte[] data;
if (tag == TYPE_BYTE_ARRAY) { if (tag == TYPE_BYTE_ARRAY) {
len = DataUtils.readVarInt(buff); int len = DataUtils.readVarInt(buff);
data = Utils.newBytes(len);
} else { } else {
len = tag - TAG_BYTE_ARRAY_0_15; int len = tag - TAG_BYTE_ARRAY_0_15;
data = Utils.newBytes(len);
} }
byte[] data = new byte[len];
buff.get(data); buff.get(data);
return data; return data;
} }
...@@ -1497,7 +1498,7 @@ public class ObjectDataType implements DataType { ...@@ -1497,7 +1498,7 @@ public class ObjectDataType implements DataType {
@Override @Override
public Object read(ByteBuffer buff, int tag) { public Object read(ByteBuffer buff, int tag) {
int len = DataUtils.readVarInt(buff); int len = DataUtils.readVarInt(buff);
byte[] data = new byte[len]; byte[] data = Utils.newBytes(len);
buff.get(data); buff.get(data);
return Utils.deserialize(data); return Utils.deserialize(data);
} }
......
...@@ -365,7 +365,7 @@ public class StringUtils { ...@@ -365,7 +365,7 @@ public class StringUtils {
* @param length the number of bytes * @param length the number of bytes
* @return the text * @return the text
*/ */
private static String utf8Decode(byte[] bytes, int offset, int length) { public static String utf8Decode(byte[] bytes, int offset, int length) {
try { try {
return new String(bytes, offset, length, Constants.UTF8); return new String(bytes, offset, length, Constants.UTF8);
} catch (Exception e) { } catch (Exception e) {
......
...@@ -382,16 +382,20 @@ public class Utils { ...@@ -382,16 +382,20 @@ public class Utils {
* Create an array of bytes with the given size. If this is not possible * Create an array of bytes with the given size. If this is not possible
* because not enough memory is available, an OutOfMemoryError with the * because not enough memory is available, an OutOfMemoryError with the
* requested size in the message is thrown. * requested size in the message is thrown.
* <p>
* This method should be used if the size of the array is user defined, or
* stored in a file, so wrong size data can be distinguished from regular
* out-of-memory.
* *
* @param len the number of bytes requested * @param len the number of bytes requested
* @return the byte array * @return the byte array
* @throws OutOfMemoryError * @throws OutOfMemoryError
*/ */
public static byte[] newBytes(int len) { public static byte[] newBytes(int len) {
if (len == 0) {
return EMPTY_BYTES;
}
try { try {
if (len == 0) {
return EMPTY_BYTES;
}
return new byte[len]; return new byte[len];
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
Error e2 = new OutOfMemoryError("Requested memory: " + len); Error e2 = new OutOfMemoryError("Requested memory: " + len);
......
...@@ -10,7 +10,7 @@ import java.util.HashSet; ...@@ -10,7 +10,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import org.h2.mvstore.cache.CacheLIRS; import org.h2.dev.cache.CacheLIRS;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.New; import org.h2.util.New;
......
...@@ -130,14 +130,14 @@ public class TestMVStore extends TestBase { ...@@ -130,14 +130,14 @@ public class TestMVStore extends TestBase {
MVStore s1 = MVStoreBuilder.fileBased(fileName).open(); MVStore s1 = MVStoreBuilder.fileBased(fileName).open();
s1.close(); s1.close();
fail(); fail();
} catch (Exception e) { } catch (IllegalStateException e) {
// expected // expected
} }
try { try {
MVStore s1 = MVStoreBuilder.fileBased(fileName).readOnly().open(); MVStore s1 = MVStoreBuilder.fileBased(fileName).readOnly().open();
s1.close(); s1.close();
fail(); fail();
} catch (Exception e) { } catch (IllegalStateException e) {
// expected // expected
} }
s.close(); s.close();
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.mvstore.cache; package org.h2.dev.cache;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -622,7 +622,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> { ...@@ -622,7 +622,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
*/ */
synchronized V put(K key, int hash, V value, int memory) { synchronized V put(K key, int hash, V value, int memory) {
if (value == null) { if (value == null) {
throw new NullPointerException(); throw new NullPointerException("The value may not be null");
} }
V old; V old;
Entry<K, V> e = find(key, hash); Entry<K, V> e = find(key, hash);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论