/* 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.collections.containers.recordManager; import java.util.Map; import java.util.SortedMap; import xxl.core.collections.MapEntry; import xxl.core.collections.containers.recordManager.RecordManager.PageInformation; /** * This class provides a next-fit strategy for the record manager. * A histogram is used to store the number of pages in each bucket, * thus saving one lookup in the index when the serach for * a page with enough free space is unsuccesfull. */ public class NextFitWithHWStrategy extends NextFitWithHStrategy { /** * Field where witnesses for each bucket are stored. */ protected Object[] witness; /** * Statistical information. */ protected int numberWitnessesUsed; /** * Creates a new NextFitStrategy Object. * @param numberOfBuckets Number of buckets for the histogram. */ public NextFitWithHWStrategy(int numberOfBuckets) { super(numberOfBuckets); numberWitnessesUsed = 0; } /** * @see xxl.core.collections.containers.recordManager.Strategy#init(java.util.SortedMap, int, int) */ public void init(SortedMap pages, int pageSize, int maxObjectSize) { super.init(pages, pageSize, maxObjectSize); witness = new Object[numberOfBuckets]; } /** * Adds a new entry to the histogram. The entry has a given * page identifyer. * @param pageId Identifyer of the page, for which a histogram entry * is added. * @param bucketNumber Number of the bucket of the histogram where * the entry is added. */ protected void addHistogramEntry(Object pageId, int bucketNumber) { histogram[bucketNumber]++; if (witness[bucketNumber]==null) witness[bucketNumber] = pageId; } /** * Removes an entry from the histogram. The entry has a given * page identifyer. * @param pageId Identifyer of the page, for which the histogram entry * is removed. * @param bucketNumber Number of the bucket of the histogram where * the entry is removed. */ protected void removeHistogramEntry(Object pageId, int bucketNumber) { histogram[bucketNumber]--; if (witness[bucketNumber]!=null && witness[bucketNumber].equals(pageId)) witness[bucketNumber] = null; } /** * Checks the consistency of the current histogram with the * real values. If the values does not match, then an Exception is * thrown. */ protected void checkConsistency() { super.checkConsistency(); for (int i=0; i<numberOfBuckets; i++) { if (witness[i]!=null) { if (histogram[i]<=0) throw new RuntimeException("Histogram witness cannot exist"); PageInformation pi = (PageInformation) pages.get(witness[i]); int realBucket = getHistogramClassForPage(pi.bytesFreeAfterPossibleReservation(0)); if (i!=realBucket) throw new RuntimeException("Histogram witness is not in correct class "+realBucket); } } } /** * Tests an entry if there is enough space for a reservation. * @param entry The entry to be tested. * @param bytesRequired bytes needed for the Record. * @return the entry if a reservation is possible else null. */ public Map.Entry testEntry(Map.Entry entry, int bytesRequired) { Map.Entry me = super.testEntry(entry, bytesRequired); // only use this as witness, if the entry will not hold // the wanted record. if (me==null) { PageInformation pi = (PageInformation) entry.getValue(); int bucket = getHistogramClassForPage(pi.bytesFreeAfterPossibleReservation(0)); if (witness[bucket]==null) witness[bucket] = entry.getKey(); } return me; } /** * Consults the histogram and returns an entry which * can hold the record. If there is an existing but * unknown page where the record will fit the method * will return null. If the method can say that * there will be no such page, then a MapEntry with * (null, null) is returned. * @param bytesRequired Number of bytes required for the * current record. * @return A valid Map.Entry, null or MapEntry(null, null). */ protected Map.Entry consultHistogram(int bytesRequired) { int minClass = getHistogramClass(bytesRequired); for (int i=minClass; i<numberOfBuckets; i++) { if (witness[i]!=null) { numberWitnessesUsed++; return new MapEntry(witness[i], null); } } for (int i=minClass; i<numberOfBuckets; i++) if (histogram[i]>0) return null; return new MapEntry(null, null); } /** * Outputs the state of the Strategy. * @return The String representation of the state of the Strategy. */ public String toString() { String s = "NextFitWithHWStrategy, Number of witnesses used: "+numberWitnessesUsed+", Number of full Searches: "+numberOfFullSearches+", currentPage: "; if (lastEntry==null) return s+"null"; else return s+lastEntry.getKey(); } }