/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.indexStructures.vLengthBPlusTree.underflowHandlers; import java.util.List; import xxl.core.indexStructures.vLengthBPlusTree.UnderflowHandler; import xxl.core.indexStructures.vLengthBPlusTree.VariableLengthBPlusTree; import xxl.core.indexStructures.vLengthBPlusTree.VariableLengthBPlusTree.IndexEntry; import xxl.core.indexStructures.vLengthBPlusTree.VariableLengthBPlusTree.Node; import xxl.core.indexStructures.vLengthBPlusTree.VariableLengthBPlusTree.Node.MergeInfo; /** * This class implements a classic underflow handler for B+Trees. Underflows are handled immediately after underflow was detected. * The handler looks at neighbor node and decides on the capacity of the neighbor whether borrowing or merging to apply. * */ public class StandardUnderflowHandler implements UnderflowHandler { @Override public MergeInfo runUnderflowHandling(MergeInfo mergeInfo, IndexEntry indexEntry, Node node, IndexEntry siblingIndexEntry, Node siblingNode, int min, int average, boolean left) { int myUnderflowLoad = node.getCurrentLoad(); int effectivLoad = min + ((average - min) / 2); if (left){ int leftLoad = siblingNode.getCurrentLoad(); // check actual load of left sibling if (leftLoad > average ){ // can be redistributed // start searching the possible new key so that new key <= old key // arg min int minKeySize = node.getKeyByteSize(siblingIndexEntry); int actualSiblingLoad = leftLoad; int indexOfNewKey = siblingNode.number()-1 ; for (int i = siblingNode.number()-1; i > 0; i--){ int entryWeight = siblingNode.getEntryByteSize(siblingNode.getEntry(i), siblingNode.level()); // int entryKey = entryWeight + containerIdSize; // check key size old vs. new if ( myUnderflowLoad < effectivLoad ){ myUnderflowLoad +=entryWeight; actualSiblingLoad -=entryWeight; if (i > 0){ int entryKey = siblingNode.getKeyByteSize(siblingNode.getEntry(i-1)) ; if ( entryKey < minKeySize ){ indexOfNewKey = i-1; minKeySize = entryKey; } } } else break; } // Check if found if (indexOfNewKey < siblingNode.number()-1 ){ // found perfrom real distribution List newEntries = siblingNode.getEntries().subList(indexOfNewKey+1, siblingNode.number()); node.getEntries().addAll(0, newEntries); newEntries.clear(); siblingNode.setByteLoad( siblingNode.computeActualLoad()); node.setByteLoad(node.computeActualLoad()); // mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.MergeState.DISTRIBUTION_LEFT); mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.DISTRIBUTION_LEFT); }else{ mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.POSTPONED_MERGE); } }else{ siblingNode.getEntries().addAll(siblingNode.number(), node.getEntries()); siblingNode.nextNeighbor = node.nextNeighbor(); // siblingNode.setByteLoad( siblingNode.computeActualLoad()); mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.MERGE); } }else{ int rightLoad = siblingNode.getCurrentLoad(); if (rightLoad > average){ // can be redistributed // start searching the possible new key so that new key <= old key // arg min int minKeySize = node.getKeyByteSize(indexEntry); int actualSiblingLoad = rightLoad; int indexOfNewKey = 0 ; for (int i = 0; i < siblingNode.number(); i++){ int entryWeight = node.getEntryByteSize(siblingNode.getEntry(i), siblingNode.level()); int entryKey = node.getKeyByteSize(siblingNode.getEntry(i)); // check key size old vs. new if ( myUnderflowLoad < effectivLoad ){ myUnderflowLoad +=entryWeight; actualSiblingLoad -=entryWeight; if (entryKey < minKeySize ){ indexOfNewKey = i; minKeySize = entryKey; } } else break; } // Check if found if (indexOfNewKey > 0 ){ // found perfrom real distribution List newEntries = siblingNode.getEntries().subList(0, indexOfNewKey+1); node.getEntries().addAll(node.number(), newEntries); newEntries.clear(); node.setByteLoad(node.computeActualLoad()); siblingNode.setByteLoad(siblingNode.computeActualLoad()); mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.DISTRIBUTION_RIGHT); }else{ mergeInfo.initialize(siblingIndexEntry,siblingNode, VariableLengthBPlusTree.POSTPONED_MERGE); } }else{ node.getEntries().addAll(node.number(), siblingNode.getEntries()); node.nextNeighbor = siblingNode.nextNeighbor(); node.setByteLoad(node.computeActualLoad()); mergeInfo.initialize(siblingIndexEntry, siblingNode, VariableLengthBPlusTree.MERGE); } } return mergeInfo; } }