public BytesBytesMultiHashMap(int initialCapacity, float loadFactor, int wbSize, long memUsage) { if (loadFactor < 0 || loadFactor > 1) { throw new AssertionError("Load factor must be between (0, 1]."); } assert initialCapacity > 0; initialCapacity = (Long.bitCount(initialCapacity) == 1) ? initialCapacity : nextHighestPowerOfTwo(initialCapacity); // 8 bytes per long in the refs, assume data will be empty. This is just a sanity check. int maxCapacity = (memUsage <= 0) ? DEFAULT_MAX_CAPACITY : (int) Math.min((long) DEFAULT_MAX_CAPACITY, memUsage / 8); if (maxCapacity < initialCapacity || initialCapacity <= 0) { // Either initialCapacity is too large, or nextHighestPowerOfTwo overflows initialCapacity = (Long.bitCount(maxCapacity) == 1) ? maxCapacity : nextLowestPowerOfTwo(maxCapacity); } validateCapacity(initialCapacity); startingHashBitCount = 63 - Long.numberOfLeadingZeros(initialCapacity); this.loadFactor = loadFactor; refs = new long[initialCapacity]; writeBuffers = new WriteBuffers(wbSize, MAX_WB_SIZE); resizeThreshold = (int) (initialCapacity * this.loadFactor); }
private void expandAndRehashImpl(long capacity) { long expandTime = System.currentTimeMillis(); final long[] oldRefs = refs; validateCapacity(capacity); long[] newRefs = new long[(int) capacity]; // We store some hash bits in ref; for every expansion, we need to add one bit to hash. // If we have enough bits, we'll do that; if we don't, we'll rehash. // LOG.info("Expanding the hashtable to " + capacity + " capacity"); int newHashBitCount = hashBitCount + 1; // Relocate all assigned slots from the old hash table. int maxSteps = 0; for (int oldSlot = 0; oldSlot < oldRefs.length; ++oldSlot) { long oldRef = oldRefs[oldSlot]; if (oldRef == 0) { continue; } // TODO: we could actually store a bit flag in ref indicating whether this is a hash // match or a probe, and in the former case use hash bits (for a first few resizes). // int hashCodeOrPart = oldSlot | Ref.getNthHashBit(oldRef, startingHashBitCount, // newHashBitCount); writeBuffers.setReadPoint(getFirstRecordLengthsOffset(oldRef, null)); // Read the value and key length for the first record. int hashCode = (int) writeBuffers.readNByteLong( Ref.getOffset(oldRef) - writeBuffers.readVLong() - writeBuffers.readVLong() - 4, 4); int probeSteps = relocateKeyRef(newRefs, oldRef, hashCode); maxSteps = Math.max(probeSteps, maxSteps); } this.refs = newRefs; this.largestNumberOfSteps = maxSteps; this.hashBitCount = newHashBitCount; this.resizeThreshold = (int) (capacity * loadFactor); metricExpandsMs += (System.currentTimeMillis() - expandTime); ++metricExpands; }