blob: 52b6d62c3afe8e12e03480363f9c5563354b0f3b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jena.dboe.trans.bplustree;
import static org.apache.jena.dboe.base.block.BlockType.BPTREE_BRANCH;
import static org.apache.jena.dboe.base.block.BlockType.BPTREE_LEAF;
import static org.apache.jena.dboe.base.block.BlockType.RECORD_BLOCK;
import java.nio.ByteBuffer;
import org.apache.jena.dboe.base.block.Block;
import org.apache.jena.dboe.base.block.BlockMgr;
import org.apache.jena.dboe.base.block.BlockType;
import org.apache.jena.dboe.base.buffer.PtrBuffer;
import org.apache.jena.dboe.base.buffer.RecordBuffer;
import org.apache.jena.dboe.base.page.BlockConverter;
import org.apache.jena.dboe.base.page.PageBlockMgr;
/** BPlusTreePageMgr = BPlusTreeNode manager */
public final class BPTreeNodeMgr extends PageBlockMgr<BPTreeNode>
{
// Only "public" for external very low level tools in development to access this class.
// Assume package access.
public BPTreeNodeMgr(BPlusTree bpTree, BlockMgr blockMgr) {
super(new Block2BPTreeNode(bpTree), blockMgr);
}
/** Allocate space for a fresh node. */
public BPTreeNode createNode(int parent) {
BPTreeNode n = create(BPTREE_BRANCH);
n.setIsLeaf(false);
n.setParent(parent);
return n;
}
@Override
public BPTreeNode getWrite(int id) {
return super.getWrite(id, BPlusTreeParams.UnsetParent);
}
@Override
public BPTreeNode getRead(int id) {
return super.getRead(id, BPlusTreeParams.UnsetParent);
}
/** Fetch a block - fill in the parent id, which is not in the on-disk bytes */
@Override
public BPTreeNode getRead(int id, int parent) {
BPTreeNode n = super.getRead$(id);
n.setParent(parent);
return n;
}
/** Fetch a block - fill in the parent id, which is not in the on-disk bytes */
@Override
public BPTreeNode getWrite(int id, int parent) {
BPTreeNode n = super.getWrite$(id);
n.setParent(parent);
return n;
}
boolean isWritable(int id) {
//System.err.println("BPTreeNodeMgr.isWritable");
return false;
// return bpTree.state.modifiableNodeBlock(id);
}
private static class Block2BPTreeNode implements BlockConverter<BPTreeNode> {
private final BPlusTree bpTree;
Block2BPTreeNode(BPlusTree bpTree) { this.bpTree = bpTree; }
@Override
public BPTreeNode createFromBlock(Block block, BlockType bType) {
return overlay(bpTree, block, bType == RECORD_BLOCK, 0);
}
@Override
public BPTreeNode fromBlock(Block block) {
// synchronized - needed for multiple reader?
synchronized (block) {
int x = block.getByteBuffer().getInt(0);
BlockType type = getType(x);
if ( type != BPTREE_BRANCH && type != BPTREE_LEAF )
throw new BPTreeException("Wrong block type: " + type);
int count = decodeCount(x);
return overlay(bpTree, block, (type == BPTREE_LEAF), count);
}
}
@Override
public Block toBlock(BPTreeNode node) {
// It's manipulated in-place so no conversion needed,
// Just the count needs to be fixed up.
// ByteBuffer bb = node.getBackingByteBuffer();
// BlockType bType = (node.isLeaf ? BPTREE_LEAF : BPTREE_BRANCH );
Block block = node.getBackingBlock();
BlockType bType = (node.isLeaf() ? BPTREE_LEAF : BPTREE_BRANCH );
int c = encodeCount(bType, node.getCount());
block.getByteBuffer().putInt(0, c);
return block;
}
}
// // Leaves have a count of -(count+1)
// // (same as the binary search encoding of "not found")
// private static final int encCount(int i) { return -(i+1); }
// private static final int decCount(int i) { return -i-1; }
// ----
private static final BlockType getType(int x) {
return BlockType.extract(x >>> 24);
}
private static final int encodeCount(BlockType type, int i) {
return (type.id() << 24) | (i & 0x00FFFFFF);
}
private static final int decodeCount(int i) {
return i & 0x00FFFFFF;
}
/** byte[] layout.
*
* New:
* 0: Block type
* 1-3: Count
* Internal nodes:
* 4-X: Records: b+tree.MaxRec*record length
* X- : Pointers: b+tree.MaxPtr*ptr length
*/
private static BPTreeNode overlay(BPlusTree bpTree, Block block, boolean asLeaf, int count) {
// if ( byteBuffer.order() != Const.NetworkOrder )
// throw new BTreeException("ByteBuffer in wrong order");
// Fix up the id later.
BPTreeNode n = new BPTreeNode(bpTree);
// The count is zero at the root only.
// When the root is zero, it's a leaf.
formatBPTreeNode(n, bpTree, block, asLeaf, BPlusTreeParams.NoParent, count);
return n;
}
static void formatBPTreeNode(BPTreeNode n, BPlusTree bpTree, Block block, boolean leaf, int parent, int count) {
BPlusTreeParams params = bpTree.getParams();
int ptrBuffLen = params.MaxPtr * params.getPtrLength();
// Only store the key part of records in a B+Tree block
// OLD - Node table has real value part - what's going on?
// [Issue:FREC]
// Allocate space for record, key and value, despite slight over
// allocation.
int recBuffLen = params.MaxRec * params.getRecordLength();
// [Issue:FREC] Should be: key space only.
// int recBuffLen = params.MaxRec * params.getKeyLength();
n.id = block.getId().intValue();
n.setParent(parent);
n.setCount(count);
n.setIsLeaf(leaf);
int header = BPlusTreeParams.BlockHeaderSize;
int rStart = header;
int pStart = header + recBuffLen;
// Find the number of pointers.
int numPtrs = -1;
// The root can have count zero - which means one pointer always.
// Junk when creating a new new node.
if ( n.getCount() < 0 ) {
numPtrs = 0;
n.setCount(decodeCount(n.getCount()));
} else
numPtrs = n.getCount() + 1;
// Block dependent
n.block = block;
ByteBuffer byteBuffer = block.getByteBuffer();
// -- Records area
byteBuffer.position(rStart);
byteBuffer.limit(rStart + recBuffLen);
ByteBuffer bbr = byteBuffer.slice();
// bbr.limit(recBuffLen);
n.setRecordBuffer(new RecordBuffer(bbr, n.params.keyFactory, n.getCount()));
// -- Pointers area
byteBuffer.position(pStart);
byteBuffer.limit(pStart + ptrBuffLen);
ByteBuffer bbi = byteBuffer.slice();
// bbi.limit(ptrBuffLen);
n.setPtrBuffer(new PtrBuffer(bbi, numPtrs));
// Reset
byteBuffer.rewind();
}
static final void formatForRoot(BPTreeNode n, boolean asLeaf) {
BPTreeNodeMgr.formatBPTreeNode(n, n.bpTree, n.getBackingBlock(), asLeaf, BPlusTreeParams.RootParent, 0);
// Tweak for the root-specials. The node is not consistent yet.
// Has one dangling pointer.
}
}