mirror of https://github.com/apache/lucene.git
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:
parent
08cdb3c867
commit
e9366323e8
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -22,15 +22,13 @@ import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.Set;
|
||||||
|
|
||||||
/** Crawls object graph to collect RAM usage for testing */
|
/** Crawls object graph to collect RAM usage for testing */
|
||||||
public final class RamUsageTester {
|
public final class RamUsageTester {
|
||||||
|
@ -91,7 +89,7 @@ public final class RamUsageTester {
|
||||||
*/
|
*/
|
||||||
private static long measureObjectSize(Object root, Accumulator accumulator) {
|
private static long measureObjectSize(Object root, Accumulator accumulator) {
|
||||||
// Objects seen so far.
|
// 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.
|
// Class cache with reference Field and precalculated shallow size.
|
||||||
final IdentityHashMap<Class<?>, ClassCache> classCache = new IdentityHashMap<>();
|
final IdentityHashMap<Class<?>, ClassCache> classCache = new IdentityHashMap<>();
|
||||||
// Stack of objects pending traversal. Recursion caused stack overflows.
|
// Stack of objects pending traversal. Recursion caused stack overflows.
|
||||||
|
@ -214,242 +212,4 @@ public final class RamUsageTester {
|
||||||
return cachedInfo;
|
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue