提交 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>
return rootReference;
}
final void setRoot(Page rootPage) {
int attempt = 0;
while (setNewRoot(null, rootPage, ++attempt, false) == null) {/**/}
}
/**
* Set the initial root.
*
......@@ -814,51 +809,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
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.
*
......@@ -891,15 +841,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
/**
* Use the new root page from now on.
* @param oldRoot the old root reference, will use the current root reference,
* if null is specified
* @param newRoot the new root page
* @param expectedRootRefrence expected current root reference
* @param newRootPage the new root page
* @param attemptUpdateCounter how many attempt (including current)
* were made to update root
* @return new RootReference or null if update failed
*/
protected final boolean updateRoot(RootReference oldRoot, Page newRoot, int attemptUpdateCounter) {
return setNewRoot(oldRoot, newRoot, attemptUpdateCounter, true) != null;
protected final boolean updateRoot(RootReference expectedRootRefrence, Page newRootPage,
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>
private Page copy(Page source, Page parent, int index) {
Page target = source.copy(this);
if (parent == null) {
setRoot(target);
setInitialRoot(target, INITIAL_VERSION);
} else {
parent.setChild(index, target);
}
......@@ -1341,7 +1295,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
} finally {
if (lockedRootReference != null && !lockedForUpdate) {
assert rootReference.root == lockedRootReference.root;
rootReference = unlockRoot(lockedRootReference.root, lockedRootReference.appendCounter);
rootReference = unlockRoot();
}
}
return rootReference;
......@@ -1718,7 +1672,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
rootReference = lockedRootReference;
}
Page rootPage = rootReference.root;
int appendCounter = rootReference.getAppendCounter();
CursorPos tip;
V result;
unsavedMemoryHolder.value = 0;
......@@ -1810,7 +1763,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
} finally {
if(lockedRootReference != null) {
unlockRoot(rootPage, appendCounter);
unlockRoot(rootPage);
}
}
while (tip != null) {
......@@ -1876,13 +1829,24 @@ public class MVMap<K, V> extends AbstractMap<K, V>
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;
boolean success;
do {
RootReference rootReference = getRoot();
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);
} while(!success);
......
......@@ -6,11 +6,15 @@
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>
*/
public final class RootReference {
public final class RootReference
{
/**
* The root page.
*/
......@@ -30,25 +34,35 @@ public final class RootReference {
/**
* Counter for successful root updates.
*/
public final long updateCounter;
final long updateCounter;
/**
* Counter for attempted root updates.
*/
public final long updateAttemptCounter;
final long updateAttemptCounter;
/**
* 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,
long updateAttemptCounter) {
// 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 = previous;
this.updateCounter = updateCounter;
this.updateAttemptCounter = updateAttemptCounter;
this.previous = null;
this.updateCounter = 1;
this.updateAttemptCounter = 1;
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
......@@ -89,18 +103,7 @@ public final class RootReference {
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() {
int getAppendCounter() {
return appendCounter & 0xff;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论