提交 0b219336 authored 作者: Thomas Mueller's avatar Thomas Mueller

Formatting, javadocs

上级 58bea228
......@@ -175,7 +175,7 @@ public class SysProperties {
* maximum delay.
*/
public static final int DELAY_WRONG_PASSWORD_MAX = Utils.getProperty("h2.delayWrongPasswordMax", 4000);
/**
* System property <code>h2.javaSystemCompiler</code> (default: true).<br />
* Whether to use the Java system compiler
......
......@@ -2498,7 +2498,7 @@ public class Database implements DataHandler {
conn.setTraceLevel(TraceSystem.OFF);
return conn;
}
public void setLogMode(int log) {
if (log < 0 || log > 2) {
throw DbException.getInvalidValueException("LOG", log);
......
......@@ -122,7 +122,7 @@ public class DataUtils {
* The estimated number of bytes used per child entry.
*/
public static final int PAGE_MEMORY_CHILD = 16;
/**
* Name of the character encoding format.
*/
......@@ -137,7 +137,7 @@ public class DataUtils {
* The maximum byte to grow a buffer at a time.
*/
private static final int MAX_GROW = 16 * 1024 * 1024;
/**
* Get the length of the variable size int.
*
......@@ -805,7 +805,7 @@ public class DataUtils {
/**
* Parse a string as a number.
*
*
* @param x the number
* @param defaultValue if x is null
* @return the parsed value
......@@ -818,14 +818,14 @@ public class DataUtils {
try {
return Long.parseLong(x);
} catch (NumberFormatException e) {
throw newIllegalStateException(ERROR_FILE_CORRUPT,
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
......
......@@ -24,28 +24,64 @@ import org.h2.store.fs.FilePathNio;
*/
public class FileStore {
/**
* The number of read operations.
*/
protected long readCount;
/**
* The number of write operations.
*/
protected long writeCount;
/**
* The free spaces between the chunks. The first block to use is block 2
* (the first two blocks are the store header).
*/
protected final FreeSpaceBitSet freeSpace = new FreeSpaceBitSet(2, MVStore.BLOCK_SIZE);
/**
* The file name.
*/
protected String fileName;
/**
* Whether this store is read-only.
*/
protected boolean readOnly;
/**
* The file size (cached).
*/
protected long fileSize;
/**
* The file.
*/
protected FileChannel file;
protected FileLock fileLock;
/**
* The encrypted file (if encryption is used).
*/
protected FileChannel encryptedFile;
/**
* The file lock.
*/
protected FileLock fileLock;
@Override
public String toString() {
return fileName;
}
/**
* Read from the file.
*
* @param pos the write position
* @param len the number of bytes to read
* @return the byte buffer
*/
public ByteBuffer readFully(long pos, int len) {
readCount++;
ByteBuffer dst = ByteBuffer.allocate(len);
......@@ -53,12 +89,27 @@ public class FileStore {
return dst;
}
/**
* Write to the file.
*
* @param pos the write position
* @param src the source buffer
*/
public void writeFully(long pos, ByteBuffer src) {
writeCount++;
fileSize = Math.max(fileSize, pos + src.remaining());
DataUtils.writeFully(file, pos, src);
}
/**
* Try to open the file.
*
* @param fileName the file name
* @param readOnly whether the file should only be opened in read-only mode,
* even if the file is writable
* @param encryptionKey the encryption key, or null if encryption is not
* used
*/
public void open(String fileName, boolean readOnly, char[] encryptionKey) {
if (fileName != null && fileName.indexOf(':') < 0) {
// NIO is used, unless a different file system is specified
......@@ -80,6 +131,7 @@ public class FileStore {
file = f.open(readOnly ? "r" : "rw");
if (encryptionKey != null) {
byte[] password = FilePathCrypt.getPasswordBytes(encryptionKey);
encryptedFile = file;
file = new FilePathCrypt.FileCrypt(fileName, password, file);
}
file = FilePathCache.wrap(file);
......@@ -104,7 +156,10 @@ public class FileStore {
"Could not open file {0}", fileName, e);
}
}
/**
* Close this store.
*/
public void close() {
try {
if (fileLock != null) {
......@@ -121,7 +176,10 @@ public class FileStore {
file = null;
}
}
/**
* Flush all changes.
*/
public void sync() {
try {
file.force(true);
......@@ -131,11 +189,21 @@ public class FileStore {
"Could not sync file {0}", fileName, e);
}
}
/**
* Get the file size.
*
* @return the file size
*/
public long size() {
return fileSize;
}
/**
* Truncate the file.
*
* @param size the new file size
*/
public void truncate(long size) {
try {
writeCount++;
......@@ -150,29 +218,43 @@ public class FileStore {
}
/**
* 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.
*
* Get the file instance in use.
* <p>
* 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 encrypted file instance, if encryption is used.
* <p>
* The application may read from the file (for example for online backup),
* but not write to it or truncate it.
*
* @return the encrypted file, or null if encryption is not used
*/
public FileChannel getEncryptedFile() {
return encryptedFile;
}
/**
* Get the number of write operations since this store was opened.
* 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() {
......@@ -183,14 +265,31 @@ public class FileStore {
return readOnly;
}
/**
* Get the default retention time for this store in milliseconds.
*
* @return the retention time
*/
public int getDefaultRetentionTime() {
return 45000;
}
public void markUsed(long start, int len) {
freeSpace.markUsed(start, len);
/**
* Mark the space as in use.
*
* @param pos the position in bytes
* @param length the number of bytes
*/
public void markUsed(long pos, int length) {
freeSpace.markUsed(pos, length);
}
/**
* Allocate a number of blocks and mark them as used.
*
* @param length the number of bytes to allocate
* @return the start position in bytes
*/
public long allocate(int length) {
return freeSpace.allocate(length);
}
......@@ -213,6 +312,9 @@ public class FileStore {
return freeSpace.getFirstFree();
}
/**
* Mark the file as empty.
*/
public void clear() {
freeSpace.clear();
}
......
......@@ -986,7 +986,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
/**
* 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
......@@ -994,10 +994,10 @@ public class MVMap<K, V> extends AbstractMap<K, V>
long size = sizeAsLong();
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() {
......
......@@ -48,7 +48,7 @@ TestMVStoreDataLoss
MVTableEngine:
- use StreamStore
- when the MVStore was enabled before, use it again
(probably by checking existence of the mvstore file)
(probably by checking existence of the mvstore file)
TransactionStore:
......@@ -62,46 +62,32 @@ MVStore:
- defragment (re-creating maps, specially those with small pages)
- chunk header: store changed chunk data as row; maybe after the root
- chunk checksum (header, last page, 2 bytes per page?)
- on insert, if the child page is already full, don't load and modify it
split directly (specially for leaves with one large entry)
- maybe let a chunk point to a list of potential next chunks
(so no fixed location header is needed), similar to a skip list
- triggers (can be implemented with a custom map);
maybe implement database indexing with triggers
- store number of write operations per page (maybe defragment
if much different than count)
- r-tree: nearest neighbor search
- support maps without values (just existence of the key)
- support maps without keys (counted b-tree features)
- use a small object value cache (StringCache), test on Android
for default serialization
- MVStoreTool.dump: dump values (using a callback)
- map split / merge (fast if no overlap)
(use case: partitioning)
- StreamStore optimization: avoid copying bytes in memory
- Feature shrink a store (create, copy, rename, delete)
and for MVStore on Windows, auto-detect renamed file
- ensure data is overwritten eventually if the system doesn't have a
real-time clock (Raspberry Pi) and if there are few writes per startup
- ensure data is overwritten eventually if the system doesn't have a
real-time clock (Raspberry Pi) and if there are few writes per startup
- SSD-friendly write (always in blocks of 4 MB / 1 second?)
- close the file on out of memory or disk write error (out of disk space or so)
- implement a sharded map (in one store, multiple stores)
to support concurrent updates and writes, and very large maps
- maybe support for writing to branches
- maybe add an optional finalizer and exit hook
to store committed changes
- to save space when persisting very small transactions,
use a transaction log where only the deltas are stored
- serialization for lists, sets, sets, sorted sets, maps, sorted maps
- maybe rename 'rollback' to 'revert' to distinguish from transactions
- support other compression algorithms (deflate, LZ4,...)
- only retain the last version, unless explicitly set (setRetainVersion)
- support opening (existing) maps by id
- more consistent null handling (keys/values sometimes may be null)
- autocommit (to avoid having to call commit,
as it could be called too often or it is easily forgotten)
- remove features that are not really needed; simplify the code
possibly using a separate layer or tools
(retainVersion?)
- rename "store" to "save", as "store" is used in "storeVersion"
- MVStoreTool.dump should dump the data if possible;
possibly using a callback for serialization
......@@ -114,8 +100,8 @@ MVStore:
- simple rollback method (rollback to last committed version)
- MVMap to implement SortedMap, then NavigableMap
- Test with OSGi
- storage that splits database into multiple files,
to speed up compact and allow using trim
- storage that splits database into multiple files,
to speed up compact and allow using trim
(by truncating / deleting empty files)
*/
......@@ -138,20 +124,20 @@ public class MVStore {
private static final int FORMAT_WRITE = 1;
private static final int FORMAT_READ = 1;
/**
* The background thread, if any.
*/
volatile Thread backgroundThread;
private volatile boolean reuseSpace = true;
private boolean closed;
private FileStore fileStore;
private final int pageSplitSize;
private long rootChunkStart;
/**
......@@ -189,7 +175,7 @@ public class MVStore {
private ByteBuffer writeBuffer;
private int lastMapId;
private long retainVersion = -1;
/**
......@@ -197,7 +183,7 @@ public class MVStore {
* (old) compressed pages.
*/
private final boolean compress;
private final Compressor compressor = new CompressLZF();
private final UncaughtExceptionHandler backgroundExceptionHandler;
......@@ -208,7 +194,7 @@ public class MVStore {
* The version of the last stored chunk.
*/
private long lastStoredVersion;
private int unsavedPageCount;
private int unsavedPageCountMax;
......@@ -245,6 +231,7 @@ public class MVStore {
/**
* Create and open the store.
*
* @param config the configuration to use
* @throws IllegalStateException if the file is corrupt, or an exception
* occurred while opening
* @throws IllegalArgumentException if the directory does not exist
......@@ -302,7 +289,7 @@ public class MVStore {
if (format > FORMAT_WRITE && !fileStore.isReadOnly()) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_UNSUPPORTED_FORMAT,
"The write format {0} is larger than the supported format {1}, " +
"The write format {0} is larger than the supported format {1}, " +
"and the file was not opened in read-only mode",
format, FORMAT_WRITE);
}
......@@ -316,7 +303,7 @@ public class MVStore {
if (rootChunkStart > 0) {
readMeta();
}
}
}
long rollback = DataUtils.parseLong(meta.get("rollbackOnOpen"), -1);
if (rollback != -1) {
rollbackTo(rollback);
......@@ -682,12 +669,14 @@ public class MVStore {
if (shrinkIfPossible) {
shrinkFileIfPossible(0);
}
// release memory early - this is important when called
// because of out of memory
cache.clear();
for (MVMap<?, ?> m : New.arrayList(maps.values())) {
m.close();
}
meta = null;
chunks.clear();
cache.clear();
maps.clear();
try {
fileStore.close();
......@@ -1074,7 +1063,7 @@ public class MVStore {
/**
* Get the position of the last used byte.
*
*
* @return the position
*/
private long getEndPosition() {
......@@ -1498,7 +1487,7 @@ public class MVStore {
* depending on the operating system and hardware.
* <p>
* This setting is not persisted.
*
*
* @param ms how many milliseconds to retain old chunks (0 to overwrite them
* as early as possible)
*/
......@@ -1518,7 +1507,7 @@ public class MVStore {
/**
* Get the oldest version to retain in memory.
*
*
* @return the version
*/
public long getRetainVersion() {
......@@ -1533,7 +1522,7 @@ public class MVStore {
/**
* Get the oldest version to retain in memory, which is the manually set
* retain version, or the current store version (whatever is older).
*
*
* @return the version
*/
long getRetainOrStoreVersion() {
......@@ -1791,7 +1780,7 @@ public class MVStore {
/**
* Get the file store.
*
*
* @return the file store
*/
public FileStore getFileStore() {
......@@ -1884,9 +1873,9 @@ public class MVStore {
*
* @param mb the cache size in MB.
*/
public void setCacheSize(long mb) {
public void setCacheSize(int mb) {
if (cache != null) {
cache.setMaxMemory(mb * 1024 * 1024);
cache.setMaxMemory((long) mb * 1024 * 1024);
}
}
......@@ -2099,10 +2088,10 @@ public class MVStore {
Thread.UncaughtExceptionHandler exceptionHandler) {
return set("backgroundExceptionHandler", exceptionHandler);
}
/**
* Use the provided file store instead of the default one.
*
*
* @param store the file store
* @return this
*/
......
......@@ -16,24 +16,24 @@ import java.util.TreeMap;
* memory.
*/
public class OffHeapStore extends FileStore {
private final TreeMap<Long, ByteBuffer> memory = new TreeMap<Long, ByteBuffer>();
@Override
public void open(String fileName, boolean readOnly, char[] encryptionKey) {
// nothing to do
}
@Override
public String toString() {
return memory.toString();
}
@Override
public ByteBuffer readFully(long pos, int len) {
Entry<Long, ByteBuffer> memEntry = memory.floorEntry(pos);
if (memEntry == null) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Could not read from position {0}", pos);
}
readCount++;
......@@ -44,20 +44,20 @@ public class OffHeapStore extends FileStore {
read.limit(len + offset);
return read.slice();
}
@Override
public void free(long pos, int length) {
freeSpace.free(pos, length);
ByteBuffer buff = memory.remove(pos);
ByteBuffer buff = memory.remove(pos);
if (buff == null) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Could not find entry at position {0}", pos);
} else if (buff.remaining() != length) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Partial remove is not supported at position {0}", pos);
}
}
@Override
public void writeFully(long pos, ByteBuffer src) {
fileSize = Math.max(fileSize, pos + src.remaining());
......@@ -73,7 +73,7 @@ public class OffHeapStore extends FileStore {
int length = src.remaining();
if (prevPos == pos) {
if (prevLength != length) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Could not write to position {0}; partial overwrite is not supported", pos);
}
writeCount++;
......@@ -82,12 +82,12 @@ public class OffHeapStore extends FileStore {
return;
}
if (prevPos + prevLength > pos) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Could not write to position {0}; partial overwrite is not supported", pos);
}
writeNewEntry(pos, src);
}
private void writeNewEntry(long pos, ByteBuffer src) {
writeCount++;
int length = src.remaining();
......@@ -112,27 +112,27 @@ public class OffHeapStore extends FileStore {
}
ByteBuffer buff = memory.get(pos);
if (buff.capacity() > size) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
throw DataUtils.newIllegalStateException(DataUtils.ERROR_READING_FAILED,
"Could not truncate to {0}; partial truncate is not supported", pos);
}
it.remove();
}
}
@Override
public void close() {
truncate(0);
freeSpace.clear();
}
@Override
public void sync() {
// nothing to do
}
@Override
public int getDefaultRetentionTime() {
return 0;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论