提交 5b028f68 authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore

上级 b70ccb3e
......@@ -13,6 +13,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import org.h2.engine.Constants;
......@@ -345,7 +346,6 @@ public class DataUtils {
}
}
/**
* Convert the length to a length code 0..31. 31 means more than 1 MB.
*
......@@ -560,23 +560,51 @@ public class DataUtils {
return (s2 << 16) | s1;
}
/**
* Throw an IllegalArgumentException if the argument is invalid.
*
* @param test true if the argument is valid
* @param message the message
* @param arguments the arguments
* @throws IllegalArgumentException if the argument is invalid
*/
public static void checkArgument(boolean test, String message, Object... arguments) {
if (!test) {
throw newIllegalArgumentException(message, arguments);
}
}
/**
* Create a new IllegalArgumentException.
*
* @param message the message
* @param arguments the arguments
* @return the exception
*/
public static IllegalArgumentException newIllegalArgumentException(
String message, Object... arguments) {
return initCause(new IllegalArgumentException(
formatMessage(message, arguments)), arguments);
}
/**
* Create a new UnsupportedOperationException.
*
* @param message the message
* @return the exception
*/
public static UnsupportedOperationException newUnsupportedOperationException(
String message) {
return new UnsupportedOperationException(message + getVersion());
}
/**
* Create a new IllegalStateException.
*
* @param message the message
* @param arguments the arguments
* @return the exception
*/
public static IllegalStateException newIllegalStateException(
String message, Object... arguments) {
return initCause(new IllegalStateException(
......@@ -609,6 +637,13 @@ public class DataUtils {
Constants.VERSION_MINOR + "." + Constants.BUILD_ID + "]";
}
/**
* Convert a char array to a byte array. The char array is cleared after
* use.
*
* @param passwordChars the password characters
* @return the byte array
*/
static byte[] getPasswordBytes(char[] passwordChars) {
// using UTF-16
int len = passwordChars.length;
......@@ -618,6 +653,7 @@ public class DataUtils {
password[i + i] = (byte) (c >>> 8);
password[i + i + 1] = (byte) c;
}
Arrays.fill(passwordChars, (char) 0);
return password;
}
......
......@@ -100,6 +100,13 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return (V) result;
}
/**
* Split the root page if necessary.
*
* @param p the page
* @param writeVersion the write version
* @return the new sibling
*/
protected Page splitRootIfNeeded(Page p, long writeVersion) {
if (p.getMemory() <= store.getPageSize() || p.getKeyCount() <= 1) {
return p;
......@@ -283,6 +290,12 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
}
/**
* Get the first (lowest) or last (largest) key.
*
* @param first whether to retrieve the first key
* @return the key, or null if the map is empty
*/
@SuppressWarnings("unchecked")
protected K getFirstLast(boolean first) {
checkOpen();
......@@ -340,6 +353,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return getMinMax(key, true, true);
}
/**
* Get the smallest or largest key using the given bounds.
*
* @param key the key
* @param min whether to retrieve the smallest key
* @param excluding if the given upper/lower bound is exclusive
* @return the key, or null if the map is empty
*/
protected K getMinMax(K key, boolean min, boolean excluding) {
checkOpen();
if (size() == 0) {
......
......@@ -28,10 +28,6 @@ public class MVMapConcurrent<K, V> extends MVMap<K, V> {
super(keyType, valueType);
}
public static <K, V> MVMap<K, V> create() {
return new MVMapConcurrent<K, V>(new ObjectDataType(), new ObjectDataType());
}
protected Page copyOnWrite(Page p, long writeVersion) {
return p.copy(writeVersion);
}
......
......@@ -43,8 +43,8 @@ H:3,...
TODO:
- separate jar file
- automated 'kill process' and 'power failure' test
- test stream store if data doesn't fit in memory
- mvcc with multiple transactions
- update checkstyle
- maybe split database into multiple files, to speed up compact
......@@ -86,14 +86,12 @@ TODO:
- ensure data is overwritten eventually if the system doesn't have a timer
- SSD-friendly write (always in blocks of 128 or 256 KB?)
- close the file on out of memory or disk write error (out of disk space or so)
- implement a shareded map (in one store, multiple stores)
- implement a sharded map (in one store, multiple stores)
-- to support concurrent updates and writes, and very large maps
- implement an off-heap file system
- remove change cursor, or add support for writing to branches
- file encryption: try using multiple threads
- file encryption: support un-aligned operations
- file encryption: separate algorithm/key for tweak
- file encryption: add a fast (insecure) algorithm
- file encryption: add a fast, insecure algorithm
*/
......@@ -405,7 +403,7 @@ public class MVStore {
file = f.open(readOnly ? "r" : "rw");
if (filePassword != null) {
byte[] password = DataUtils.getPasswordBytes(filePassword);
file = new FilePathCrypt.FileCrypt2(password, file);
file = new FilePathCrypt.FileCrypt(fileName, password, file);
}
file = FilePathCache.wrap(file);
if (readOnly) {
......@@ -1392,6 +1390,12 @@ public class MVStore {
}
}
/**
* Rename a map.
*
* @param map the map
* @param newName the new name
*/
void renameMap(MVMap<?, ?> map, String newName) {
checkOpen();
DataUtils.checkArgument(map != meta,
......@@ -1411,6 +1415,12 @@ public class MVStore {
meta.put("name." + newName, Integer.toString(id));
}
/**
* Get the name of the given map.
*
* @param id the map id
* @return the name
*/
String getMapName(int id) {
String m = meta.get("map." + id);
return DataUtils.parseMap(m).get("name");
......
......@@ -462,7 +462,7 @@ public class Page {
}
/**
* Update the (descendent) count for the given child, if there was a change.
* Update the (descendant) count for the given child, if there was a change.
*
* @param index the index
* @param c the new child page
......@@ -472,7 +472,7 @@ public class Page {
}
/**
* Update the (descendent) count for the given child, if there was a change.
* Update the (descendant) count for the given child, if there was a change.
*
* @param index the index
* @param total the new value
......
......@@ -25,6 +25,8 @@ import org.h2.util.StringUtils;
* checks if there is already a block with the next key, and if necessary
* searches the next free entry using a binary search (0 to Long.MAX_VALUE).
* <p>
* Before storing
* <p>
* The format of the binary id is: An empty id represents 0 bytes of data.
* In-place data is encoded as 0, the size (a variable size int), then the data.
* A stored block is encoded as 1, the length of the block (a variable size
......@@ -157,9 +159,20 @@ public class StreamStore {
private long writeBlock(byte[] data) {
long key = getAndIncrementNextKey();
map.put(key, data);
onStore(data.length);
return key;
}
/**
* This method is called after a block of data is stored. Override this
* method to persist data if necessary.
*
* @param len the length of the stored block.
*/
protected void onStore(int len) {
// do nothing by default
}
private long getAndIncrementNextKey() {
long key = nextKey.getAndIncrement();
if (!map.containsKey(key)) {
......
......@@ -262,22 +262,52 @@ public class ObjectDataType implements DataType {
return l;
}
/**
* Check whether this object is a BigInteger.
*
* @param obj the object
* @return true if yes
*/
static boolean isBigInteger(Object obj) {
return obj instanceof BigInteger && obj.getClass() == BigInteger.class;
}
/**
* Check whether this object is a BigDecimal.
*
* @param obj the object
* @return true if yes
*/
static boolean isBigDecimal(Object obj) {
return obj instanceof BigDecimal && obj.getClass() == BigDecimal.class;
}
/**
* Check whether this object is a date.
*
* @param obj the object
* @return true if yes
*/
static boolean isDate(Object obj) {
return obj instanceof Date && obj.getClass() == Date.class;
}
/**
* Check whether this object is an array.
*
* @param obj the object
* @return true if yes
*/
static boolean isArray(Object obj) {
return obj != null && obj.getClass().isArray();
}
/**
* Get the class id, or null if not found.
*
* @param clazz the class
* @return the class id or null
*/
static Integer getCommonClassId(Class<?> clazz) {
HashMap<Class<?>, Integer> map = COMMON_CLASSES_MAP;
if (map.size() == 0) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论