Skip to content

Commit acd352d

Browse files
committed
optimize EvaluatorBucketing
1 parent 650dfbe commit acd352d

File tree

2 files changed

+39
-13
lines changed

2 files changed

+39
-13
lines changed

lib/sdk/server/src/main/java/com/launchdarkly/sdk/server/EvaluatorBucketing.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,42 @@ static float computeBucketValue(
4747
}
4848
}
4949

50-
String idHash = getBucketableStringValue(contextValue);
51-
if (idHash == null) {
50+
StringBuilder keyBuilder = new StringBuilder();
51+
if (seed != null) {
52+
keyBuilder.append(seed.intValue());
53+
} else {
54+
keyBuilder.append(flagOrSegmentKey).append('.').append(salt);
55+
}
56+
keyBuilder.append('.');
57+
if (!getBucketableStringValue(keyBuilder, contextValue)) {
5258
return 0;
5359
}
5460

55-
String prefix;
56-
if (seed != null) {
57-
prefix = seed.toString();
58-
} else {
59-
prefix = flagOrSegmentKey + "." + salt;
61+
// turn the first 15 hex digits of this into a long
62+
byte[] hash = DigestUtils.sha1(keyBuilder.toString());
63+
long longVal = 0;
64+
for (int i = 0; i < 7; i++) {
65+
longVal <<= 8;
66+
longVal |= (hash[i] & 0xff);
6067
}
61-
String hash = DigestUtils.sha1Hex(prefix + "." + idHash).substring(0, 15);
62-
long longVal = Long.parseLong(hash, 16);
68+
longVal <<= 4;
69+
longVal |= ((hash[7] >> 4) & 0xf);
6370
return (float) longVal / LONG_SCALE;
6471
}
6572

66-
private static String getBucketableStringValue(LDValue userValue) {
73+
private static boolean getBucketableStringValue(StringBuilder keyBuilder, LDValue userValue) {
6774
switch (userValue.getType()) {
6875
case STRING:
69-
return userValue.stringValue();
76+
keyBuilder.append(userValue.stringValue());
77+
return true;
7078
case NUMBER:
71-
return userValue.isInt() ? String.valueOf(userValue.intValue()) : null;
79+
if (userValue.isInt()) {
80+
keyBuilder.append(userValue.intValue());
81+
return true;
82+
}
83+
return false;
7284
default:
73-
return null;
85+
return false;
7486
}
7587
}
7688
}

lib/sdk/server/src/test/java/com/launchdarkly/sdk/server/EvaluatorBucketingTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import com.launchdarkly.sdk.server.DataModel.RolloutKind;
99
import com.launchdarkly.sdk.server.DataModel.WeightedVariation;
1010

11+
import org.apache.commons.codec.digest.DigestUtils;
12+
1113
import org.junit.Test;
1214

1315
import java.util.Arrays;
@@ -132,6 +134,18 @@ public void cannotBucketByBooleanAttribute() {
132134
assertEquals(0f, result, Float.MIN_VALUE);
133135
}
134136

137+
@Test
138+
public void optimizedHashText() {
139+
LDContext context = LDContext.builder("key")
140+
.set("stringattr", "33333")
141+
.build();
142+
float result = computeBucketValue(false, noSeed, context, null, "key", AttributeRef.fromLiteral("stringattr"), "salt");
143+
String hash = DigestUtils.sha1Hex("key.salt.33333").substring(0, 15);
144+
long longVal = Long.parseLong(hash, 16);
145+
float expectedResult = longVal / (float) 0xFFFFFFFFFFFFFFFL;
146+
assertEquals(expectedResult, result, Float.MIN_VALUE);
147+
}
148+
135149
private static void assertVariationIndexFromRollout(
136150
int expectedVariation,
137151
Rollout rollout,

0 commit comments

Comments
 (0)