Skip to content

Commit bddf7f2

Browse files
committed
fixup: make mergemap mutate
Signed-off-by: Todd Baert <[email protected]>
1 parent 5cd181f commit bddf7f2

File tree

5 files changed

+71
-70
lines changed

5 files changed

+71
-70
lines changed

benchmark.txt

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ Audit done.
3636
processing is enabled explicitly (-proc:only, -proc:full).
3737
Use -Xlint:-options to suppress this message.
3838
Use -proc:none to disable annotation processing.
39-
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/EventDetails.java:[9,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
40-
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/ImmutableStructure.java:[22,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
4139
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/MutableStructure.java:[19,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
40+
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/ImmutableStructure.java:[22,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
41+
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/EventDetails.java:[9,1] Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.
4242
[WARNING] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/Value.java:[27,26] finalize() in java.lang.Object has been deprecated and marked for removal
4343
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/NoOpProvider.java: Some input files use or override a deprecated API.
4444
[INFO] /home/todd/git/java-sdk/src/main/java/dev/openfeature/sdk/NoOpProvider.java: Recompile with -Xlint:deprecation for details.
@@ -129,41 +129,41 @@ Audit done.
129129
[0.001s][warning][gc,init] Consider enabling -XX:+AlwaysPreTouch to avoid memory commit hiccups
130130
Iteration 1: num #instances #bytes class name (module)
131131
-------------------------------------------------------
132-
1: 559671 26864208 java.util.HashMap ([email protected])
133-
2: 352017 11264544 java.util.HashMap$Node ([email protected])
134-
3: 210497 11170088 [Ljava.util.HashMap$Node; ([email protected])
135-
4: 47815 9732672 [B ([email protected])
136-
5: 279526 8944832 java.util.HashMap$EntryIterator ([email protected])
137-
6: 305991 8105872 [Ljava.lang.Object; ([email protected])
138-
7: 445455 7127280 java.util.Optional ([email protected])
139-
8: 199209 6374688 java.util.Collections$UnmodifiableMap ([email protected])
140-
9: 154 4368416 [Ljdk.internal.vm.FillerElement; ([email protected])
141-
10: 100000 4000000 dev.openfeature.sdk.HookContext
142-
11: 100000 4000000 dev.openfeature.sdk.HookContext$HookContextBuilder
143-
12: 230006 3680096 dev.openfeature.sdk.Value
144-
13: 210062 3360992 java.util.HashMap$EntrySet ([email protected])
145-
14: 139788 3354912 java.util.ArrayList ([email protected])
146-
15: 199210 3187360 dev.openfeature.sdk.ImmutableStructure
147-
16: 130219 3125256 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1 ([email protected])
148-
17: 189210 3027360 dev.openfeature.sdk.ImmutableContext
149-
18: 177267 2836272 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry ([email protected])
150-
19: 82425 2637600 java.util.ArrayList$Itr ([email protected])
151-
20: 149207 2387312 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet ([email protected])
152-
21: 50000 2000000 dev.openfeature.sdk.FlagEvaluationDetails
153-
22: 50000 2000000 dev.openfeature.sdk.ProviderEvaluation
154-
23: 34652 1663296 dev.openfeature.sdk.FlagEvaluationDetails$FlagEvaluationDetailsBuilder
155-
24: 100001 1600016 dev.openfeature.sdk.NoOpProvider$$Lambda/0x00007bf8a002fa78
156-
25: 50000 1600000 [Ldev.openfeature.sdk.EvaluationContext;
157-
26: 50000 1600000 [Ljava.util.List; ([email protected])
158-
27: 100000 1600000 dev.openfeature.sdk.ImmutableMetadata
159-
28: 100000 1600000 dev.openfeature.sdk.ImmutableMetadata$ImmutableMetadataBuilder
160-
29: 100000 1600000 dev.openfeature.sdk.OpenFeatureClient$$Lambda/0x00007bf8a0082800
161-
30: 50000 1200000 dev.openfeature.sdk.FlagEvaluationOptions
162-
31: 44836 1076064 dev.openfeature.sdk.FlagEvaluationOptions$FlagEvaluationOptionsBuilder
163-
32: 26278 1051120 dev.openfeature.sdk.ProviderEvaluation$ProviderEvaluationBuilder
164-
33: 40785 978840 dev.openfeature.sdk.HookSupport$$Lambda/0x00007bf8a0081da8
165-
34: 40423 970152 dev.openfeature.sdk.HookSupport$$Lambda/0x00007bf8a0081b78
166-
35: 54212 867392 dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock$$Lambda/0x00007bf8a002eae8
132+
1: 480234 23051232 java.util.HashMap ([email protected])
133+
2: 150497 12050088 [Ljava.util.HashMap$Node; ([email protected])
134+
3: 332017 10624544 java.util.HashMap$Node ([email protected])
135+
4: 47815 9732480 [B ([email protected])
136+
5: 305991 8105872 [Ljava.lang.Object; ([email protected])
137+
6: 366682 5866912 java.util.Optional ([email protected])
138+
7: 183332 5866624 java.util.HashMap$EntryIterator ([email protected])
139+
8: 172970 5535040 java.util.Collections$UnmodifiableMap ([email protected])
140+
9: 100000 4000000 dev.openfeature.sdk.HookContext
141+
10: 100000 4000000 dev.openfeature.sdk.HookContext$HookContextBuilder
142+
11: 230006 3680096 dev.openfeature.sdk.Value
143+
12: 200062 3200992 java.util.HashMap$EntrySet ([email protected])
144+
13: 132870 3188880 java.util.ArrayList ([email protected])
145+
14: 192292 3076672 dev.openfeature.sdk.ImmutableStructure
146+
15: 182292 2916672 dev.openfeature.sdk.ImmutableContext
147+
16: 50000 2000000 dev.openfeature.sdk.FlagEvaluationDetails
148+
17: 50000 2000000 dev.openfeature.sdk.ProviderEvaluation
149+
18: 122968 1967488 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet ([email protected])
150+
19: 149 1884376 [Ljdk.internal.vm.FillerElement; ([email protected])
151+
20: 56476 1807232 java.util.ArrayList$Itr ([email protected])
152+
21: 37481 1799088 dev.openfeature.sdk.FlagEvaluationDetails$FlagEvaluationDetailsBuilder
153+
22: 100001 1600016 dev.openfeature.sdk.NoOpProvider$$Lambda/0x000076e79c02fa78
154+
23: 50000 1600000 [Ldev.openfeature.sdk.EvaluationContext;
155+
24: 50000 1600000 [Ljava.util.List; ([email protected])
156+
25: 100000 1600000 dev.openfeature.sdk.OpenFeatureClient$$Lambda/0x000076e79c082800
157+
26: 36720 1468800 dev.openfeature.sdk.ProviderEvaluation$ProviderEvaluationBuilder
158+
27: 87481 1399696 dev.openfeature.sdk.ImmutableMetadata
159+
28: 50000 1200000 dev.openfeature.sdk.FlagEvaluationOptions
160+
29: 74201 1187216 dev.openfeature.sdk.ImmutableMetadata$ImmutableMetadataBuilder
161+
30: 73235 1171760 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$UnmodifiableEntry ([email protected])
162+
31: 45869 1100856 java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1 ([email protected])
163+
32: 43776 1050624 dev.openfeature.sdk.FlagEvaluationOptions$FlagEvaluationOptionsBuilder
164+
33: 40016 960384 dev.openfeature.sdk.HookSupport$$Lambda/0x000076e79c081b78
165+
34: 39967 959208 dev.openfeature.sdk.HookSupport$$Lambda/0x000076e79c081da8
166+
35: 57783 924528 dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock$$Lambda/0x000076e79c02eae8
167167
36: 4490 721440 [I ([email protected])
168168
37: 26594 638256 java.lang.String ([email protected])
169169
38: 1461 390008 [J ([email protected])
@@ -248,20 +248,20 @@ Iteration 1: num #instances #bytes class name (module)
248248
117: 65 5200 java.net.URI ([email protected])
249249
118: 215 5104 [Ljdk.internal.org.objectweb.asm.Type; ([email protected])
250250
truncated...
251-
Total 5107873 156138304
251+
Total 4452140 139359040
252252

253-
0.187 s/op
254-
+totalAllocatedBytes: 156138304.000 bytes
255-
+totalAllocatedInstances: 5107873.000 instances
253+
0.186 s/op
254+
+totalAllocatedBytes: 139359040.000 bytes
255+
+totalAllocatedInstances: 4452140.000 instances
256256
+totalHeap: 521412608.000 bytes
257257

258258

259259

260260
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalAllocatedBytes":
261-
156138304.000 bytes
261+
139359040.000 bytes
262262

263263
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalAllocatedInstances":
264-
5107873.000 instances
264+
4452140.000 instances
265265

266266
Secondary result "dev.openfeature.sdk.benchmark.AllocationBenchmark.run:+totalHeap":
267267
521412608.000 bytes
@@ -282,13 +282,13 @@ different JVMs are already problematic, the performance difference caused by dif
282282
modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons.
283283

284284
Benchmark Mode Cnt Score Error Units
285-
AllocationBenchmark.run ss 0.187 s/op
286-
AllocationBenchmark.run:+totalAllocatedBytes ss 156138304.000 bytes
287-
AllocationBenchmark.run:+totalAllocatedInstances ss 5107873.000 instances
285+
AllocationBenchmark.run ss 0.186 s/op
286+
AllocationBenchmark.run:+totalAllocatedBytes ss 139359040.000 bytes
287+
AllocationBenchmark.run:+totalAllocatedInstances ss 4452140.000 instances
288288
AllocationBenchmark.run:+totalHeap ss 521412608.000 bytes
289289
[INFO] ------------------------------------------------------------------------
290290
[INFO] BUILD SUCCESS
291291
[INFO] ------------------------------------------------------------------------
292-
[INFO] Total time: 8.226 s
293-
[INFO] Finished at: 2024-10-23T12:36:22-04:00
292+
[INFO] Total time: 8.280 s
293+
[INFO] Finished at: 2024-10-23T12:37:24-04:00
294294
[INFO] ------------------------------------------------------------------------

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

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

3-
import java.util.HashMap;
43
import java.util.Map;
54
import java.util.Map.Entry;
65
import java.util.function.Function;
@@ -26,38 +25,38 @@ public interface EvaluationContext extends Structure {
2625
EvaluationContext merge(EvaluationContext overridingContext);
2726

2827
/**
29-
* Recursively merges the base Value map with the overriding map.
28+
* Recursively merges the overriding map into the base Value map.
29+
* The base map is mutated, the overriding map is not.
30+
* Null maps will cause no-op.
3031
*
31-
* @param <T> Structure type
3232
* @param newStructure function to create the right structure(s) for Values
3333
* @param base base map to merge
3434
* @param overriding overriding map to merge
35-
* @return resulting merged map
3635
*/
37-
static <T extends Structure> Map<String, Value> mergeMaps(Function<Map<String, Value>, Structure> newStructure,
36+
static void mergeMaps(Function<Map<String, Value>, Structure> newStructure,
3837
Map<String, Value> base,
3938
Map<String, Value> overriding) {
4039

41-
if (base == null || base.isEmpty()) {
42-
return overriding;
40+
if (base == null) {
41+
return;
4342
}
4443
if (overriding == null || overriding.isEmpty()) {
45-
return base;
44+
return;
4645
}
4746

48-
final Map<String, Value> merged = new HashMap<>(base);
4947
for (Entry<String, Value> overridingEntry : overriding.entrySet()) {
5048
String key = overridingEntry.getKey();
51-
if (overridingEntry.getValue().isStructure() && merged.containsKey(key) && merged.get(key).isStructure()) {
52-
Structure mergedValue = merged.get(key).asStructure();
49+
if (overridingEntry.getValue().isStructure() && base.containsKey(key) && base.get(key).isStructure()) {
50+
Structure mergedValue = base.get(key).asStructure();
5351
Structure overridingValue = overridingEntry.getValue().asStructure();
54-
Map<String, Value> newMap = mergeMaps(newStructure, mergedValue.asUnmodifiableMap(),
52+
Map<String, Value> newMap = mergedValue.asMap();
53+
mergeMaps(newStructure, newMap,
5554
overridingValue.asUnmodifiableMap());
56-
merged.put(key, new Value(newStructure.apply(newMap)));
55+
base.put(key, new Value(newStructure.apply(newMap)));
5756
} else {
58-
merged.put(key, overridingEntry.getValue());
57+
base.put(key, overridingEntry.getValue());
5958
}
6059
}
61-
return merged;
60+
return;
6261
}
6362
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ public EvaluationContext merge(EvaluationContext overridingContext) {
8787
return new ImmutableContext(overridingContext.asUnmodifiableMap());
8888
}
8989

90-
return new ImmutableContext(
91-
EvaluationContext.mergeMaps(ImmutableStructure::new, this.asUnmodifiableMap(),
92-
overridingContext.asUnmodifiableMap()));
90+
Map<String, Value> attributes = this.asMap();
91+
EvaluationContext.mergeMaps(ImmutableStructure::new, attributes,
92+
overridingContext.asUnmodifiableMap());
93+
return new ImmutableContext(attributes);
9394
}
9495

9596
@SuppressWarnings("all")

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ public EvaluationContext merge(EvaluationContext overridingContext) {
121121
return overridingContext;
122122
}
123123

124-
Map<String, Value> merged = EvaluationContext.mergeMaps(
125-
MutableStructure::new, this.asUnmodifiableMap(), overridingContext.asUnmodifiableMap());
126-
return new MutableContext(merged);
124+
Map<String, Value> attributes = this.asMap();
125+
EvaluationContext.mergeMaps(
126+
MutableStructure::new, attributes, overridingContext.asUnmodifiableMap());
127+
return new MutableContext(attributes);
127128
}
128129

129130
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ private EvaluationContext mergeContextMaps(EvaluationContext... contexts) {
203203
Map merged = new HashMap<>();
204204
for (EvaluationContext evaluationContext : contexts) {
205205
if (evaluationContext != null && !evaluationContext.isEmpty()) {
206-
merged = EvaluationContext.mergeMaps(ImmutableStructure::new, merged,
206+
EvaluationContext.mergeMaps(ImmutableStructure::new, merged,
207207
evaluationContext.asUnmodifiableMap());
208208
}
209209
}

0 commit comments

Comments
 (0)