LUCENE-6095: Remove RamUsageTester.IdentityHashSet and use Collections.newSetFromMap(new IdentityHashMap<E, Boolean>()) instead.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1644587 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Adrien Grand 2014-12-11 10:16:01 +00:00
parent 08cdb3c867
commit e9366323e8
2 changed files with 2 additions and 298 deletions

View File

@ -1,56 +0,0 @@
package org.apache.lucene.util;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.*;
import org.junit.Assert;
import org.junit.Test;
public class TestIdentityHashSet extends LuceneTestCase {
@Test
public void testCheck() {
Random rnd = random();
Set<Object> jdk = Collections.newSetFromMap(
new IdentityHashMap<Object,Boolean>());
RamUsageTester.IdentityHashSet<Object> us = new RamUsageTester.IdentityHashSet<>();
int max = 100000;
int threshold = 256;
for (int i = 0; i < max; i++) {
// some of these will be interned and some will not so there will be collisions.
Integer v = rnd.nextInt(threshold);
boolean e1 = jdk.contains(v);
boolean e2 = us.contains(v);
Assert.assertEquals(e1, e2);
e1 = jdk.add(v);
e2 = us.add(v);
Assert.assertEquals(e1, e2);
}
Set<Object> collected = Collections.newSetFromMap(
new IdentityHashMap<Object,Boolean>());
for (Object o : us) {
collected.add(o);
}
Assert.assertEquals(collected, jdk);
}
}

View File

@ -22,15 +22,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/** Crawls object graph to collect RAM usage for testing */
public final class RamUsageTester {
@ -91,7 +89,7 @@ public final class RamUsageTester {
*/
private static long measureObjectSize(Object root, Accumulator accumulator) {
// Objects seen so far.
final IdentityHashSet<Object> seen = new IdentityHashSet<>();
final Set<Object> seen = Collections.newSetFromMap(new IdentityHashMap<Object, Boolean>());
// Class cache with reference Field and precalculated shallow size.
final IdentityHashMap<Class<?>, ClassCache> classCache = new IdentityHashMap<>();
// Stack of objects pending traversal. Recursion caused stack overflows.
@ -213,243 +211,5 @@ public final class RamUsageTester {
referenceFields.toArray(new Field[referenceFields.size()]));
return cachedInfo;
}
/**
* An identity hash set implemented using open addressing. No null keys are allowed.
*
* TODO: If this is useful outside this class, make it public - needs some work
*/
static final class IdentityHashSet<KType> implements Iterable<KType> {
/**
* Default load factor.
*/
public final static float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* Minimum capacity for the set.
*/
public final static int MIN_CAPACITY = 4;
/**
* All of set entries. Always of power of two length.
*/
public Object[] keys;
/**
* Cached number of assigned slots.
*/
public int assigned;
/**
* The load factor for this set (fraction of allocated or deleted slots before
* the buffers must be rehashed or reallocated).
*/
public final float loadFactor;
/**
* Cached capacity threshold at which we must resize the buffers.
*/
private int resizeThreshold;
/**
* Creates a hash set with the default capacity of 16.
* load factor of {@value #DEFAULT_LOAD_FACTOR}. `
*/
public IdentityHashSet() {
this(16, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a hash set with the given capacity, load factor of
* {@value #DEFAULT_LOAD_FACTOR}.
*/
public IdentityHashSet(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* Creates a hash set with the given capacity and load factor.
*/
public IdentityHashSet(int initialCapacity, float loadFactor) {
initialCapacity = Math.max(MIN_CAPACITY, initialCapacity);
assert initialCapacity > 0 : "Initial capacity must be between (0, "
+ Integer.MAX_VALUE + "].";
assert loadFactor > 0 && loadFactor < 1 : "Load factor must be between (0, 1).";
this.loadFactor = loadFactor;
allocateBuffers(roundCapacity(initialCapacity));
}
/**
* Adds a reference to the set. Null keys are not allowed.
*/
public boolean add(KType e) {
assert e != null : "Null keys not allowed.";
if (assigned >= resizeThreshold) expandAndRehash();
final int mask = keys.length - 1;
int slot = rehash(e) & mask;
Object existing;
while ((existing = keys[slot]) != null) {
if (e == existing) {
return false; // already found.
}
slot = (slot + 1) & mask;
}
assigned++;
keys[slot] = e;
return true;
}
/**
* Checks if the set contains a given ref.
*/
public boolean contains(KType e) {
final int mask = keys.length - 1;
int slot = rehash(e) & mask;
Object existing;
while ((existing = keys[slot]) != null) {
if (e == existing) {
return true;
}
slot = (slot + 1) & mask;
}
return false;
}
/** Rehash via MurmurHash.
*
* <p>The implementation is based on the
* finalization step from Austin Appleby's
* <code>MurmurHash3</code>.
*
* @see <a href="http://sites.google.com/site/murmurhash/">http://sites.google.com/site/murmurhash/</a>
*/
private static int rehash(Object o) {
int k = System.identityHashCode(o);
k ^= k >>> 16;
k *= 0x85ebca6b;
k ^= k >>> 13;
k *= 0xc2b2ae35;
k ^= k >>> 16;
return k;
}
/**
* Expand the internal storage buffers (capacity) or rehash current keys and
* values if there are a lot of deleted slots.
*/
private void expandAndRehash() {
final Object[] oldKeys = this.keys;
assert assigned >= resizeThreshold;
allocateBuffers(nextCapacity(keys.length));
/*
* Rehash all assigned slots from the old hash table.
*/
final int mask = keys.length - 1;
for (int i = 0; i < oldKeys.length; i++) {
final Object key = oldKeys[i];
if (key != null) {
int slot = rehash(key) & mask;
while (keys[slot] != null) {
slot = (slot + 1) & mask;
}
keys[slot] = key;
}
}
Arrays.fill(oldKeys, null);
}
/**
* Allocate internal buffers for a given capacity.
*
* @param capacity
* New capacity (must be a power of two).
*/
private void allocateBuffers(int capacity) {
this.keys = new Object[capacity];
this.resizeThreshold = (int) (capacity * DEFAULT_LOAD_FACTOR);
}
/**
* Return the next possible capacity, counting from the current buffers' size.
*/
protected int nextCapacity(int current) {
assert current > 0 && Long.bitCount(current) == 1 : "Capacity must be a power of two.";
assert ((current << 1) > 0) : "Maximum capacity exceeded ("
+ (0x80000000 >>> 1) + ").";
if (current < MIN_CAPACITY / 2) current = MIN_CAPACITY / 2;
return current << 1;
}
/**
* Round the capacity to the next allowed value.
*/
protected int roundCapacity(int requestedCapacity) {
// Maximum positive integer that is a power of two.
if (requestedCapacity > (0x80000000 >>> 1)) return (0x80000000 >>> 1);
int capacity = MIN_CAPACITY;
while (capacity < requestedCapacity) {
capacity <<= 1;
}
return capacity;
}
public void clear() {
assigned = 0;
Arrays.fill(keys, null);
}
public int size() {
return assigned;
}
public boolean isEmpty() {
return size() == 0;
}
@Override
public Iterator<KType> iterator() {
return new Iterator<KType>() {
int pos = -1;
Object nextElement = fetchNext();
@Override
public boolean hasNext() {
return nextElement != null;
}
@SuppressWarnings("unchecked")
@Override
public KType next() {
Object r = this.nextElement;
if (r == null) {
throw new NoSuchElementException();
}
this.nextElement = fetchNext();
return (KType) r;
}
private Object fetchNext() {
pos++;
while (pos < keys.length && keys[pos] == null) {
pos++;
}
return (pos >= keys.length ? null : keys[pos]);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
}