Unverified 提交 c0d55ffd authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1687 from h2database/mvmap-refact

MVMap minor cleanup
...@@ -799,11 +799,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -799,11 +799,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return rootReference; return rootReference;
} }
final void setRoot(Page rootPage) {
int attempt = 0;
while (setNewRoot(null, rootPage, ++attempt, false) == null) {/**/}
}
/** /**
* Set the initial root. * Set the initial root.
* *
...@@ -814,51 +809,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -814,51 +809,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
root.set(new RootReference(rootPage, version)); root.set(new RootReference(rootPage, version));
} }
/**
* Try to set the new root reference from now on.
*
* @param oldRoot previous root reference
* @param newRootPage the new root page
* @param attemptUpdateCounter how many attempt (including current)
* were made to update root
* @param obeyLock false means override root even if it's marked as locked (used to unlock)
* true will fail to update, if root is currently locked
* @return new RootReference or null if update failed
*/
private RootReference setNewRoot(RootReference oldRoot, Page newRootPage,
int attemptUpdateCounter, boolean obeyLock) {
RootReference currentRoot = flushAndGetRoot();
assert newRootPage != null || currentRoot != null;
if (currentRoot != oldRoot && oldRoot != null) {
return null;
}
RootReference previous = currentRoot;
int appendCounter = 0;
long updateCounter = 1;
long newVersion = INITIAL_VERSION;
if(currentRoot != null) {
if (obeyLock && currentRoot.lockedForUpdate) {
return null;
}
if (newRootPage == null) {
newRootPage = currentRoot.root;
}
newVersion = currentRoot.version;
previous = currentRoot.previous;
appendCounter = currentRoot.getAppendCounter();
updateCounter += currentRoot.updateCounter;
attemptUpdateCounter += currentRoot.updateAttemptCounter;
}
RootReference updatedRootReference = new RootReference(newRootPage, newVersion, previous, appendCounter,
updateCounter, attemptUpdateCounter);
boolean success = root.compareAndSet(currentRoot, updatedRootReference);
return success ? updatedRootReference : null;
}
/** /**
* Rollback to the given version. * Rollback to the given version.
* *
...@@ -891,15 +841,19 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -891,15 +841,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
/** /**
* Use the new root page from now on. * Use the new root page from now on.
* @param oldRoot the old root reference, will use the current root reference, * @param expectedRootRefrence expected current root reference
* if null is specified * @param newRootPage the new root page
* @param newRoot the new root page
* @param attemptUpdateCounter how many attempt (including current) * @param attemptUpdateCounter how many attempt (including current)
* were made to update root * were made to update root
* @return new RootReference or null if update failed * @return new RootReference or null if update failed
*/ */
protected final boolean updateRoot(RootReference oldRoot, Page newRoot, int attemptUpdateCounter) { protected final boolean updateRoot(RootReference expectedRootRefrence, Page newRootPage,
return setNewRoot(oldRoot, newRoot, attemptUpdateCounter, true) != null; int attemptUpdateCounter) {
RootReference currentRoot = flushAndGetRoot();
return currentRoot == expectedRootRefrence &&
!currentRoot.lockedForUpdate &&
root.compareAndSet(currentRoot,
new RootReference(currentRoot, newRootPage, attemptUpdateCounter));
} }
/** /**
...@@ -995,15 +949,12 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -995,15 +949,12 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @return the number of entries * @return the number of entries
*/ */
public final long sizeAsLong() { public final long sizeAsLong() {
RootReference rootReference = getRoot(); return getRoot().getTotalCount();
return rootReference.root.getTotalCount() + rootReference.getAppendCounter();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
RootReference rootReference = getRoot(); return sizeAsLong() == 0;
Page rootPage = rootReference.root;
return rootPage.isLeaf() && rootPage.getKeyCount() == 0 && rootReference.getAppendCounter() == 0;
} }
public final long getCreateVersion() { public final long getCreateVersion() {
...@@ -1204,7 +1155,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1204,7 +1155,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
private Page copy(Page source, Page parent, int index) { private Page copy(Page source, Page parent, int index) {
Page target = source.copy(this); Page target = source.copy(this);
if (parent == null) { if (parent == null) {
setRoot(target); setInitialRoot(target, INITIAL_VERSION);
} else { } else {
parent.setChild(index, target); parent.setChild(index, target);
} }
...@@ -1344,7 +1295,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1344,7 +1295,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} finally { } finally {
if (lockedRootReference != null && !lockedForUpdate) { if (lockedRootReference != null && !lockedForUpdate) {
assert rootReference.root == lockedRootReference.root; assert rootReference.root == lockedRootReference.root;
rootReference = unlockRoot(lockedRootReference.root, lockedRootReference.appendCounter); rootReference = unlockRoot();
} }
} }
return rootReference; return rootReference;
...@@ -1420,111 +1371,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1420,111 +1371,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return asString(null); return asString(null);
} }
public static final class RootReference
{
/**
* The root page.
*/
public final Page root;
/**
* The version used for writing.
*/
public final long version;
/**
* Indicator that map is locked for update.
*/
final boolean lockedForUpdate;
/**
* Reference to the previous root in the chain.
*/
public volatile RootReference previous;
/**
* Counter for successful root updates.
*/
public final long updateCounter;
/**
* Counter for attempted root updates.
*/
public final long updateAttemptCounter;
/**
* Size of the occupied part of the append buffer.
*/
public final byte appendCounter;
RootReference(Page root, long version, RootReference previous, int appendCounter, long updateCounter,
long updateAttemptCounter) {
this.root = root;
this.version = version;
this.previous = previous;
this.updateCounter = updateCounter;
this.updateAttemptCounter = updateAttemptCounter;
this.lockedForUpdate = false;
this.appendCounter = (byte)appendCounter;
}
// This one is used for locking
RootReference(RootReference r, int attempt) {
this.root = r.root;
this.version = r.version;
this.previous = r.previous;
this.updateCounter = r.updateCounter + 1;
this.updateAttemptCounter = r.updateAttemptCounter + attempt;
this.lockedForUpdate = true;
this.appendCounter = r.appendCounter;
}
// This one is used for unlocking
RootReference(RootReference r, Page root, int appendCounter, boolean lockedForUpdate) {
this.root = root;
this.version = r.version;
this.previous = r.previous;
this.updateCounter = r.updateCounter;
this.updateAttemptCounter = r.updateAttemptCounter;
this.lockedForUpdate = lockedForUpdate;
this.appendCounter = (byte)appendCounter;
}
// This one is used for version change
RootReference(RootReference r, long version, int attempt) {
RootReference previous = r;
RootReference tmp;
while ((tmp = previous.previous) != null && tmp.root == r.root) {
previous = tmp;
}
this.root = r.root;
this.version = version;
this.previous = previous;
this.updateCounter = r.updateCounter + 1;
this.updateAttemptCounter = r.updateAttemptCounter + attempt;
this.lockedForUpdate = r.lockedForUpdate;
this.appendCounter = r.appendCounter;
}
// This one is used for r/o snapshots
RootReference(Page root, long version) {
this.root = root;
this.version = version;
this.previous = null;
this.updateCounter = 1;
this.updateAttemptCounter = 1;
this.lockedForUpdate = false;
this.appendCounter = 0;
}
public int getAppendCounter() {
return appendCounter & 0xff;
}
public long getTotalCount() {
return root.getTotalCount() + getAppendCounter();
}
@Override
public String toString() {
return "RootReference("+ System.identityHashCode(root)+","+version+","+ lockedForUpdate +")";
}
}
/** /**
* A builder for maps. * A builder for maps.
* *
...@@ -1826,7 +1672,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1826,7 +1672,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
rootReference = lockedRootReference; rootReference = lockedRootReference;
} }
Page rootPage = rootReference.root; Page rootPage = rootReference.root;
int appendCounter = rootReference.getAppendCounter();
CursorPos tip; CursorPos tip;
V result; V result;
unsavedMemoryHolder.value = 0; unsavedMemoryHolder.value = 0;
...@@ -1918,7 +1763,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1918,7 +1763,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} }
} finally { } finally {
if(lockedRootReference != null) { if(lockedRootReference != null) {
unlockRoot(rootPage, appendCounter); unlockRoot(rootPage);
} }
} }
while (tip != null) { while (tip != null) {
...@@ -1984,13 +1829,24 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1984,13 +1829,24 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return null; return null;
} }
private RootReference unlockRoot(Page newRoot, int appendCounter) { private RootReference unlockRoot() {
return unlockRoot(null, -1);
}
private RootReference unlockRoot(Page newRootPage) {
return unlockRoot(newRootPage, -1);
}
private RootReference unlockRoot(Page newRootPage, int appendCounter) {
RootReference updatedRootReference; RootReference updatedRootReference;
boolean success; boolean success;
do { do {
RootReference rootReference = getRoot(); RootReference rootReference = getRoot();
assert rootReference.lockedForUpdate; assert rootReference.lockedForUpdate;
updatedRootReference = new RootReference(rootReference, newRoot, appendCounter, false); updatedRootReference = new RootReference(rootReference,
newRootPage == null ? rootReference.root : newRootPage,
appendCounter == -1 ? rootReference.getAppendCounter() : appendCounter,
false);
success = root.compareAndSet(rootReference, updatedRootReference); success = root.compareAndSet(rootReference, updatedRootReference);
} while(!success); } while(!success);
......
...@@ -505,9 +505,12 @@ public class MVStore implements AutoCloseable { ...@@ -505,9 +505,12 @@ public class MVStore implements AutoCloseable {
M map; M map;
if (id >= 0) { if (id >= 0) {
map = openMap(id, builder); map = openMap(id, builder);
assert builder.getKeyType() == null || map.getKeyType().getClass().equals(builder.getKeyType().getClass());
assert builder.getValueType() == null || map.getValueType().getClass().equals(builder.getValueType().getClass());
} else { } else {
HashMap<String, Object> c = new HashMap<>(); HashMap<String, Object> c = new HashMap<>();
id = lastMapId.incrementAndGet(); id = lastMapId.incrementAndGet();
assert getMap(id) == null;
c.put("id", id); c.put("id", id);
c.put("createVersion", currentVersion); c.put("createVersion", currentVersion);
map = builder.create(this, c); map = builder.create(this, c);
...@@ -1250,7 +1253,7 @@ public class MVStore implements AutoCloseable { ...@@ -1250,7 +1253,7 @@ public class MVStore implements AutoCloseable {
ArrayList<Page> changed = new ArrayList<>(); ArrayList<Page> changed = new ArrayList<>();
for (Iterator<MVMap<?, ?>> iter = maps.values().iterator(); iter.hasNext(); ) { for (Iterator<MVMap<?, ?>> iter = maps.values().iterator(); iter.hasNext(); ) {
MVMap<?, ?> map = iter.next(); MVMap<?, ?> map = iter.next();
MVMap.RootReference rootReference = map.setWriteVersion(version); RootReference rootReference = map.setWriteVersion(version);
if (rootReference == null) { if (rootReference == null) {
assert map.isClosed(); assert map.isClosed();
assert map.getVersion() < getOldestVersionToKeep(); assert map.getVersion() < getOldestVersionToKeep();
...@@ -1289,7 +1292,7 @@ public class MVStore implements AutoCloseable { ...@@ -1289,7 +1292,7 @@ public class MVStore implements AutoCloseable {
} }
} }
applyFreedSpace(); applyFreedSpace();
MVMap.RootReference metaRootReference = meta.setWriteVersion(version); RootReference metaRootReference = meta.setWriteVersion(version);
assert metaRootReference != null; assert metaRootReference != null;
assert metaRootReference.version == version : metaRootReference.version + " != " + version; assert metaRootReference.version == version : metaRootReference.version + " != " + version;
metaChanged = false; metaChanged = false;
...@@ -1445,9 +1448,9 @@ public class MVStore implements AutoCloseable { ...@@ -1445,9 +1448,9 @@ public class MVStore implements AutoCloseable {
try { try {
ChunkIdsCollector collector = new ChunkIdsCollector(meta.getId()); ChunkIdsCollector collector = new ChunkIdsCollector(meta.getId());
long oldestVersionToKeep = getOldestVersionToKeep(); long oldestVersionToKeep = getOldestVersionToKeep();
MVMap.RootReference rootReference = meta.flushAndGetRoot(); RootReference rootReference = meta.flushAndGetRoot();
if (fast) { if (fast) {
MVMap.RootReference previous; RootReference previous;
while (rootReference.version >= oldestVersionToKeep && (previous = rootReference.previous) != null) { while (rootReference.version >= oldestVersionToKeep && (previous = rootReference.previous) != null) {
rootReference = previous; rootReference = previous;
} }
...@@ -1482,7 +1485,7 @@ public class MVStore implements AutoCloseable { ...@@ -1482,7 +1485,7 @@ public class MVStore implements AutoCloseable {
* @param inspectedRoots set of page positions for map's roots already inspected * @param inspectedRoots set of page positions for map's roots already inspected
* or null if not to be used * or null if not to be used
*/ */
private void inspectVersion(MVMap.RootReference rootReference, ChunkIdsCollector collector, private void inspectVersion(RootReference rootReference, ChunkIdsCollector collector,
ThreadPoolExecutor executorService, ThreadPoolExecutor executorService,
AtomicInteger executingThreadCounter, AtomicInteger executingThreadCounter,
Set<Long> inspectedRoots) { Set<Long> inspectedRoots) {
...@@ -2683,7 +2686,7 @@ public class MVStore implements AutoCloseable { ...@@ -2683,7 +2686,7 @@ public class MVStore implements AutoCloseable {
DataUtils.checkArgument(map != meta, DataUtils.checkArgument(map != meta,
"Removing the meta map is not allowed"); "Removing the meta map is not allowed");
map.close(); map.close();
MVMap.RootReference rootReference = map.getRoot(); RootReference rootReference = map.getRoot();
updateCounter += rootReference.updateCounter; updateCounter += rootReference.updateCounter;
updateAttemptCounter += rootReference.updateAttemptCounter; updateAttemptCounter += rootReference.updateAttemptCounter;
...@@ -2983,11 +2986,11 @@ public class MVStore implements AutoCloseable { ...@@ -2983,11 +2986,11 @@ public class MVStore implements AutoCloseable {
public double getUpdateFailureRatio() { public double getUpdateFailureRatio() {
long updateCounter = this.updateCounter; long updateCounter = this.updateCounter;
long updateAttemptCounter = this.updateAttemptCounter; long updateAttemptCounter = this.updateAttemptCounter;
MVMap.RootReference rootReference = meta.getRoot(); RootReference rootReference = meta.getRoot();
updateCounter += rootReference.updateCounter; updateCounter += rootReference.updateCounter;
updateAttemptCounter += rootReference.updateAttemptCounter; updateAttemptCounter += rootReference.updateAttemptCounter;
for (MVMap<?, ?> map : maps.values()) { for (MVMap<?, ?> map : maps.values()) {
MVMap.RootReference root = map.getRoot(); RootReference root = map.getRoot();
updateCounter += root.updateCounter; updateCounter += root.updateCounter;
updateAttemptCounter += root.updateAttemptCounter; updateAttemptCounter += root.updateAttemptCounter;
} }
......
...@@ -699,8 +699,8 @@ public class MVStoreTool { ...@@ -699,8 +699,8 @@ public class MVStoreTool {
@Override @Override
public void write(WriteBuffer buff, Object[] obj, int len, boolean key) { public void write(WriteBuffer buff, Object[] obj, int len, boolean key) {
for (Object o : obj) { for (int i = 0; i < len; i++) {
write(buff, o); write(buff, obj[i]);
} }
} }
...@@ -717,12 +717,9 @@ public class MVStoreTool { ...@@ -717,12 +717,9 @@ public class MVStoreTool {
@Override @Override
public void read(ByteBuffer buff, Object[] obj, int len, boolean key) { public void read(ByteBuffer buff, Object[] obj, int len, boolean key) {
for (int i = 0; i < obj.length; i++) { for (int i = 0; i < len; i++) {
obj[i] = read(buff); obj[i] = read(buff);
} }
} }
} }
} }
...@@ -468,7 +468,7 @@ public abstract class Page implements Cloneable ...@@ -468,7 +468,7 @@ public abstract class Page implements Cloneable
* @return the value or null * @return the value or null
*/ */
int binarySearch(Object key) { int binarySearch(Object key) {
int low = 0, high = keys.length - 1; int low = 0, high = getKeyCount() - 1;
// the cached index minus one, so that // the cached index minus one, so that
// for the first time (when cachedCompare is 0), // for the first time (when cachedCompare is 0),
// the default value is used // the default value is used
...@@ -550,7 +550,7 @@ public abstract class Page implements Cloneable ...@@ -550,7 +550,7 @@ public abstract class Page implements Cloneable
public abstract long getTotalCount(); public abstract long getTotalCount();
/** /**
* Get the descendant counts for the given child. * Get the number of key-value pairs for a given child.
* *
* @param index the child index * @param index the child index
* @return the descendant count * @return the descendant count
...@@ -621,7 +621,7 @@ public abstract class Page implements Cloneable ...@@ -621,7 +621,7 @@ public abstract class Page implements Cloneable
final void insertKey(int index, Object key) { final void insertKey(int index, Object key) {
int keyCount = getKeyCount(); int keyCount = getKeyCount();
assert index <= keyCount : index + " > " + keyCount; assert index <= keyCount : index + " > " + keyCount;
Object[] newKeys = new Object[keyCount + 1]; Object[] newKeys = createKeyStorage(keyCount + 1);
DataUtils.copyWithGap(keys, newKeys, keyCount, index); DataUtils.copyWithGap(keys, newKeys, keyCount, index);
keys = newKeys; keys = newKeys;
...@@ -647,7 +647,7 @@ public abstract class Page implements Cloneable ...@@ -647,7 +647,7 @@ public abstract class Page implements Cloneable
Object old = getKey(index); Object old = getKey(index);
addMemory(-MEMORY_POINTER - keyType.getMemory(old)); addMemory(-MEMORY_POINTER - keyType.getMemory(old));
} }
Object[] newKeys = new Object[keyCount - 1]; Object[] newKeys = createKeyStorage(keyCount - 1);
DataUtils.copyExcept(keys, newKeys, keyCount, index); DataUtils.copyExcept(keys, newKeys, keyCount, index);
keys = newKeys; keys = newKeys;
} }
...@@ -661,7 +661,7 @@ public abstract class Page implements Cloneable ...@@ -661,7 +661,7 @@ public abstract class Page implements Cloneable
private void read(ByteBuffer buff, int chunkId) { private void read(ByteBuffer buff, int chunkId) {
int pageLength = buff.remaining() + 4; // size of int, since we've read page length already int pageLength = buff.remaining() + 4; // size of int, since we've read page length already
int len = DataUtils.readVarInt(buff); int len = DataUtils.readVarInt(buff);
keys = new Object[len]; keys = createKeyStorage(len);
int type = buff.get(); int type = buff.get();
if(isLeaf() != ((type & 1) == PAGE_TYPE_LEAF)) { if(isLeaf() != ((type & 1) == PAGE_TYPE_LEAF)) {
throw DataUtils.newIllegalStateException( throw DataUtils.newIllegalStateException(
...@@ -728,7 +728,7 @@ public abstract class Page implements Cloneable ...@@ -728,7 +728,7 @@ public abstract class Page implements Cloneable
buff.put((byte) type); buff.put((byte) type);
writeChildren(buff, true); writeChildren(buff, true);
int compressStart = buff.position(); int compressStart = buff.position();
map.getKeyType().write(buff, keys, getKeyCount(), true); map.getKeyType().write(buff, keys, len, true);
writeValues(buff); writeValues(buff);
MVStore store = map.getStore(); MVStore store = map.getStore();
int expLen = buff.position() - compressStart; int expLen = buff.position() - compressStart;
...@@ -889,10 +889,11 @@ public abstract class Page implements Cloneable ...@@ -889,10 +889,11 @@ public abstract class Page implements Cloneable
* @return memory in bytes * @return memory in bytes
*/ */
protected int calculateMemory() { protected int calculateMemory() {
int mem = keys.length * MEMORY_POINTER; int keyCount = getKeyCount();
int mem = keyCount * MEMORY_POINTER;
DataType keyType = map.getKeyType(); DataType keyType = map.getKeyType();
for (Object key : keys) { for (int i = 0; i < keyCount; i++) {
mem += keyType.getMemory(key); mem += keyType.getMemory(keys[i]);
} }
return mem; return mem;
} }
...@@ -1472,6 +1473,7 @@ public abstract class Page implements Cloneable ...@@ -1472,6 +1473,7 @@ public abstract class Page implements Cloneable
long getCounts(int index) { long getCounts(int index) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void setChild(int index, Page c) { public void setChild(int index, Page c) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
...@@ -1510,6 +1512,7 @@ public abstract class Page implements Cloneable ...@@ -1510,6 +1512,7 @@ public abstract class Page implements Cloneable
} }
} }
} }
@Override @Override
public void insertNode(int index, Object key, Page childPage) { public void insertNode(int index, Object key, Page childPage) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
...@@ -1573,11 +1576,11 @@ public abstract class Page implements Cloneable ...@@ -1573,11 +1576,11 @@ public abstract class Page implements Cloneable
@Override @Override
protected int calculateMemory() { protected int calculateMemory() {
int mem = super.calculateMemory() + PAGE_LEAF_MEMORY + int keyCount = getKeyCount();
values.length * MEMORY_POINTER; int mem = super.calculateMemory() + PAGE_LEAF_MEMORY + keyCount * MEMORY_POINTER;
DataType valueType = map.getValueType(); DataType valueType = map.getValueType();
for (Object value : values) { for (int i = 0; i < keyCount; i++) {
mem += valueType.getMemory(value); mem += valueType.getMemory(values[i]);
} }
return mem; return mem;
} }
......
/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.mvstore;
/**
* Class RootReference is an immutable structure to represent state of the MVMap as a whole
* (not related to a particular B-Tree node).
* Single structure would allow for non-blocking atomic state change.
* The most important part of it is a reference to the root node.
*
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/
public final class RootReference
{
/**
* The root page.
*/
public final Page root;
/**
* The version used for writing.
*/
public final long version;
/**
* Indicator that map is locked for update.
*/
final boolean lockedForUpdate;
/**
* Reference to the previous root in the chain.
*/
public volatile RootReference previous;
/**
* Counter for successful root updates.
*/
final long updateCounter;
/**
* Counter for attempted root updates.
*/
final long updateAttemptCounter;
/**
* Size of the occupied part of the append buffer.
*/
final byte appendCounter;
// This one is used to set root initially and for r/o snapshots
RootReference(Page root, long version) {
this.root = root;
this.version = version;
this.previous = null;
this.updateCounter = 1;
this.updateAttemptCounter = 1;
this.lockedForUpdate = false;
this.appendCounter = 0;
}
RootReference(RootReference r, Page root, long updateAttemptCounter) {
this.root = root;
this.version = r.version;
this.previous = r.previous;
this.updateCounter = r.updateCounter + 1;
this.updateAttemptCounter = r.updateAttemptCounter + updateAttemptCounter;
this.lockedForUpdate = false;
this.appendCounter = r.appendCounter;
}
// This one is used for locking
RootReference(RootReference r, int attempt) {
this.root = r.root;
this.version = r.version;
this.previous = r.previous;
this.updateCounter = r.updateCounter + 1;
this.updateAttemptCounter = r.updateAttemptCounter + attempt;
this.lockedForUpdate = true;
this.appendCounter = r.appendCounter;
}
// This one is used for unlocking
RootReference(RootReference r, Page root, int appendCounter, boolean lockedForUpdate) {
this.root = root;
this.version = r.version;
this.previous = r.previous;
this.updateCounter = r.updateCounter;
this.updateAttemptCounter = r.updateAttemptCounter;
this.lockedForUpdate = lockedForUpdate;
this.appendCounter = (byte) appendCounter;
}
// This one is used for version change
RootReference(RootReference r, long version, int attempt) {
RootReference previous = r;
RootReference tmp;
while ((tmp = previous.previous) != null && tmp.root == r.root) {
previous = tmp;
}
this.root = r.root;
this.version = version;
this.previous = previous;
this.updateCounter = r.updateCounter + 1;
this.updateAttemptCounter = r.updateAttemptCounter + attempt;
this.lockedForUpdate = r.lockedForUpdate;
this.appendCounter = r.appendCounter;
}
int getAppendCounter() {
return appendCounter & 0xff;
}
public long getTotalCount() {
return root.getTotalCount() + getAppendCounter();
}
@Override
public String toString() {
return "RootReference(" + System.identityHashCode(root) + "," + version + "," + lockedForUpdate + ")";
}
}
...@@ -13,6 +13,7 @@ import org.h2.mvstore.CursorPos; ...@@ -13,6 +13,7 @@ import org.h2.mvstore.CursorPos;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.Page; import org.h2.mvstore.Page;
import org.h2.mvstore.RootReference;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
/** /**
......
...@@ -9,6 +9,7 @@ import org.h2.mvstore.Cursor; ...@@ -9,6 +9,7 @@ import org.h2.mvstore.Cursor;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.Page; import org.h2.mvstore.Page;
import org.h2.mvstore.RootReference;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.value.VersionedValue; import org.h2.value.VersionedValue;
...@@ -100,19 +101,19 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -100,19 +101,19 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
// In order to get such a "snapshot", we wait for a moment of silence, // In order to get such a "snapshot", we wait for a moment of silence,
// when none of the variables concurrently changes it's value. // when none of the variables concurrently changes it's value.
BitSet committingTransactions; BitSet committingTransactions;
MVMap.RootReference mapRootReference; RootReference mapRootReference;
MVMap.RootReference[] undoLogRootReferences; RootReference[] undoLogRootReferences;
long undoLogSize; long undoLogSize;
do { do {
committingTransactions = store.committingTransactions.get(); committingTransactions = store.committingTransactions.get();
mapRootReference = map.flushAndGetRoot(); mapRootReference = map.flushAndGetRoot();
BitSet opentransactions = store.openTransactions.get(); BitSet opentransactions = store.openTransactions.get();
undoLogRootReferences = new MVMap.RootReference[opentransactions.length()]; undoLogRootReferences = new RootReference[opentransactions.length()];
undoLogSize = 0; undoLogSize = 0;
for (int i = opentransactions.nextSetBit(0); i >= 0; i = opentransactions.nextSetBit(i+1)) { for (int i = opentransactions.nextSetBit(0); i >= 0; i = opentransactions.nextSetBit(i+1)) {
MVMap<Long, Object[]> undoLog = store.undoLogs[i]; MVMap<Long, Object[]> undoLog = store.undoLogs[i];
if (undoLog != null) { if (undoLog != null) {
MVMap.RootReference rootReference = undoLog.flushAndGetRoot(); RootReference rootReference = undoLog.flushAndGetRoot();
undoLogRootReferences[i] = rootReference; undoLogRootReferences[i] = rootReference;
undoLogSize += rootReference.getTotalCount(); undoLogSize += rootReference.getTotalCount();
} }
...@@ -156,7 +157,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -156,7 +157,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
} else { } else {
// The undo logs are much smaller than the map - scan all undo logs, // The undo logs are much smaller than the map - scan all undo logs,
// and then lookup relevant map entry. // and then lookup relevant map entry.
for (MVMap.RootReference undoLogRootReference : undoLogRootReferences) { for (RootReference undoLogRootReference : undoLogRootReferences) {
if (undoLogRootReference != null) { if (undoLogRootReference != null) {
Cursor<Long, Object[]> cursor = new Cursor<>(undoLogRootReference.root, null); Cursor<Long, Object[]> cursor = new Cursor<>(undoLogRootReference.root, null);
while (cursor.hasNext()) { while (cursor.hasNext()) {
...@@ -688,7 +689,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -688,7 +689,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
// In order to get such a "snapshot", we wait for a moment of silence, // In order to get such a "snapshot", we wait for a moment of silence,
// when neither of the variables concurrently changes it's value. // when neither of the variables concurrently changes it's value.
BitSet committingTransactions; BitSet committingTransactions;
MVMap.RootReference mapRootReference; RootReference mapRootReference;
do { do {
committingTransactions = store.committingTransactions.get(); committingTransactions = store.committingTransactions.get();
mapRootReference = map.flushAndGetRoot(); mapRootReference = map.flushAndGetRoot();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论