use of org.neo4j.io.pagecache.PageCursor in project neo4j by neo4j.
the class MuninnPageCacheTest method mustUnblockPageFaultersWhenEvictionGetsException.
@Test(timeout = SEMI_LONG_TIMEOUT_MILLIS)
public void mustUnblockPageFaultersWhenEvictionGetsException() throws Exception {
writeInitialDataTo(file("a"));
FileSystemAbstraction fs = new DelegatingFileSystemAbstraction(this.fs) {
@Override
public StoreChannel open(File fileName, String mode) throws IOException {
return new DelegatingStoreChannel(super.open(fileName, mode)) {
@Override
public void writeAll(ByteBuffer src, long position) throws IOException {
throw new IOException("uh-oh...");
}
};
}
};
MuninnPageCache pageCache = createPageCache(fs, 2, 8, PageCacheTracer.NULL, DefaultPageCursorTracerSupplier.INSTANCE);
final PagedFile pagedFile = pageCache.map(file("a"), 8);
// all writes.
try (PageCursor cursor = pagedFile.io(0, PF_SHARED_WRITE_LOCK)) {
for (int i = 0; i < 1000; i++) {
assertTrue(cursor.next());
}
fail("Expected an exception at this point");
} catch (IOException ignore) {
// Good.
}
}
use of org.neo4j.io.pagecache.PageCursor in project neo4j by neo4j.
the class GBPTree method writeState.
private void writeState(PagedFile pagedFile, Header.Writer headerWriter) throws IOException {
Pair<TreeState, TreeState> states = readStatePages(pagedFile);
TreeState oldestState = TreeStatePair.selectOldestOrInvalid(states);
long pageToOverwrite = oldestState.pageId();
Root root = this.root;
try (PageCursor cursor = pagedFile.io(pageToOverwrite, PagedFile.PF_SHARED_WRITE_LOCK)) {
PageCursorUtil.goTo(cursor, "state page", pageToOverwrite);
TreeState.write(cursor, stableGeneration(generation), unstableGeneration(generation), root.id(), root.generation(), freeList.lastId(), freeList.writePageId(), freeList.readPageId(), freeList.writePos(), freeList.readPos());
writerHeader(pagedFile, headerWriter, other(states, oldestState), cursor);
checkOutOfBounds(cursor);
}
}
use of org.neo4j.io.pagecache.PageCursor in project neo4j by neo4j.
the class InternalTreeLogic method updateLeftmostChildInRightSibling.
private void updateLeftmostChildInRightSibling(PageCursor cursor, long childPointer, long stableGeneration, long unstableGeneration) throws IOException {
long rightSibling = bTreeNode.rightSibling(cursor, stableGeneration, unstableGeneration);
// Left sibling is not allowed to be NO_NODE here because that means there is a child node with no parent
PointerChecking.checkPointer(rightSibling, false);
try (PageCursor rightSiblingCursor = cursor.openLinkedCursor(rightSibling)) {
bTreeNode.goTo(rightSiblingCursor, "right sibling", rightSibling);
bTreeNode.setChildAt(rightSiblingCursor, childPointer, 0, stableGeneration, unstableGeneration);
}
}
use of org.neo4j.io.pagecache.PageCursor in project neo4j by neo4j.
the class InternalTreeLogic method underflowInLeaf.
private void underflowInLeaf(PageCursor cursor, StructurePropagation<KEY> structurePropagation, int keyCount, long stableGeneration, long unstableGeneration) throws IOException {
long leftSibling = bTreeNode.leftSibling(cursor, stableGeneration, unstableGeneration);
PointerChecking.checkPointer(leftSibling, true);
long rightSibling = bTreeNode.rightSibling(cursor, stableGeneration, unstableGeneration);
PointerChecking.checkPointer(rightSibling, true);
if (TreeNode.isNode(leftSibling)) {
// Go to left sibling and read stuff
try (PageCursor leftSiblingCursor = cursor.openLinkedCursor(GenerationSafePointerPair.pointer(leftSibling))) {
leftSiblingCursor.next();
int leftSiblingKeyCount = bTreeNode.keyCount(leftSiblingCursor);
if (keyCount + leftSiblingKeyCount >= bTreeNode.leafMaxKeyCount()) {
createSuccessorIfNeeded(leftSiblingCursor, structurePropagation, StructurePropagation.UPDATE_LEFT_CHILD, stableGeneration, unstableGeneration);
rebalanceLeaf(cursor, leftSiblingCursor, structurePropagation, keyCount, leftSiblingKeyCount);
} else {
// No need to create new unstable version of left sibling.
// Parent pointer will be updated later.
mergeFromLeftSiblingLeaf(cursor, leftSiblingCursor, structurePropagation, keyCount, leftSiblingKeyCount, stableGeneration, unstableGeneration);
}
}
} else if (TreeNode.isNode(rightSibling)) {
try (PageCursor rightSiblingCursor = cursor.openLinkedCursor(GenerationSafePointerPair.pointer(rightSibling))) {
rightSiblingCursor.next();
int rightSiblingKeyCount = bTreeNode.keyCount(rightSiblingCursor);
if (keyCount + rightSiblingKeyCount <= bTreeNode.leafMaxKeyCount()) {
createSuccessorIfNeeded(rightSiblingCursor, structurePropagation, UPDATE_RIGHT_CHILD, stableGeneration, unstableGeneration);
mergeToRightSiblingLeaf(cursor, rightSiblingCursor, structurePropagation, keyCount, rightSiblingKeyCount, stableGeneration, unstableGeneration);
}
}
}
}
use of org.neo4j.io.pagecache.PageCursor in project neo4j by neo4j.
the class InternalTreeLogic method splitInternal.
/**
* Leaves cursor at same page as when called. No guarantees on offset.
* <p>
* Split in internal node caused by an insertion of rightKey and newRightChild
*
* @param cursor {@link PageCursor} pinned to page containing internal node, full node.
* @param structurePropagation {@link StructurePropagation} used to report structure changes between tree levels.
* @param newKey new key to be inserted together with newRightChild, causing the split
* @param newRightChild new child to be inserted to the right of newKey
* @param keyCount key count for fullNode
* @throws IOException on cursor failure
*/
private void splitInternal(PageCursor cursor, StructurePropagation<KEY> structurePropagation, KEY newKey, long newRightChild, int keyCount, long stableGeneration, long unstableGeneration) throws IOException {
long current = cursor.getCurrentPageId();
long oldRight = bTreeNode.rightSibling(cursor, stableGeneration, unstableGeneration);
PointerChecking.checkPointer(oldRight, true);
long newRight = idProvider.acquireNewId(stableGeneration, unstableGeneration);
// Find position to insert new key
int pos = positionOf(search(cursor, newKey, readKey, keyCount));
int keyCountAfterInsert = keyCount + 1;
int middlePos = middle(keyCountAfterInsert);
// Update structurePropagation
structurePropagation.hasRightKeyInsert = true;
structurePropagation.midChild = current;
structurePropagation.rightChild = newRight;
if (middlePos == pos) {
layout.copyKey(newKey, structurePropagation.rightKey);
} else {
bTreeNode.keyAt(cursor, structurePropagation.rightKey, pos < middlePos ? middlePos - 1 : middlePos);
}
// Update new right
try (PageCursor rightCursor = cursor.openLinkedCursor(newRight)) {
bTreeNode.goTo(rightCursor, "new right sibling in split", newRight);
bTreeNode.initializeInternal(rightCursor, stableGeneration, unstableGeneration);
bTreeNode.setRightSibling(rightCursor, oldRight, stableGeneration, unstableGeneration);
bTreeNode.setLeftSibling(rightCursor, current, stableGeneration, unstableGeneration);
// -1 because don't keep prim key in internal
int rightKeyCount = keyCountAfterInsert - middlePos - 1;
if (pos < middlePos) {
// v-------v copy
// before key _,_,_,_,_,_,_,_,_,_
// before child -,-,-,-,-,-,-,-,-,-,-
// insert key _,_,X,_,_,_,_,_,_,_,_
// insert child -,-,-,x,-,-,-,-,-,-,-,-
// middle key ^
// children
cursor.copyTo(bTreeNode.keyOffset(middlePos), rightCursor, bTreeNode.keyOffset(0), rightKeyCount * bTreeNode.keySize());
cursor.copyTo(bTreeNode.childOffset(middlePos), rightCursor, bTreeNode.childOffset(0), (rightKeyCount + 1) * bTreeNode.childSize());
} else {
// pos > middlePos
// v-v first copy
// v-v-v second copy
// before key _,_,_,_,_,_,_,_,_,_
// before child -,-,-,-,-,-,-,-,-,-,-
// insert key _,_,_,_,_,_,_,X,_,_,_
// insert child -,-,-,-,-,-,-,-,x,-,-,-
// middle key ^
// pos == middlePos
// first copy
// v-v-v-v-v second copy
// before key _,_,_,_,_,_,_,_,_,_
// before child -,-,-,-,-,-,-,-,-,-,-
// insert key _,_,_,_,_,X,_,_,_,_,_
// insert child -,-,-,-,-,-,x,-,-,-,-,-
// middle key ^
// Keys
int countBeforePos = pos - (middlePos + 1);
// ... first copy
if (countBeforePos > 0) {
cursor.copyTo(bTreeNode.keyOffset(middlePos + 1), rightCursor, bTreeNode.keyOffset(0), countBeforePos * bTreeNode.keySize());
}
// ... insert
if (countBeforePos >= 0) {
bTreeNode.insertKeyAt(rightCursor, newKey, countBeforePos, countBeforePos);
}
// ... second copy
int countAfterPos = keyCount - pos;
if (countAfterPos > 0) {
cursor.copyTo(bTreeNode.keyOffset(pos), rightCursor, bTreeNode.keyOffset(countBeforePos + 1), countAfterPos * bTreeNode.keySize());
}
// Children
countBeforePos = pos - middlePos;
// ... first copy
if (countBeforePos > 0) {
// first copy
cursor.copyTo(bTreeNode.childOffset(middlePos + 1), rightCursor, bTreeNode.childOffset(0), countBeforePos * bTreeNode.childSize());
}
// ... insert
bTreeNode.insertChildAt(rightCursor, newRightChild, countBeforePos, countBeforePos, stableGeneration, unstableGeneration);
// ... second copy
if (countAfterPos > 0) {
cursor.copyTo(bTreeNode.childOffset(pos + 1), rightCursor, bTreeNode.childOffset(countBeforePos + 1), countAfterPos * bTreeNode.childSize());
}
}
bTreeNode.setKeyCount(rightCursor, rightKeyCount);
}
// Update old right with new left sibling (newRight)
if (TreeNode.isNode(oldRight)) {
bTreeNode.goTo(cursor, "old right sibling", oldRight);
bTreeNode.setLeftSibling(cursor, newRight, stableGeneration, unstableGeneration);
}
// Update left node
// Move cursor back to left
bTreeNode.goTo(cursor, "left", current);
bTreeNode.setKeyCount(cursor, middlePos);
if (pos < middlePos) {
bTreeNode.insertKeyAt(cursor, newKey, pos, middlePos - 1);
bTreeNode.insertChildAt(cursor, newRightChild, pos + 1, middlePos - 1, stableGeneration, unstableGeneration);
}
bTreeNode.setRightSibling(cursor, newRight, stableGeneration, unstableGeneration);
}
Aggregations