Skip to content

Commit

Permalink
HPPC-150: Make the default key mixing strategy globally configurable …
Browse files Browse the repository at this point in the history
…(via

          "hppc.bitmixer" sysprop). This property allows switching from
          random bit mixer strategy to any of the following:
          - random
              the default strategy. Varies bit mixer per instance.
          - deterministic
              the default strategy in HPPC up to v. 0.6.x. Varies bit
              mixer depending on hash container size.
          - none
              No bit mixing is used (hash sets/maps become scatter sets/ maps).

          This is a last-resort, discouraged, property. Your code should not
          rely on hash map/set ordering. Your code should use scatter maps when
          speed is of absolute importance and there are guarantees that keys
          won't be copied around to other associative containers.
×
  • Loading branch information
dweiss committed May 4, 2015
1 parent b2c7434 commit 3ff7f5b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 5 deletions.
16 changes: 16 additions & 0 deletions CHANGES.txt
Expand Up @@ -101,6 +101,22 @@ HPPC-117: A summary of API changes resulting from other issues.

** New features

HPPC-150: Make the default key mixing strategy globally configurable (via
"hppc.bitmixer" sysprop). This property allows switching from
random bit mixer strategy to any of the following:
- random
the default strategy. Varies bit mixer per instance.
- deterministic
the default strategy in HPPC up to v. 0.6.x. Varies bit
mixer depending on hash container size.
- none
No bit mixing is used (hash sets/maps become scatter sets/ maps).

This is a last-resort, discouraged, property. Your code should not
rely on hash map/set ordering. Your code should use scatter maps when
speed is of absolute importance and there are guarantees that keys
won't be copied around to other associative containers.

HPPC-145: Removed any "Open" infix from all classes.

HPPC-144: Moved certain esoteric key/value containers to a separate JAR. This
Expand Down
76 changes: 74 additions & 2 deletions hppc/src/main/java/com/carrotsearch/hppc/HashOrderMixing.java
@@ -1,12 +1,42 @@
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<HashOrderMixingStrategy> {
RANDOM {
@Override
public HashOrderMixingStrategy call() {
return randomized();
}
},
DETERMINISTIC {
@Override
public HashOrderMixingStrategy call() {
return deterministic();
}
},
NONE {
@Override
public HashOrderMixingStrategy call() {
return none();
}
};
}

private HashOrderMixing() {}

/**
Expand Down Expand Up @@ -37,6 +67,9 @@ public static HashOrderMixingStrategy randomized() {
* 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() {
Expand All @@ -58,7 +91,7 @@ public HashOrderMixingStrategy clone() {
*
* 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.
* unique keys (for which scatter tables should be used).
*
* @deprecated Permanently deprecated as a warning signal.
*/
Expand All @@ -71,7 +104,7 @@ public static HashOrderMixingStrategy 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.
* unique keys (for which scatter tables should be used).
*
* @deprecated Permanently deprecated as a warning signal.
*/
Expand All @@ -89,4 +122,43 @@ public HashOrderMixingStrategy clone() {
}
};
}

/**
* Returns the currently configured default {@link HashOrderMixingStrategy}.
*/
public static HashOrderMixingStrategy defaultStrategy() {
if (strategy == null) {
try {
String propValue = java.security.AccessController.doPrivileged(new PrivilegedAction<String>() {
@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.
}
}
}
Expand Up @@ -107,7 +107,7 @@ public KTypeHashSet(int expectedElements) {
* @see #KTypeHashSet(int, double, HashOrderMixingStrategy)
*/
public KTypeHashSet(int expectedElements, double loadFactor) {
this(expectedElements, loadFactor, HashOrderMixing.randomized());
this(expectedElements, loadFactor, HashOrderMixing.defaultStrategy());
}

/**
Expand Down
Expand Up @@ -118,7 +118,7 @@ public KTypeVTypeHashMap(int expectedElements) {
* are rejected by {@link #verifyLoadFactor(double)}.
*/
public KTypeVTypeHashMap(int expectedElements, double loadFactor) {
this(expectedElements, loadFactor, HashOrderMixing.randomized());
this(expectedElements, loadFactor, HashOrderMixing.defaultStrategy());
}

/**
Expand Down
5 changes: 4 additions & 1 deletion hppc/src/test/java/com/carrotsearch/hppc/ContainersTest.java
Expand Up @@ -23,7 +23,9 @@ public void resetState() {

@Test
public void testNoTestsSeed() {
Assertions.assertThat(System.getProperty("tests.seed")).isNull();
System.clearProperty("tests.seed");
Containers.test$reset();

Assertions.assertThat(Containers.randomSeed64())
.isNotEqualTo(Containers.randomSeed64());
}
Expand All @@ -32,6 +34,7 @@ public void testNoTestsSeed() {
public void testWithTestsSeed() {
System.setProperty("tests.seed", "deadbeef");
Containers.test$reset();

Assertions.assertThat(Containers.randomSeed64())
.isEqualTo(Containers.randomSeed64());
}
Expand Down

0 comments on commit 3ff7f5b

Please sign in to comment.