提交 62061bef authored 作者: Thomas Mueller's avatar Thomas Mueller

MVStore bugfixes

上级 5a6bf821
...@@ -803,10 +803,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -803,10 +803,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
K key = (K) p.getKey(0); K key = (K) p.getKey(0);
V value = get(key); V value = get(key);
if (value != null) { if (value != null) {
// this is to avoid storing while replacing, to avoid a
// deadlock when rewriting the meta map
// TODO there should be no deadlocks possible
store.beforeWrite();
replace(key, value, value); replace(key, value, value);
} }
} }
...@@ -1047,7 +1043,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1047,7 +1043,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
throw DataUtils.newUnsupportedOperationException( throw DataUtils.newUnsupportedOperationException(
"This map is read-only"); "This map is read-only");
} }
store.beforeWrite(); store.beforeWrite(this);
} }
@Override @Override
......
...@@ -43,6 +43,9 @@ TransactionStore: ...@@ -43,6 +43,9 @@ TransactionStore:
if there is only one connection if there is only one connection
MVStore: MVStore:
- better and clearer memory usage accounting rules
(heap memory versus disk memory), so that even there is never an out of memory
even for a small heap, and so that chunks are still relatively big on average
- make sure serialization / deserialization errors don't corrupt the file - make sure serialization / deserialization errors don't corrupt the file
- FileStore: don't open and close when set using MVStore.Builder.fileStore - FileStore: don't open and close when set using MVStore.Builder.fileStore
- test and possibly improve compact operation (for large dbs) - test and possibly improve compact operation (for large dbs)
...@@ -271,6 +274,8 @@ public class MVStore { ...@@ -271,6 +274,8 @@ public class MVStore {
private Object compactSync = new Object(); private Object compactSync = new Object();
private IllegalStateException panicException;
/** /**
* Create and open the store. * Create and open the store.
* *
...@@ -326,7 +331,7 @@ public class MVStore { ...@@ -326,7 +331,7 @@ public class MVStore {
segmentCount, stackMoveDistance); segmentCount, stackMoveDistance);
} }
o = config.get("autoCommitBufferSize"); o = config.get("autoCommitBufferSize");
int kb = o == null ? 512 : (Integer) o; int kb = o == null ? 1024 : (Integer) o;
// 19 KB memory is about 1 KB storage // 19 KB memory is about 1 KB storage
autoCommitMemory = kb * 1024 * 19; autoCommitMemory = kb * 1024 * 19;
...@@ -366,11 +371,11 @@ public class MVStore { ...@@ -366,11 +371,11 @@ public class MVStore {
} }
private void panic(IllegalStateException e) { private void panic(IllegalStateException e) {
try { if (backgroundExceptionHandler != null) {
closeStore(false); backgroundExceptionHandler.uncaughtException(null, e);
} catch (Exception e2) {
// ignore
} }
panicException = e;
closeImmediately();
throw e; throw e;
} }
...@@ -772,7 +777,7 @@ public class MVStore { ...@@ -772,7 +777,7 @@ public class MVStore {
try { try {
fileStore.writeFully(pos, buffer); fileStore.writeFully(pos, buffer);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
closeImmediately(); panic(e);
throw e; throw e;
} }
} }
...@@ -1256,7 +1261,8 @@ public class MVStore { ...@@ -1256,7 +1261,8 @@ public class MVStore {
DataUtils.ERROR_FILE_CORRUPT, DataUtils.ERROR_FILE_CORRUPT,
"Negative position {0}", filePos); "Negative position {0}", filePos);
} }
r = PageChildren.read(fileStore, filePos, mapId, pos); long maxPos = (c.block + c.len) * BLOCK_SIZE;
r = PageChildren.read(fileStore, pos, mapId, filePos, maxPos);
} else { } else {
r = new PageChildren(p); r = new PageChildren(p);
} }
...@@ -1803,7 +1809,8 @@ public class MVStore { ...@@ -1803,7 +1809,8 @@ public class MVStore {
DataUtils.ERROR_FILE_CORRUPT, DataUtils.ERROR_FILE_CORRUPT,
"Negative position {0}", filePos); "Negative position {0}", filePos);
} }
p = Page.read(fileStore, map, pos, filePos, fileStore.size()); long maxPos = (c.block + c.len) * BLOCK_SIZE;
p = Page.read(fileStore, pos, map, filePos, maxPos);
cachePage(pos, p, p.getMemory()); cachePage(pos, p, p.getMemory());
} }
return p; return p;
...@@ -2042,9 +2049,18 @@ public class MVStore { ...@@ -2042,9 +2049,18 @@ public class MVStore {
/** /**
* This method is called before writing to a map. * This method is called before writing to a map.
*
* @param map the map
*/ */
void beforeWrite() { void beforeWrite(MVMap<?, ?> map) {
if (saveNeeded) { if (saveNeeded) {
if (map == meta) {
// to, don't save while the metadata map is locked
// this is to avoid deadlocks that could occur when we
// synchronize on the store and then on the metadata map
// TODO there should be no deadlocks possible
return;
}
saveNeeded = false; saveNeeded = false;
// check again, because it could have been written by now // check again, because it could have been written by now
if (unsavedMemory > autoCommitMemory && autoCommitMemory > 0) { if (unsavedMemory > autoCommitMemory && autoCommitMemory > 0) {
...@@ -2242,7 +2258,7 @@ public class MVStore { ...@@ -2242,7 +2258,7 @@ public class MVStore {
private void checkOpen() { private void checkOpen() {
if (closed) { if (closed) {
throw DataUtils.newIllegalStateException(DataUtils.ERROR_CLOSED, throw DataUtils.newIllegalStateException(DataUtils.ERROR_CLOSED,
"This store is closed"); "This store is closed", panicException);
} }
} }
...@@ -2298,6 +2314,7 @@ public class MVStore { ...@@ -2298,6 +2314,7 @@ public class MVStore {
* @return the name, or null if not found * @return the name, or null if not found
*/ */
public synchronized String getMapName(int id) { public synchronized String getMapName(int id) {
checkOpen();
String m = meta.get(MVMap.getMapKey(id)); String m = meta.get(MVMap.getMapKey(id));
return m == null ? null : DataUtils.parseMap(m).get("name"); return m == null ? null : DataUtils.parseMap(m).get("name");
} }
...@@ -2571,7 +2588,7 @@ public class MVStore { ...@@ -2571,7 +2588,7 @@ public class MVStore {
* stores). Unless auto-commit is disabled, changes are automatically * stores). Unless auto-commit is disabled, changes are automatically
* saved if there are more than this amount of changes. * saved if there are more than this amount of changes.
* <p> * <p>
* The default is 512 KB. * The default is 1024 KB.
* <p> * <p>
* When the value is set to 0 or lower, data is not automatically * When the value is set to 0 or lower, data is not automatically
* stored. * stored.
......
...@@ -163,14 +163,14 @@ public class Page { ...@@ -163,14 +163,14 @@ public class Page {
* Read a page. * Read a page.
* *
* @param fileStore the file store * @param fileStore the file store
* @param pos the position
* @param map the map * @param map the map
* @param pos the page position
* @param filePos the position in the file * @param filePos the position in the file
* @param fileSize the file size (to avoid reading past EOF) * @param maxPos the maximum position (the end of the chunk)
* @return the page * @return the page
*/ */
static Page read(FileStore fileStore, MVMap<?, ?> map, static Page read(FileStore fileStore, long pos, MVMap<?, ?> map,
long pos, long filePos, long fileSize) { long filePos, long maxPos) {
ByteBuffer buff; ByteBuffer buff;
int maxLength = DataUtils.getPageMaxLength(pos); int maxLength = DataUtils.getPageMaxLength(pos);
if (maxLength == DataUtils.PAGE_LARGE) { if (maxLength == DataUtils.PAGE_LARGE) {
...@@ -178,13 +178,13 @@ public class Page { ...@@ -178,13 +178,13 @@ public class Page {
maxLength = buff.getInt(); maxLength = buff.getInt();
// read the first bytes again // read the first bytes again
} }
maxLength = (int) Math.min(fileSize - filePos, maxLength); maxLength = (int) Math.min(maxPos - filePos, maxLength);
int length = maxLength; int length = maxLength;
if (length < 0) { if (length < 0) {
throw DataUtils.newIllegalStateException( throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, DataUtils.ERROR_FILE_CORRUPT,
"Illegal page length {0} reading at {1}; file size {2} ", "Illegal page length {0} reading at {1}; max pos {2} ",
length, filePos, fileSize); length, filePos, maxPos);
} }
buff = fileStore.readFully(filePos, length); buff = fileStore.readFully(filePos, length);
Page p = new Page(map, 0); Page p = new Page(map, 0);
...@@ -1003,12 +1003,14 @@ public class Page { ...@@ -1003,12 +1003,14 @@ public class Page {
* values. * values.
* *
* @param fileStore the file store * @param fileStore the file store
* @param filePos the position in the file
* @param mapId the map id
* @param pos the position * @param pos the position
* @param mapId the map id
* @param filePos the position in the file
* @param maxPos the maximum position (the end of the chunk)
* @return the page children object * @return the page children object
*/ */
static PageChildren read(FileStore fileStore, long filePos, int mapId, long pos) { static PageChildren read(FileStore fileStore, long pos, int mapId,
long filePos, long maxPos) {
ByteBuffer buff; ByteBuffer buff;
int maxLength = DataUtils.getPageMaxLength(pos); int maxLength = DataUtils.getPageMaxLength(pos);
if (maxLength == DataUtils.PAGE_LARGE) { if (maxLength == DataUtils.PAGE_LARGE) {
...@@ -1016,14 +1018,13 @@ public class Page { ...@@ -1016,14 +1018,13 @@ public class Page {
maxLength = buff.getInt(); maxLength = buff.getInt();
// read the first bytes again // read the first bytes again
} }
long fileSize = fileStore.fileSize; maxLength = (int) Math.min(maxPos - filePos, maxLength);
maxLength = (int) Math.min(fileSize - filePos, maxLength);
int length = maxLength; int length = maxLength;
if (length < 0) { if (length < 0) {
throw DataUtils.newIllegalStateException( throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, DataUtils.ERROR_FILE_CORRUPT,
"Illegal page length {0} reading at {1}; file size {2} ", "Illegal page length {0} reading at {1}; max pos {2} ",
length, filePos, fileSize); length, filePos, maxPos);
} }
buff = fileStore.readFully(filePos, length); buff = fileStore.readFully(filePos, length);
int chunkId = DataUtils.getPageChunkId(pos); int chunkId = DataUtils.getPageChunkId(pos);
......
...@@ -1267,7 +1267,9 @@ public class ObjectDataType implements DataType { ...@@ -1267,7 +1267,9 @@ public class ObjectDataType implements DataType {
} }
} }
} }
return size; // we say they are larger, because these objects
// use quite a lot of disk space
return size * 2;
} }
@Override @Override
...@@ -1527,7 +1529,9 @@ public class ObjectDataType implements DataType { ...@@ -1527,7 +1529,9 @@ public class ObjectDataType implements DataType {
return; return;
} }
byte[] data = serialize(obj); byte[] data = serialize(obj);
int size = data.length; // we say they are larger, because these objects
// use quite a lot of disk space
int size = data.length * 2;
// adjust the average size // adjust the average size
// using an exponential moving average // using an exponential moving average
averageSize = (size + 15 * averageSize) / 16; averageSize = (size + 15 * averageSize) / 16;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论