public void addKey(TreeNode node) { this.treeNodes.put(node.getKey(), node); }
@Override public List<Key> getKeyRange(Key start, boolean includeStart, Key end, boolean includeEnd) { List<TreeNode> foundNodes = treeNodes.range(start, includeStart, end, includeEnd); List<Key> foundKeys = new ArrayList<>(foundNodes.size()); for(TreeNode node : foundNodes) { foundKeys.add(node.getKey()); } return foundKeys; }
protected void addKeys(List<TreeNode> nodes, LeaveBlockImpl targetLeave) { for(TreeNode node : nodes) { targetLeave.addKey(node.getKey()); } }
@Override public Key getFirst() { return treeNodes.first().getKey(); }
@Override public Key getLast() { return treeNodes.last().getKey(); }
@Override public Key getKey(Key key) { return treeNodes.get(key).getKey(); }
private void removeNodeInternal(TreeNode node) { this.treeNodes.remove(node.getKey()); }
@Override public List<Key> getValues() { List<Key> rootKeys = new ArrayList<>(treeNodes.size()); for(TreeNode treeNode : treeNodes.values()) { rootKeys.add(treeNode.getKey()); } return rootKeys; }
@Override public void updateKey(Key key) throws JasDBStorageException { if(isLeave) { Key foundKey = treeNodes.get(key).getKey(); foundKey.setKeys(key.getKeys()); modified = true; } else { throw new JasDBStorageException("Unable to update key, root is not a leave"); } }
protected void removeBlockPointer(Key minBlockValue, IndexBlock removedBlock) throws JasDBStorageException { TreeNode removeNode = treeNodes.getBefore(minBlockValue); // LOG.info("Closest remove node: {} nodes: {}", removeNode, treeNodes.size()); TreeNode next = treeNodes.next(removeNode.getKey()); if(next != null && removeNode.getLeft() != removedBlock.getPosition()) { //we need to relink the next block next.setLeft(removeNode.getLeft()); } treeNodes.remove(removeNode.getKey()); modified = true; handleBlockUnderflow(); }
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); } } }
protected void updateBlockPointer(Key replaceKey, long leftBlock, long rightBlock) throws JasDBStorageException { modified = true; if(treeNodes.contains(replaceKey)) { treeNodes.remove(replaceKey); treeNodes.put(replaceKey, new TreeNode(replaceKey, leftBlock, rightBlock)); } else { treeNodes.put(replaceKey, new TreeNode(replaceKey, leftBlock, rightBlock)); TreeNode previousNode = treeNodes.previous(replaceKey); TreeNode nextNode = treeNodes.next(replaceKey); if(previousNode != null && nextNode != null) { //we are updating in the middle if(previousNode.getLeft() == leftBlock && previousNode.getRight() == rightBlock) { //the previous node is the one we are replacing, lets remove it treeNodes.remove(previousNode.getKey()); } else if(nextNode.getLeft() == leftBlock && nextNode.getRight() == rightBlock) { //the next node is the one we are replacing, lets remove it treeNodes.remove(nextNode.getKey()); } else { throw new JasDBStorageException("Unable to update the pointer after remove, invalid state"); } } else if(previousNode != null) { //we are updating at the end of the chain treeNodes.remove(previousNode.getKey()); } else { //we must be updating in the beginning of the chain treeNodes.remove(nextNode.getKey()); } } }
protected long getRightSibbling(TreeBlock block) { TreeNode beforeNode = treeNodes.getBefore(block.getLast()); if(beforeNode.getRight() == block.getPosition()) { TreeNode nextNode = treeNodes.next(beforeNode.getKey()); return nextNode != null ? nextNode.getRight() : -1; } else { //this only happens with one node return beforeNode.getRight(); } }
@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 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); } } }
@Override public void persistBlock(TreeBlock treeBlock) throws JasDBStorageException { if(treeBlock.isModified()) { LOG.debug("Persisting block at position: {}", treeBlock.getPosition()); List<TreeNode> treeNodes = treeBlock.getNodes().values(); DataBlock dataBlock = treeBlock.getDataBlock(); dataBlock.reset(); dataBlock.getHeader().putLong(PARENTPOINTER_INDEX, treeBlock.getParentPointer()); dataBlock.getHeader().putInt(NODEAMOUNT_INDEX, treeNodes.size()); for(TreeNode treeNode : treeNodes) { dataBlock = writeKey(treeBlock, treeNode.getKey(), dataBlock); dataBlock = dataBlock.writeLong(treeNode.getLeft()).getDataBlock(); dataBlock = dataBlock.writeLong(treeNode.getRight()).getDataBlock(); } } }
@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 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); }
@Override public TreeBlock loadBlock(DataBlock dataBlock) throws JasDBStorageException { TreeBlock treeBlock = createBlock(-1, dataBlock); treeBlock.setModified(false); treeBlock.setParentPointer(dataBlock.getHeader().getLong(PARENTPOINTER_INDEX)); int nrNodes = dataBlock.getHeader().getInt(NODEAMOUNT_INDEX); int offset = 0; DataBlock currentBlock = dataBlock; for(int i=0; i<nrNodes; i++) { KeyLoadResult loadedKeyResult = loadKeyResult(treeBlock, offset, currentBlock); DataBlockResult<Long> leftPointerResult = loadedKeyResult.getEndBlock().loadLong(loadedKeyResult.getNextOffset()); DataBlockResult<Long> rightPointerResult = leftPointerResult.getEndBlock().loadLong(leftPointerResult.getNextOffset()); TreeNode node = new TreeNode(loadedKeyResult.getLoadedKey(), leftPointerResult.getValue(), rightPointerResult.getValue()); treeBlock.addKey(node); LOG.trace("Loaded Key: {} with left: {} and right: {} on block: {}", node.getKey(), node.getLeft(), node.getRight(), treeBlock.getPosition()); offset = rightPointerResult.getNextOffset(); currentBlock = rightPointerResult.getEndBlock(); } return treeBlock; }