com.bigdata.htree.HTreeUtil Maven / Gradle / Ivy
/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 [email protected] This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Apr 20, 2011 */ package com.bigdata.htree; import it.unimi.dsi.bits.Fast; import com.bigdata.util.BytesUtil; /** * Static utility methods and data for an {@link HTree}. * * @author Bryan Thompson * @version $Id$ */ public class HTreeUtil { /** * Find the first power of two which is GTE the given value. This is used to * compute the size of the address space (in bits) which is required to * address a hash table with slots for that many buckets. */ static int getMapSize(final int nentries) { if (nentries <= 0) throw new IllegalArgumentException(); int i = 1; while ((1 << i) < nentries) i++; return i; } /** * Return
for the hash tree.) * * @return The local depth of that child node. * * @throws IllegalArgumentException * if addressBits is LT ONE (1). * @throws IllegalArgumentException * if globalDepth is LT ZERO (0). * @throws IllegalArgumentException * if globalDepth is GT2^n
. * * @param n * The exponent. * * @return The result. */ static int pow2(final int n) { // return (int) Math.pow(2d, n); return 1 << n; } /** * Returntrue
if the argument is a power of TWO (2). * * @param v * The argument. * * @returntrue
if the argument is a power of TWO (2). */ static public boolean isPowerOf2(final int v) { return ((v & -v) == v); } /** * Return the #of entries in the address map for a page having the given * local depth. This is2^(globalHashBits - localHashBits)
. The * following table shows the relationship between the global hash bits (gb), * the local hash bits (lb) for a page, and the #of directory entries for * that page (nentries). * ** gb lb nentries * 1 0 2 * 1 1 1 * 2 0 4 * 2 1 2 * 2 2 1 * 3 0 8 * 3 1 4 * 3 2 2 * 3 3 1 * 4 0 16 * 4 1 8 * 4 2 4 * 4 3 2 * 4 4 1 ** * @param globalDepth * The global depth of the parent. * @param localDepth * The local depth of the child. * * @return The #of directory entries for that child page. * * @throws IllegalArgumentException * if either argument is less than ZERO (0). * @throws IllegalArgumentException * if localHashBits is greater than * globalHashBits. */ public static int getSlotsOnPage(final int globalDepth, final int localDepth) { if (localDepth < 0) throw new IllegalArgumentException(); if (globalDepth < 0) throw new IllegalArgumentException(); if (localDepth > globalDepth) throw new IllegalArgumentException(); // The #of slots entries for the child page. final int numSlotsForPage = (1 << (globalDepth - localDepth)); return numSlotsForPage; } /** * Return the local depth of a child page having npointers to that * page in the parent node. This method is based on the relationship *2^(n-i) = npointers
where n is the global depth of * the parent and i is the local depth of the child. The value of * i is the MSB of(npointers / (2^n))
. That equation * always evaluates to a power of two since npointers is a power of two. The * MSB is the index of the highest (and only) ONE (1) bit in the result for * that equation. * * @param addressBits * The #of address bits for the hash tree. This is set when the * tree is configured and is immutable. addressBits is not * required for the computation, but is used to validate the * other arguments. * @param globalDepth * The global depth of the parent node. * @param npointers * The #of pointers to that child in the parent node. All of * those pointers will be within a single buddy hash table in the * parent. The maximum value for npointers is *2^globalDepth
for a given globalDepth. * (The maximum value of globalDepth is the configured * value of addressBits2^addressBits
. * @throws IllegalArgumentException * if npointers is LT ONE (1). * @throws IllegalArgumentException * if npointers is greater than *2^globalDepth
. * @throws IllegalArgumentException * if npointers is not a power of 2. */ public static int getLocalDepth(final int addressBits, final int globalDepth, final int npointers) { if (addressBits < 1) throw new IllegalArgumentException(); if (globalDepth < 0) throw new IllegalArgumentException(); if (globalDepth > (1 << addressBits)) // aka 2^addressBits throw new IllegalArgumentException(); if (npointers < 1) throw new IllegalArgumentException(); if (npointers > (1 << globalDepth)) // aka 2^globalDepth throw new IllegalArgumentException(); if ((npointers & -npointers) != npointers) // e.g., not a power of 2. throw new IllegalArgumentException(); final int x = (1 << globalDepth) / npointers; final int i = Fast.mostSignificantBit(x); assert 1 << (globalDepth-i) == npointers; // System.err.println("addressBits=" + addressBits + ", globalDepth=" // + globalDepth + ", npointers=" + npointers + ", x=" + x // + ", localDepth=" + i); // Alternative code from Martyn. We have not compared performance. I suspect // that the relatively "closed" form solution above will do better, but this // should be tested. // // npointers == 2^(g-i) // 2^i = (2^g)/npointers // need to find nb st 2^nb == npointers // then 2^i == 2^g / 2^nb = 2^(g-nb) // and i == g-nb // // int nb = 0; // while (npointers != (1 << nb)) ++nb; // // return globalDepth - nb; return i; } /** * Find the offset of the buddy hash table or buddy bucket in the child. * Each page of the hash tree is logically an ordered array of "buddies" * sharing the same physical page. When the page is a directory page, the * buddies are buddy hash tables. When the page is a bucket page, the * buddies are buddy hash buckets. The returned value is the offset required * to index into the appropriate buddy hash table or buddy hash bucket in * the child page. * * @param hashBits * The relevant bits of the hash code used to lookup the child * within the parent. * @param globalDepth * The global depth of the parent. * @param localDepth * The local depth of the child page within the parent. * * @return The offset of the start of the buddy hash table or buddy hash * bucket within the child. This is an index into the slots of the * child. There are m:=(2^addressBits)-1 slots in the child, so the * returned index is in the half open range [0:m). * * @throws IllegalArgumentException * if the globalDepth is negative. * @throws IllegalArgumentException * if the localDepth is greater than the * globalDepth. */ public static int getBuddyOffset(final int hashBits, final int globalDepth, final int localDepth) { if (globalDepth < 0) throw new IllegalArgumentException(); if (localDepth > globalDepth) throw new IllegalArgumentException(); final int nbits = (globalDepth - localDepth); // #of address slots in each buddy hash table in the child. final int slotsPerBuddy = (1 << localDepth); // index of the buddy in [0:nChildBuddies-1]. final int tmp = BytesUtil.maskOffLSB(hashBits, nbits); // index of the buddy as a slot offset into the child. final int childBuddyOffset = tmp * slotsPerBuddy; return childBuddyOffset; } }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy