提交 f0fb7e00 authored 作者: Andrei Tokar's avatar Andrei Tokar

inline MVMap.setNewRoot()

上级 630aaa81
...@@ -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));
} }
/** /**
...@@ -1201,7 +1155,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1201,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);
} }
...@@ -1341,7 +1295,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1341,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;
...@@ -1718,7 +1672,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1718,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;
...@@ -1810,7 +1763,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1810,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) {
...@@ -1876,13 +1829,24 @@ public class MVMap<K, V> extends AbstractMap<K, V> ...@@ -1876,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);
......
...@@ -6,11 +6,15 @@ ...@@ -6,11 +6,15 @@
package org.h2.mvstore; package org.h2.mvstore;
/** /**
* Class RootReference. * 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> * @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/ */
public final class RootReference { public final class RootReference
{
/** /**
* The root page. * The root page.
*/ */
...@@ -30,25 +34,35 @@ public final class RootReference { ...@@ -30,25 +34,35 @@ public final class RootReference {
/** /**
* Counter for successful root updates. * Counter for successful root updates.
*/ */
public final long updateCounter; final long updateCounter;
/** /**
* Counter for attempted root updates. * Counter for attempted root updates.
*/ */
public final long updateAttemptCounter; final long updateAttemptCounter;
/** /**
* Size of the occupied part of the append buffer. * Size of the occupied part of the append buffer.
*/ */
public final byte appendCounter; final byte appendCounter;
RootReference(Page root, long version, RootReference previous, int appendCounter, long updateCounter, // This one is used to set root initially and for r/o snapshots
long updateAttemptCounter) { RootReference(Page root, long version) {
this.root = root; this.root = root;
this.version = version; this.version = version;
this.previous = previous; this.previous = null;
this.updateCounter = updateCounter; this.updateCounter = 1;
this.updateAttemptCounter = updateAttemptCounter; this.updateAttemptCounter = 1;
this.lockedForUpdate = false; this.lockedForUpdate = false;
this.appendCounter = (byte) appendCounter; 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 // This one is used for locking
...@@ -89,18 +103,7 @@ public final class RootReference { ...@@ -89,18 +103,7 @@ public final class RootReference {
this.appendCounter = r.appendCounter; this.appendCounter = r.appendCounter;
} }
// This one is used for r/o snapshots int getAppendCounter() {
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; return appendCounter & 0xff;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论