/** Bind this frame to a tree node. Called with exclusive latch held. */ void bind(Node node, int nodePos) { mNode = node; mNodePos = nodePos; TreeCursorFrame last = node.mLastCursorFrame; if (last != null) { mPrevCousin = last; last.mNextCousin = this; } node.mLastCursorFrame = this; }
/** Unbind this frame from a tree node. Called with exclusive latch held. */ void unbind() { TreeCursorFrame prev = mPrevCousin; TreeCursorFrame next = mNextCousin; if (prev != null) { prev.mNextCousin = next; mPrevCousin = null; } if (next != null) { next.mPrevCousin = prev; mNextCousin = null; } else { mNode.mLastCursorFrame = prev; } }
/** * Copy this frame and all parent frames. * * @param dest new frame instance to receive copy */ void copyInto(TreeCursorFrame dest) { Node node = acquireExclusive(); TreeCursorFrame parent = mParentFrame; if (parent != null) { node.releaseExclusive(); TreeCursorFrame parentCopy = new TreeCursorFrame(); while (true) { // Need to check if parent is null, when looping back. if (parent != null) { parent.copyInto(parentCopy); } // Parent can change when tree height is concurrently changing. node = acquireExclusive(); final TreeCursorFrame actualParent = mParentFrame; if (actualParent == parent) { // Parent frame hasn't changed, so use the copy. if (parent != null) { dest.mParentFrame = parentCopy; } break; } // Get rid of the stale copy and do over, which should be rare. node.releaseExclusive(); popAll(parentCopy); parent = actualParent; } } dest.mNotFoundKey = mNotFoundKey; dest.bind(node, mNodePos); node.releaseExclusive(); }
/** Pop given non-null frame and all parent frames. */ static void popAll(TreeCursorFrame frame) { outer: do { Node node = frame.mNode; while (true) { if (node == null) { // Frame was not bound properly, suggesting that cursor is // being cleaned up in response to an exception. Frame // cannot be latched, so just go to the parent. frame = frame.mParentFrame; continue outer; } node.acquireExclusive(); Node actualNode = frame.mNode; if (actualNode == node) { frame = frame.pop(); node.releaseExclusive(); continue outer; } node.releaseExclusive(); node = actualNode; } } while (frame != null); }