private void closeIndexResources() throws JasDBStorageException { try { if(channel != null) { BtreeIndexHeader.createHeader(dataBlockFactory.getHeaderBlock(), pageSize, recordCount.get(), keyInfo); persister.close(); dataBlockFactory.close(); this.fileLock.release(); this.channel.close(); this.randomAccess.close(); state = IndexState.CLOSED; closed = true; } } catch(IOException e) { throw new JasDBStorageException("Unable to cleanly close index", e); } }
@Override public void flushIndex() throws JasDBStorageException { openIndex(); persister.flush(); }
@Override public long memorySize() { return size() * persister.getKeyInfo().getKeySize(); }
protected void handleBlockUnderflow() throws JasDBStorageException { if(treeNodes.size() < persister.getMinKeys()) { LOG.debug("Handling block underflow"); TreeBlock parentBlock = (TreeBlock) persister.loadBlock(parentPointer); long leftSibblingPointer = parentBlock.getLeftSibbling(this); long rightSibblingPointer = parentBlock.getRightSibbling(this); TreeBlock leftSibbling = null; TreeBlock rightSibbling = null; if(leftSibblingPointer != -1) { leftSibbling = (TreeBlock) persister.loadBlock(leftSibblingPointer); } if(rightSibblingPointer != -1) { rightSibbling = (TreeBlock) persister.loadBlock(rightSibblingPointer); } if(leftSibbling != null && leftSibbling.size() > persister.getMinKeys()) { handleBorrowLeft(parentBlock, leftSibbling); } else if(rightSibbling != null && rightSibbling.size() > persister.getMinKeys()) { handleBorrowRight(parentBlock, rightSibbling); } else { //nothing to borrow we need to merge handleMerge(parentBlock, leftSibbling, rightSibbling); } } }
@Override public LeaveBlock findFirstLeaveBlock(LockIntentType intentType) throws JasDBStorageException { TreeNode firstNode = treeNodes.first(); IndexBlock block = persister.loadBlock(firstNode.getLeft()); persister.getLockManager().acquireLock(intentType, block); return block.findFirstLeaveBlock(intentType); }
private void handleBlockOverflow() throws JasDBStorageException { if(treeNodes.size() > persister.getMaxKeys()) { List<TreeNode>[] blockNodeSplit = treeNodes.split(); List<TreeNode> leftBlockNodes = blockNodeSplit[0]; List<TreeNode> rightBlockNodes = blockNodeSplit[1]; treeNodes.reset(); Key promoteKey = rightBlockNodes.get(0).getKey(); TreeBlock leftBlock = (TreeBlock) persister.createBlock(BlockTypes.NODEBLOCK, getParentPointer()); leftBlock.addNodes(leftBlockNodes, null, leftBlock.getPosition()); if(parentPointer != -1) { //add the nodes, we use -1 as parent does not need to be changed addNodes(rightBlockNodes, promoteKey, getPosition()); TreeBlock parentBlock = (TreeBlock) persister.loadBlock(parentPointer); parentBlock.insertBlock(promoteKey, leftBlock, this); } else { //we are at the root TreeBlock rightBlock = (TreeBlock) persister.createBlock(BlockTypes.NODEBLOCK, getPosition()); rightBlock.addNodes(rightBlockNodes, promoteKey, rightBlock.getPosition()); TreeNode node = new TreeNode(promoteKey, leftBlock.getPosition(), rightBlock.getPosition()); treeNodes.put(node.getKey(), node); } } }
this.lockManager = persister.getLockManager(); } catch(ConfigurationException | IOException e) { state = IndexState.INVALID; this.rootBlock = (RootBlock) persister.createBlock(BlockTypes.ROOTBLOCK, -1); this.rootBlock.setModified(true); } else { this.rootBlock = (RootBlock) persister.loadBlock(indexHeader.getHeaderSize());
protected Key getMin() throws JasDBStorageException { TreeNode node = treeNodes.first(); IndexBlock leftBlock = persister.loadBlock(node.getLeft()); if(leftBlock instanceof TreeBlock) { return ((TreeBlock)leftBlock).getMin(); } else { return leftBlock.getFirst(); } }
@Override public void insertKey(Key key) throws JasDBStorageException { if(isLeave) { addKey(key); modified = true; if(treeNodes.size() > persister.getMaxKeys()) { List<TreeNode>[] leaveValues = treeNodes.split(); List<TreeNode> leftLeaves = leaveValues[0]; List<TreeNode> rightLeaves = leaveValues[1]; treeNodes.reset(); LeaveBlockImpl leftLeaveBlock = (LeaveBlockImpl) persister.createBlock(BlockTypes.LEAVEBLOCK, getPosition()); LeaveBlockImpl rightLeaveBlock = (LeaveBlockImpl) persister.createBlock(BlockTypes.LEAVEBLOCK, getPosition()); leftLeaveBlock.setNext(rightLeaveBlock.getPosition()); rightLeaveBlock.setPrevious(leftLeaveBlock.getPosition()); addKeys(leftLeaves, leftLeaveBlock); addKeys(rightLeaves, rightLeaveBlock); Key promoteKey = leftLeaves.get(leftLeaves.size() - 1).getKey(); TreeNode rootNode = new TreeNode(promoteKey, leftLeaveBlock.getPosition(), rightLeaveBlock.getPosition()); treeNodes.put(promoteKey, rootNode); isLeave = false; RootBlockFactory.writeHeader(getDataBlock(), false); } } else { throw new JasDBStorageException("Unable to store key, root is not a leave"); } }
private void mergeLeaves(TreeBlock parentBlock, LeaveBlockImpl leftLeave, LeaveBlockImpl rightLeave) throws JasDBStorageException { //lets remove the block and update the admin above Key removeKey; if(leftLeave != null && leftLeave.getParentPointer() == getParentPointer()) { removeKey = getFirst(); log.debug("Doing merge into left leave with remove key: {}", removeKey); leftLeave.addKeys(leaves.values()); leftLeave.recalculateMemorySize(); } else if(rightLeave != null && rightLeave.getParentPointer() == getParentPointer()) { removeKey = getLast(); log.debug("Doing merge into right leave with remove key: {}", removeKey); rightLeave.addKeys(leaves.values()); rightLeave.recalculateMemorySize(); } else { throw new JasDBStorageException("Invalid index state there should always be a sibbling leave block"); } if(leftLeave != null) { leftLeave.setNext(rightLeave != null ? rightLeave.getPosition() : -1); } if(rightLeave != null) { rightLeave.setPrevious(leftLeave != null ? leftLeave.getPosition() : -1); } leaves.reset(); persister.markDeleted(this); parentBlock.removeBlockPointer(removeKey, this); }
public void release() { for(LockEntry entry : lockEntries) { ReadWriteLock lockManager = entry.getBlock().getLockManager(); if(entry.getType() == LOCK_TYPE.WRITE) { lockManager.writeUnlock(); } else { lockManager.readUnlock(); } } for(IndexBlock usedBlock : usedBlocks) { persister.releaseBlock(usedBlock); } }
@Override public void removeFromIndex(Key key) throws JasDBStorageException { openIndex(); resourceLockManager.sharedLock(); lockManager.startLockChain(); lockManager.acquireLock(LockIntentType.LEAVELOCK_OPTIMISTIC, rootBlock); try { LeaveBlock leaveBlock = rootBlock.findLeaveBlock(LockIntentType.LEAVELOCK_OPTIMISTIC, key); if(leaveBlock.size() == persister.getMinKeys()) { lockManager.releaseLockChain(); lockManager.startLockChain(); lockManager.acquireLock(LockIntentType.WRITE_EXCLUSIVE, rootBlock); leaveBlock = rootBlock.findLeaveBlock(LockIntentType.WRITE_EXCLUSIVE, key); doLeaveBlockRemove(leaveBlock, key); } else { doLeaveBlockRemove(leaveBlock, key); } } finally { lockManager.releaseLockChain(); resourceLockManager.sharedUnlock(); } }
@Override public void insertIntoIndex(Key key) throws JasDBStorageException { openIndex(); StatRecord btreeInsertRecord = StatisticsMonitor.createRecord("btree:insert"); resourceLockManager.sharedLock(); lockManager.startLockChain(); lockManager.acquireLock(LockIntentType.LEAVELOCK_OPTIMISTIC, rootBlock); try { LeaveBlock leaveBlock = rootBlock.findLeaveBlock(LockIntentType.LEAVELOCK_OPTIMISTIC, key); if(leaveBlock.size() == persister.getMaxKeys()) { lockManager.releaseLockChain(); lockManager.startLockChain(); lockManager.acquireLock(LockIntentType.WRITE_EXCLUSIVE, rootBlock); leaveBlock = rootBlock.findLeaveBlock(LockIntentType.WRITE_EXCLUSIVE, key); doLeaveBlockInsert(leaveBlock, key); } else { //no overflow, we can just write into the leave doLeaveBlockInsert(leaveBlock, key); } } finally { lockManager.releaseLockChain(); resourceLockManager.sharedUnlock(); btreeInsertRecord.stop(); } }
private void handleBlockOverflow() throws JasDBStorageException { if(leaves.size() > persister.getMaxKeys()) { List<Key>[] splittedKeys = leaves.split(); this.leaves.reset(); /* this block keeps representing the right half, the last current block key == max right */ List<Key> rightKeys = splittedKeys[1]; addKeys(rightKeys); List<Key> leftKeys = splittedKeys[0]; long currentPrevious = leaveProperties.getPreviousBlock(); LeaveBlockImpl leftLeaveBlock = (LeaveBlockImpl) persister.createBlock(BlockTypes.LEAVEBLOCK, leaveProperties.getParentPointer()); leftLeaveBlock.setPrevious(currentPrevious); leftLeaveBlock.setNext(getPosition()); leftLeaveBlock.addKeys(leftKeys); this.recalculateMemorySize(); leftLeaveBlock.recalculateMemorySize(); if(currentPrevious != -1) { //we need to relink, there is a previous block present LeaveBlockImpl previousBlock = (LeaveBlockImpl) persister.loadBlock(currentPrevious); previousBlock.setNext(leftLeaveBlock.getPosition()); } leaveProperties.setPreviousBlock(leftLeaveBlock.getPosition()); TreeBlock parentBlock = (TreeBlock) persister.loadBlock(leaveProperties.getParentPointer()); parentBlock.insertBlock(leftLeaveBlock.getLast(), leftLeaveBlock, this); } }
protected Key getMax() throws JasDBStorageException { TreeNode node = treeNodes.last(); IndexBlock rightBlock = persister.loadBlock(node.getRight()); if(rightBlock instanceof TreeBlock) { return ((TreeBlock) rightBlock).getMax(); } else { return rightBlock.getLast(); } } }
@Override public LeaveBlock findLeaveBlock(LockIntentType intent, Key key) throws JasDBStorageException { TreeNode closestNode = treeNodes.getBefore(key); Key nodeKey = closestNode.getKey(); int compare = key.compareTo(nodeKey); long blockPointer; if(compare <= 0) { blockPointer = closestNode.getLeft(); } else { blockPointer = closestNode.getRight(); } IndexBlock block = persister.loadBlock(blockPointer); persister.getLockManager().acquireLock(intent, block); return block.findLeaveBlock(intent, key); }
private void handleBlockUnderflow() throws JasDBStorageException { if(leaves.size() < persister.getMinKeys()) { LeaveBlockImpl leftLeave = null; LeaveBlockImpl rightLeave = null; if(leaveProperties.getPreviousBlock() != -1) { leftLeave = (LeaveBlockImpl) persister.loadBlock(leaveProperties.getPreviousBlock()); rightLeave = (LeaveBlockImpl) persister.loadBlock(leaveProperties.getNextBlock()); TreeBlock parentBlock = (TreeBlock) persister.loadBlock(leaveProperties.getParentPointer()); if(leftLeave != null && leftLeave.getParentPointer() == getParentPointer() && leftLeave.size() > persister.getMinKeys()) { log.debug("Borrowing from left leave"); } else if(rightLeave != null && rightLeave.getParentPointer() == getParentPointer() && rightLeave.size() > persister.getMinKeys()) { log.debug("Borrowing from right leave");
private void handleMerge(TreeBlock parentBlock, TreeBlock leftSibbling, TreeBlock rightSibbling) throws JasDBStorageException { Key removeKey; if(leftSibbling != null) { Key mergeKey = leftSibbling.getMax(); TreeNode leftSibblingLastNode = leftSibbling.getNodes().last(); TreeNode currentFirstNode = treeNodes.first(); removeKey = currentFirstNode.getKey(); TreeNode mergeNode = new TreeNode(mergeKey, leftSibblingLastNode.getRight(), currentFirstNode.getLeft()); leftSibbling.addKey(mergeNode); leftSibbling.addNodes(treeNodes.values(), null, leftSibbling.getPosition()); } else if(rightSibbling != null) { Key mergeKey = getMax(); TreeNode rightFirstNode = rightSibbling.getNodes().first(); TreeNode currentLastNode = treeNodes.last(); removeKey = currentLastNode.getKey(); TreeNode mergeNode = new TreeNode(mergeKey, currentLastNode.getRight(), rightFirstNode.getLeft()); rightSibbling.addKey(mergeNode); rightSibbling.addNodes(treeNodes.values(), null, rightSibbling.getPosition()); } else { throw new JasDBStorageException("Invalid index state there should always be a sibbling tree block"); } treeNodes.reset(); persister.markDeleted(this); parentBlock.removeBlockPointer(removeKey, this); }
protected void addNodes(List<TreeNode> nodes, Key exclude, long parentBlock) throws JasDBStorageException { for(TreeNode node : nodes) { boolean isExcluded = exclude != null && exclude.equals(node.getKey()); if(parentBlock != -1 && (!isExcluded)) { if(node.getLeft() != -1) { IndexBlock block = persister.loadBlock(node.getLeft()); block.setParentPointer(parentBlock); } if(node.getRight() != -1) { IndexBlock block = persister.loadBlock(node.getRight()); block.setParentPointer(parentBlock); } } if(!isExcluded) { treeNodes.put(node.getKey(), node); } } }