Skip to content

Commit 9052e91

Browse files
chrfwowtoddbaert
andauthored
feat: Performance enhancements (#1741)
* add bench Signed-off-by: christian.lutnik <[email protected]> * fix bench Signed-off-by: christian.lutnik <[email protected]> * merge master Signed-off-by: christian.lutnik <[email protected]> * improve benchmark Signed-off-by: christian.lutnik <[email protected]> * improve benchmark Signed-off-by: christian.lutnik <[email protected]> * add str hook for ctx Signed-off-by: christian.lutnik <[email protected]> * a collection of perf enhancements Signed-off-by: christian.lutnik <[email protected]> * revert comments Signed-off-by: christian.lutnik <[email protected]> * extract hash map generation Signed-off-by: christian.lutnik <[email protected]> --------- Signed-off-by: christian.lutnik <[email protected]> Co-authored-by: Todd Baert <[email protected]>
1 parent ab04409 commit 9052e91

File tree

6 files changed

+56
-32
lines changed

6 files changed

+56
-32
lines changed

src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dev.openfeature.sdk;
22

3-
import java.util.Optional;
43
import lombok.AllArgsConstructor;
54
import lombok.Builder;
65
import lombok.Data;
@@ -26,7 +25,7 @@ public class FlagEvaluationDetails<T> implements BaseEvaluation<T> {
2625
private String errorMessage;
2726

2827
@Builder.Default
29-
private ImmutableMetadata flagMetadata = ImmutableMetadata.builder().build();
28+
private ImmutableMetadata flagMetadata = ImmutableMetadata.EMPTY;
3029

3130
/**
3231
* Generate detail payload from the provider response.
@@ -37,15 +36,18 @@ public class FlagEvaluationDetails<T> implements BaseEvaluation<T> {
3736
* @return detail payload
3837
*/
3938
public static <T> FlagEvaluationDetails<T> from(ProviderEvaluation<T> providerEval, String flagKey) {
40-
return FlagEvaluationDetails.<T>builder()
41-
.flagKey(flagKey)
42-
.value(providerEval.getValue())
43-
.variant(providerEval.getVariant())
44-
.reason(providerEval.getReason())
45-
.errorMessage(providerEval.getErrorMessage())
46-
.errorCode(providerEval.getErrorCode())
47-
.flagMetadata(Optional.ofNullable(providerEval.getFlagMetadata())
48-
.orElse(ImmutableMetadata.builder().build()))
49-
.build();
39+
var flagMetadata = providerEval.getFlagMetadata();
40+
if (flagMetadata == null) {
41+
flagMetadata = ImmutableMetadata.EMPTY;
42+
}
43+
44+
return new FlagEvaluationDetails<>(
45+
flagKey,
46+
providerEval.getValue(),
47+
providerEval.getVariant(),
48+
providerEval.getReason(),
49+
providerEval.getErrorCode(),
50+
providerEval.getErrorMessage(),
51+
flagMetadata);
5052
}
5153
}

src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
@lombok.Value
1111
@Builder
1212
public class FlagEvaluationOptions {
13+
14+
public static final FlagEvaluationOptions EMPTY =
15+
FlagEvaluationOptions.builder().build();
16+
1317
@Singular
1418
List<Hook> hooks;
1519

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package dev.openfeature.sdk;
2+
3+
import java.util.HashMap;
4+
5+
class HashMapUtils {
6+
private HashMapUtils() {}
7+
8+
static <K, V> HashMap<K, V> forEntries(int expectedEntries) {
9+
return new HashMap<>((int) Math.ceil(expectedEntries / .75));
10+
}
11+
}

src/main/java/dev/openfeature/sdk/ImmutableContext.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.openfeature.sdk;
22

33
import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport;
4+
import java.util.Collections;
45
import java.util.HashMap;
56
import java.util.Map;
67
import java.util.function.Function;
@@ -20,7 +21,7 @@
2021
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
2122
public final class ImmutableContext implements EvaluationContext {
2223

23-
public static final ImmutableContext EMPTY = new ImmutableContext();
24+
public static final ImmutableContext EMPTY = new ImmutableContext(Collections.emptyMap());
2425

2526
@Delegate(excludes = DelegateExclusions.class)
2627
private final ImmutableStructure structure;
@@ -58,7 +59,7 @@ public ImmutableContext(Map<String, Value> attributes) {
5859
* @param attributes evaluation context attributes
5960
*/
6061
public ImmutableContext(String targetingKey, Map<String, Value> attributes) {
61-
if (targetingKey != null && !targetingKey.trim().isEmpty()) {
62+
if (targetingKey != null && !targetingKey.isBlank()) {
6263
this.structure = new ImmutableStructure(targetingKey, attributes);
6364
} else {
6465
this.structure = new ImmutableStructure(attributes);

src/main/java/dev/openfeature/sdk/ImmutableStructure.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.util.HashSet;
55
import java.util.Map;
66
import java.util.Map.Entry;
7-
import java.util.Optional;
87
import java.util.Set;
98
import lombok.EqualsAndHashCode;
109
import lombok.ToString;
@@ -69,15 +68,21 @@ private static Map<String, Value> copyAttributes(Map<String, Value> in) {
6968
}
7069

7170
private static Map<String, Value> copyAttributes(Map<String, Value> in, String targetingKey) {
72-
Map<String, Value> copy = new HashMap<>();
71+
Map<String, Value> copy;
7372
if (in != null) {
73+
var numMappings = in.size();
74+
if (targetingKey != null) {
75+
numMappings++;
76+
}
77+
copy = HashMapUtils.forEntries(numMappings);
7478
for (Entry<String, Value> entry : in.entrySet()) {
75-
copy.put(
76-
entry.getKey(),
77-
Optional.ofNullable(entry.getValue())
78-
.map((Value val) -> val.clone())
79-
.orElse(null));
79+
var key = entry.getKey();
80+
var value = entry.getValue();
81+
Value cloned = value == null ? null : value.clone();
82+
copy.put(key, cloned);
8083
}
84+
} else {
85+
copy = new HashMap<>(targetingKey == null ? 0 : 1);
8186
}
8287
if (targetingKey != null) {
8388
copy.put(EvaluationContext.TARGETING_KEY, new Value(targetingKey));

src/main/java/dev/openfeature/sdk/OpenFeatureClient.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,13 @@ private <T> FlagEvaluationDetails<T> evaluateFlag(
163163
FlagEvaluationDetails<T> details = null;
164164
HookSupportData hookSupportData = new HookSupportData();
165165

166-
var flagOptions = ObjectUtils.defaultIfNull(
167-
options, () -> FlagEvaluationOptions.builder().build());
166+
FlagEvaluationOptions flagOptions;
167+
if (options == null) {
168+
flagOptions = FlagEvaluationOptions.EMPTY;
169+
} else {
170+
flagOptions = options;
171+
}
172+
168173
hookSupportData.hints = Collections.unmodifiableMap(flagOptions.getHookHints());
169174
var context = new LayeredEvaluationContext(
170175
openfeatureApi.getEvaluationContext(),
@@ -323,8 +328,7 @@ public FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defa
323328

324329
@Override
325330
public FlagEvaluationDetails<Boolean> getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx) {
326-
return getBooleanDetails(
327-
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
331+
return getBooleanDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY);
328332
}
329333

330334
@Override
@@ -356,8 +360,7 @@ public FlagEvaluationDetails<String> getStringDetails(String key, String default
356360

357361
@Override
358362
public FlagEvaluationDetails<String> getStringDetails(String key, String defaultValue, EvaluationContext ctx) {
359-
return getStringDetails(
360-
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
363+
return getStringDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY);
361364
}
362365

363366
@Override
@@ -389,8 +392,7 @@ public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defa
389392

390393
@Override
391394
public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx) {
392-
return getIntegerDetails(
393-
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
395+
return getIntegerDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY);
394396
}
395397

396398
@Override
@@ -454,8 +456,7 @@ public FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultVa
454456

455457
@Override
456458
public FlagEvaluationDetails<Value> getObjectDetails(String key, Value defaultValue, EvaluationContext ctx) {
457-
return getObjectDetails(
458-
key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
459+
return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY);
459460
}
460461

461462
@Override
@@ -466,7 +467,7 @@ public FlagEvaluationDetails<Value> getObjectDetails(
466467

467468
@Override
468469
public ClientMetadata getMetadata() {
469-
return () -> domain;
470+
return this::getDomain;
470471
}
471472

472473
/**

0 commit comments

Comments
 (0)