
com.carrotsearch.hppc.HashOrderMixing Maven / Gradle / Ivy
package com.carrotsearch.hppc;
import java.security.PrivilegedAction;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Factory methods to acquire the most common types of
* {@link HashOrderMixingStrategy}.
*
* @see HashOrderMixingStrategy
*/
public final class HashOrderMixing {
public static final String PROPERTY_BIT_MIXER = "hppc.bitmixer";
private static Strategy strategy;
public enum Strategy implements Callable {
RANDOM {
@Override
public HashOrderMixingStrategy call() {
return randomized();
}
},
DETERMINISTIC {
@Override
public HashOrderMixingStrategy call() {
return deterministic();
}
},
NONE {
@Override
public HashOrderMixingStrategy call() {
return none();
}
};
}
private HashOrderMixing() {}
/**
* @see #deterministic()
*/
private static final HashOrderMixingStrategy DETERMINISTIC = new HashOrderMixingStrategy() {
@Override
public int newKeyMixer(int newContainerBufferSize) {
return BitMixer.mix32(newContainerBufferSize);
}
@Override
public HashOrderMixingStrategy clone() {
return this;
}
};
/**
* Returns a randomized {@link HashOrderMixingStrategy} that issues unique
* per-container seed. This minimizes the chances of hash distribution conflicts.
*/
public static HashOrderMixingStrategy randomized() {
return RandomizedHashOrderMixer.INSTANCE;
}
/**
* A constant {@link HashOrderMixingStrategy}. This is useful if one needs to have
* deterministic key distribution but wishes to control it manually.
*
* Do not use the same constant for more than one container.
*
* Consider using {@linkplain ObjectScatterSet scatter maps or sets} instead
* of constant hash order mixer.
*/
public static HashOrderMixingStrategy constant(final long seed) {
return new HashOrderMixingStrategy() {
@Override
public int newKeyMixer(int newContainerBufferSize) {
return (int) BitMixer.mix64(newContainerBufferSize ^ seed);
}
@Override
public HashOrderMixingStrategy clone() {
return this;
}
};
}
/**
* Deterministic {@link HashOrderMixingStrategy} will reorder keys depending
* on the size of the container's buffer.
*
* This is inherently unsafe with hash containers using linear conflict
* addressing. The only use case when this can be useful is to count/ collect
* unique keys (for which scatter tables should be used).
*
* @deprecated Permanently deprecated as a warning signal.
*/
@Deprecated
public static HashOrderMixingStrategy deterministic() {
return DETERMINISTIC;
}
/**
* This strategy does not change the hash order of keys at all. This
* is inherently unsafe with hash containers using linear conflict
* addressing. The only use case when this can be useful is to count/ collect
* unique keys (for which scatter tables should be used).
*
* @deprecated Permanently deprecated as a warning signal.
*/
@Deprecated
public static HashOrderMixingStrategy none() {
return new HashOrderMixingStrategy() {
@Override
public int newKeyMixer(int newContainerBufferSize) {
return 0;
}
@Override
public HashOrderMixingStrategy clone() {
return this;
}
};
}
/**
* Returns the currently configured default {@link HashOrderMixingStrategy}.
*/
public static HashOrderMixingStrategy defaultStrategy() {
if (strategy == null) {
try {
String propValue = java.security.AccessController.doPrivileged(new PrivilegedAction() {
@Override
public String run() {
return System.getProperty(PROPERTY_BIT_MIXER);
}
});
if (propValue != null) {
for (Strategy s : Strategy.values()) {
if (s.name().equalsIgnoreCase(propValue)) {
strategy = s;
break;
}
}
}
} catch (SecurityException e) {
// If failed on security exception, don't panic.
Logger.getLogger(Containers.class.getName())
.log(Level.INFO, "Failed to read 'tests.seed' property for initial random seed.", e);
}
if (strategy == null) {
strategy = Strategy.RANDOM;
}
}
try {
return strategy.call();
} catch (Exception e) {
throw new RuntimeException(e); // Effectively unreachable.
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy