提交 5831e75e authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #553 from andreitokar/mem_optimization

eliminate memory estimations for "mem:" case
...@@ -72,7 +72,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -72,7 +72,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
protected MVMap(DataType keyType, DataType valueType) { protected MVMap(DataType keyType, DataType valueType) {
this.keyType = keyType; this.keyType = keyType;
this.valueType = valueType; this.valueType = valueType;
this.root = Page.createEmpty(this, -1);
} }
/** /**
...@@ -106,6 +105,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -106,6 +105,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
this.id = DataUtils.readHexInt(config, "id", 0); this.id = DataUtils.readHexInt(config, "id", 0);
this.createVersion = DataUtils.readHexLong(config, "createVersion", 0); this.createVersion = DataUtils.readHexLong(config, "createVersion", 0);
this.writeVersion = store.getCurrentVersion(); this.writeVersion = store.getCurrentVersion();
this.root = Page.createEmpty(this, -1);
} }
/** /**
......
...@@ -120,7 +120,7 @@ MVStore: ...@@ -120,7 +120,7 @@ MVStore:
/** /**
* A persistent storage for maps. * A persistent storage for maps.
*/ */
public class MVStore { public final class MVStore {
/** /**
* Whether assertions are enabled. * Whether assertions are enabled.
...@@ -292,12 +292,21 @@ public class MVStore { ...@@ -292,12 +292,21 @@ public class MVStore {
Object o = config.get("compress"); Object o = config.get("compress");
this.compressionLevel = o == null ? 0 : (Integer) o; this.compressionLevel = o == null ? 0 : (Integer) o;
String fileName = (String) config.get("fileName"); String fileName = (String) config.get("fileName");
fileStore = (FileStore) config.get("fileStore");
fileStoreIsProvided = fileStore != null;
if(fileStore == null && fileName != null) {
fileStore = new FileStore();
}
o = config.get("pageSplitSize"); o = config.get("pageSplitSize");
if (o == null) { int pgSplitSize;
pageSplitSize = fileName == null ? 4 * 1024 : 16 * 1024; if (o != null) {
pgSplitSize = (Integer) o;
} else if(fileStore != null) {
pgSplitSize = 16 * 1024;
} else { } else {
pageSplitSize = (Integer) o; pgSplitSize = 48; // number of keys per page in that case
} }
pageSplitSize = pgSplitSize;
o = config.get("backgroundExceptionHandler"); o = config.get("backgroundExceptionHandler");
this.backgroundExceptionHandler = (UncaughtExceptionHandler) o; this.backgroundExceptionHandler = (UncaughtExceptionHandler) o;
meta = new MVMap<String, String>(StringDataType.INSTANCE, meta = new MVMap<String, String>(StringDataType.INSTANCE,
...@@ -306,18 +315,11 @@ public class MVStore { ...@@ -306,18 +315,11 @@ public class MVStore {
c.put("id", 0); c.put("id", 0);
c.put("createVersion", currentVersion); c.put("createVersion", currentVersion);
meta.init(this, c); meta.init(this, c);
fileStore = (FileStore) config.get("fileStore"); if (fileStore == null) {
if (fileName == null && fileStore == null) {
cache = null; cache = null;
cacheChunkRef = null; cacheChunkRef = null;
return; return;
} }
if (fileStore == null) {
fileStoreIsProvided = false;
fileStore = new FileStore();
} else {
fileStoreIsProvided = true;
}
retentionTime = fileStore.getDefaultRetentionTime(); retentionTime = fileStore.getDefaultRetentionTime();
boolean readOnly = config.containsKey("readOnly"); boolean readOnly = config.containsKey("readOnly");
o = config.get("cacheSize"); o = config.get("cacheSize");
...@@ -995,7 +997,7 @@ public class MVStore { ...@@ -995,7 +997,7 @@ public class MVStore {
* *
* @return the new version * @return the new version
*/ */
public long commit() { public synchronized long commit() {
if (fileStore != null) { if (fileStore != null) {
return commitAndSave(); return commitAndSave();
} }
......
...@@ -36,6 +36,7 @@ public class Page { ...@@ -36,6 +36,7 @@ public class Page {
* An empty object array. * An empty object array.
*/ */
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
private static final int IN_MEMORY = Integer.MIN_VALUE;
private final MVMap<?, ?> map; private final MVMap<?, ?> map;
private long version; private long version;
...@@ -52,7 +53,7 @@ public class Page { ...@@ -52,7 +53,7 @@ public class Page {
private int cachedCompare; private int cachedCompare;
/** /**
* The estimated memory used. * The estimated memory used in persistent case, IN_MEMORY marker value otherwise.
*/ */
private int memory; private int memory;
...@@ -125,13 +126,15 @@ public class Page { ...@@ -125,13 +126,15 @@ public class Page {
p.values = values; p.values = values;
p.children = children; p.children = children;
p.totalCount = totalCount; p.totalCount = totalCount;
if (memory == 0) { MVStore store = map.store;
if(store.getFileStore() == null) {
p.memory = IN_MEMORY;
} else if (memory == 0) {
p.recalculateMemory(); p.recalculateMemory();
} else { } else {
p.addMemory(memory); p.addMemory(memory);
} }
MVStore store = map.store; if(store.getFileStore() != null) {
if (store != null) {
store.registerUnsavedPage(p.memory); store.registerUnsavedPage(p.memory);
} }
return p; return p;
...@@ -146,18 +149,8 @@ public class Page { ...@@ -146,18 +149,8 @@ public class Page {
* @return the page * @return the page
*/ */
public static Page create(MVMap<?, ?> map, long version, Page source) { public static Page create(MVMap<?, ?> map, long version, Page source) {
Page p = new Page(map, version); return create(map, version, source.keys, source.values, source.children,
// the position is 0 source.totalCount, source.memory);
p.keys = source.keys;
p.values = source.values;
p.children = source.children;
p.totalCount = source.totalCount;
p.memory = source.memory;
MVStore store = map.store;
if (store != null) {
store.registerUnsavedPage(p.memory);
}
return p;
} }
/** /**
...@@ -302,7 +295,7 @@ public class Page { ...@@ -302,7 +295,7 @@ public class Page {
Page newPage = create(map, version, Page newPage = create(map, version,
keys, values, keys, values,
children, totalCount, children, totalCount,
getMemory()); memory);
// mark the old as deleted // mark the old as deleted
removePage(); removePage();
newPage.cachedCompare = cachedCompare; newPage.cachedCompare = cachedCompare;
...@@ -368,7 +361,11 @@ public class Page { ...@@ -368,7 +361,11 @@ public class Page {
* @return the page with the entries after the split index * @return the page with the entries after the split index
*/ */
Page split(int at) { Page split(int at) {
return isLeaf() ? splitLeaf(at) : splitNode(at); Page page = isLeaf() ? splitLeaf(at) : splitNode(at);
if(isPersistent()) {
recalculateMemory();
}
return page;
} }
private Page splitLeaf(int at) { private Page splitLeaf(int at) {
...@@ -388,9 +385,7 @@ public class Page { ...@@ -388,9 +385,7 @@ public class Page {
Page newPage = create(map, version, Page newPage = create(map, version,
bKeys, bValues, bKeys, bValues,
null, null,
bKeys.length, 0); b, 0);
recalculateMemory();
newPage.recalculateMemory();
return newPage; return newPage;
} }
...@@ -422,8 +417,6 @@ public class Page { ...@@ -422,8 +417,6 @@ public class Page {
bKeys, null, bKeys, null,
bChildren, bChildren,
t, 0); t, 0);
recalculateMemory();
newPage.recalculateMemory();
return newPage; return newPage;
} }
...@@ -498,13 +491,15 @@ public class Page { ...@@ -498,13 +491,15 @@ public class Page {
// this is slightly slower: // this is slightly slower:
// keys = Arrays.copyOf(keys, keys.length); // keys = Arrays.copyOf(keys, keys.length);
keys = keys.clone(); keys = keys.clone();
Object old = keys[index]; if(isPersistent()) {
DataType keyType = map.getKeyType(); Object old = keys[index];
int mem = keyType.getMemory(key); DataType keyType = map.getKeyType();
if (old != null) { int mem = keyType.getMemory(key);
mem -= keyType.getMemory(old); if (old != null) {
mem -= keyType.getMemory(old);
}
addMemory(mem);
} }
addMemory(mem);
keys[index] = key; keys[index] = key;
} }
...@@ -521,8 +516,10 @@ public class Page { ...@@ -521,8 +516,10 @@ public class Page {
// values = Arrays.copyOf(values, values.length); // values = Arrays.copyOf(values, values.length);
values = values.clone(); values = values.clone();
DataType valueType = map.getValueType(); DataType valueType = map.getValueType();
addMemory(valueType.getMemory(value) - if(isPersistent()) {
valueType.getMemory(old)); addMemory(valueType.getMemory(value) -
valueType.getMemory(old));
}
values[index] = value; values[index] = value;
return old; return old;
} }
...@@ -569,8 +566,10 @@ public class Page { ...@@ -569,8 +566,10 @@ public class Page {
keys[index] = key; keys[index] = key;
values[index] = value; values[index] = value;
totalCount++; totalCount++;
addMemory(map.getKeyType().getMemory(key) + if(isPersistent()) {
map.getValueType().getMemory(value)); addMemory(map.getKeyType().getMemory(key) +
map.getValueType().getMemory(value));
}
} }
/** /**
...@@ -595,8 +594,10 @@ public class Page { ...@@ -595,8 +594,10 @@ public class Page {
children = newChildren; children = newChildren;
totalCount += childPage.totalCount; totalCount += childPage.totalCount;
addMemory(map.getKeyType().getMemory(key) + if(isPersistent()) {
DataUtils.PAGE_MEMORY_CHILD); addMemory(map.getKeyType().getMemory(key) +
DataUtils.PAGE_MEMORY_CHILD);
}
} }
/** /**
...@@ -607,22 +608,28 @@ public class Page { ...@@ -607,22 +608,28 @@ public class Page {
public void remove(int index) { public void remove(int index) {
int keyLength = keys.length; int keyLength = keys.length;
int keyIndex = index >= keyLength ? index - 1 : index; int keyIndex = index >= keyLength ? index - 1 : index;
Object old = keys[keyIndex]; if(isPersistent()) {
addMemory(-map.getKeyType().getMemory(old)); Object old = keys[keyIndex];
addMemory(-map.getKeyType().getMemory(old));
}
Object[] newKeys = new Object[keyLength - 1]; Object[] newKeys = new Object[keyLength - 1];
DataUtils.copyExcept(keys, newKeys, keyLength, keyIndex); DataUtils.copyExcept(keys, newKeys, keyLength, keyIndex);
keys = newKeys; keys = newKeys;
if (values != null) { if (values != null) {
old = values[index]; if(isPersistent()) {
addMemory(-map.getValueType().getMemory(old)); Object old = values[index];
addMemory(-map.getValueType().getMemory(old));
}
Object[] newValues = new Object[keyLength - 1]; Object[] newValues = new Object[keyLength - 1];
DataUtils.copyExcept(values, newValues, keyLength, index); DataUtils.copyExcept(values, newValues, keyLength, index);
values = newValues; values = newValues;
totalCount--; totalCount--;
} }
if (children != null) { if (children != null) {
addMemory(-DataUtils.PAGE_MEMORY_CHILD); if(isPersistent()) {
addMemory(-DataUtils.PAGE_MEMORY_CHILD);
}
long countOffset = children[index].count; long countOffset = children[index].count;
int childCount = children.length; int childCount = children.length;
...@@ -887,16 +894,23 @@ public class Page { ...@@ -887,16 +894,23 @@ public class Page {
return pos != 0 ? (int) (pos | (pos >>> 32)) : super.hashCode(); return pos != 0 ? (int) (pos | (pos >>> 32)) : super.hashCode();
} }
private boolean isPersistent() {
return memory != IN_MEMORY;
}
public int getMemory() { public int getMemory() {
if (MVStore.ASSERT) { if (isPersistent()) {
int mem = memory; if (MVStore.ASSERT) {
recalculateMemory(); int mem = memory;
if (mem != memory) { recalculateMemory();
throw DataUtils.newIllegalStateException( if (mem != memory) {
DataUtils.ERROR_INTERNAL, "Memory calculation error"); throw DataUtils.newIllegalStateException(
DataUtils.ERROR_INTERNAL, "Memory calculation error");
}
} }
return memory;
} }
return memory; return getKeyCount();
} }
private void addMemory(int mem) { private void addMemory(int mem) {
...@@ -928,11 +942,13 @@ public class Page { ...@@ -928,11 +942,13 @@ public class Page {
* Remove the page. * Remove the page.
*/ */
public void removePage() { public void removePage() {
long p = pos; if(isPersistent()) {
if (p == 0) { long p = pos;
removedInMemory = true; if (p == 0) {
removedInMemory = true;
}
map.removePage(p, memory);
} }
map.removePage(p, memory);
} }
/** /**
......
...@@ -1416,7 +1416,9 @@ public class TestMVStore extends TestBase { ...@@ -1416,7 +1416,9 @@ public class TestMVStore extends TestBase {
assertEquals(i + 1, m.size()); assertEquals(i + 1, m.size());
} }
assertEquals(1000, m.size()); assertEquals(1000, m.size());
assertEquals(131896, s.getUnsavedMemory()); // previously (131896) we fail to account for initial root page for every map
// there are two of them here (meta and "data"), hence lack of 256 bytes
assertEquals(132152, s.getUnsavedMemory());
s.commit(); s.commit();
assertEquals(2, s.getFileStore().getWriteCount()); assertEquals(2, s.getFileStore().getWriteCount());
s.close(); s.close();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论