diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureDeduper.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureDeduper.java index 879488b2..c50ef684 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureDeduper.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureDeduper.java @@ -8,6 +8,11 @@ * Decides whether a hook should be told about an evaluation, so that repeated evaluations resolving * to the same result do not invoke the hook again within a time window. *
+ * This class is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + * It is experimental. Subclassing it to change which evaluations are deduplicated is supported, but the shape + * it is subclassed through, and the components of {@link EvaluationExposureKey} a subclass reasons about, may + * change. + *
* Deduplication is opt-in per hook: a hook is told about every evaluation until you wrap it in a * {@link DedupingHook}, which is what consults a deduper. * @@ -112,12 +117,10 @@ public synchronized void reset() { private static final class TrackedFlag { private final String mobileKeyHash; private final String flagKey; - private final int hashCode; TrackedFlag(EvaluationExposureKey key) { this.mobileKeyHash = key.getMobileKeyHash(); this.flagKey = key.getFlagKey(); - this.hashCode = 31 * Objects.hashCode(mobileKeyHash) + Objects.hashCode(flagKey); } @Override @@ -130,14 +133,13 @@ public boolean equals(Object other) { } TrackedFlag o = (TrackedFlag) other; - return hashCode == o.hashCode - && Objects.equals(flagKey, o.flagKey) + return Objects.equals(flagKey, o.flagKey) && Objects.equals(mobileKeyHash, o.mobileKeyHash); } @Override public int hashCode() { - return hashCode; + return 31 * Objects.hashCode(mobileKeyHash) + Objects.hashCode(flagKey); } } diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKey.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKey.java index 17fb2e2a..07a49366 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKey.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKey.java @@ -8,6 +8,10 @@ * Identifies the evaluation result a hook is about to be told about, so that an * {@link EvaluationExposureDeduper} can recognize a repeat of it. *
+ * This class is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + * It is experimental. Which components make up the identity of an evaluation is the most likely part to be + * revised, so a deduper subclass that reasons about them may need to change with it. + *
* Two evaluations are the same exposure when every component here matches. The value is included * directly rather than inferred from the variation and version: those are the identity LaunchDarkly * uses to bucket summary events, but neither by itself guarantees that the payload is unchanged. @@ -38,7 +42,7 @@ * experiment does not depend on the window; a hook that reads the reason itself is what can miss such * a change until the window elapses. *
- * Instances are immutable, and their hash code is computed once, the first time one is asked for. + * Instances are immutable. */ public final class EvaluationExposureKey { private final String mobileKeyHash; @@ -48,12 +52,6 @@ public final class EvaluationExposureKey { private final int flagVersion; private final String fullyQualifiedContextKey; - // Computed on demand, because the SDK's own deduper recognizes a repeat by the flag a key belongs - // to and the result it describes, and so never hashes a whole key: only a deduper of your own - // that holds keys in a map or a set does. Races are benign, as every thread computes the same - // value from fields that cannot change. - private int hashCode; - /** * Creates a key with a JSON null value. Prefer the overload accepting {@code value}, since the * variation and version do not by themselves distinguish one result from another. @@ -159,17 +157,12 @@ public boolean equals(Object other) { @Override public int hashCode() { - int hash = hashCode; - if (hash == 0) { - hash = Objects.hashCode(mobileKeyHash); - hash = 31 * hash + Objects.hashCode(flagKey); - hash = 31 * hash + Objects.hashCode(value); - hash = 31 * hash + variation; - hash = 31 * hash + flagVersion; - hash = 31 * hash + Objects.hashCode(fullyQualifiedContextKey); - hashCode = hash; - } - return hash; + int hash = Objects.hashCode(mobileKeyHash); + hash = 31 * hash + Objects.hashCode(flagKey); + hash = 31 * hash + Objects.hashCode(value); + hash = 31 * hash + variation; + hash = 31 * hash + flagVersion; + return 31 * hash + Objects.hashCode(fullyQualifiedContextKey); } @Override diff --git a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKeySupplier.java b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKeySupplier.java index 2969a133..d6781973 100644 --- a/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKeySupplier.java +++ b/launchdarkly-android-client-sdk/src/main/java/com/launchdarkly/sdk/android/integrations/EvaluationExposureKeySupplier.java @@ -7,6 +7,9 @@ /** * Builds the key identifying the result an evaluation is about to return. *
+ * This interface is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + * It is experimental. + *
* The SDK gives one of these to each {@link EvaluationSeriesContext} it builds, so that a hook which * needs the identity of an evaluation can ask for it without the SDK building one for hooks that do * not. {@link DedupingHook} is the hook that needs it.