Skip to content

Commit

Permalink
Avoid map resizing in PrivateViewConfig
Browse files Browse the repository at this point in the history
Properly size the LinkedHashMaps in the createState method to avoid rehashing / resizing.
Additionally, if instrumentation is not enabled, just use the singleton empty map.

To facilitate this change, add an Iterables utility class with a "size" helper to determine
the size of the passed in Iterable; this is necessary because the Config::keys method returns
Iterable, but in practice is typically a Collection.

Finally, add a marker annotation, Internal, to indicate classes such as Maps and Iterables that
are not meant to be used by users of Archaius and may not have stable APIs.
  • Loading branch information
kilink committed Sep 21, 2024
1 parent 3424aa3 commit 6dadc2e
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 3 deletions.
20 changes: 20 additions & 0 deletions archaius2-core/src/main/java/com/netflix/archaius/Internal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.netflix.archaius;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;

/**
* Annotation to convey classes and other elements not meant to be part of the public API, but are public by necessity;
* such elements should not be depended on by consumers as there is no guarantee of API stability.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {CONSTRUCTOR, METHOD, TYPE, FIELD, PACKAGE})
public @interface Internal {
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
*/
package com.netflix.archaius.config;

import java.util.LinkedHashMap;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;

import com.netflix.archaius.api.Config;
import com.netflix.archaius.api.ConfigListener;
import com.netflix.archaius.api.Decoder;
import com.netflix.archaius.api.StrInterpolator;
import com.netflix.archaius.util.Iterables;
import com.netflix.archaius.util.Maps;

/**
* View into another Config that allows usage of a private {@link Decoder}, {@link StrInterpolator}, and
Expand Down Expand Up @@ -68,9 +70,11 @@ private void updateState(Config config) {
}

private CachedState createState(Config config) {
Map<String, Object> data = new LinkedHashMap<>();
Map<String, Config> instrumentedKeys = new LinkedHashMap<>();
boolean instrumented = config.instrumentationEnabled();
int size = Iterables.size(config.keys());
final Map<String, Object> data = Maps.newLinkedHashMap(size);
final Map<String, Config> instrumentedKeys = instrumented ? Maps.newHashMap(size) : Collections.emptyMap();

config.forEachPropertyUninstrumented((k, v) -> {
data.put(k, v);
if (instrumented) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.netflix.archaius.util;

import com.netflix.archaius.Internal;

import java.util.Collection;

@Internal
public final class Iterables {
private Iterables() {}

/**
* Returns the number of elements in {@code iterable}.
*/
public static int size(Iterable<?> iterable) {
if (iterable instanceof Collection<?>) {
return ((Collection<?>) iterable).size();
}
int size = 0;
for (Object ignored : iterable) {
size++;
}
return size;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.netflix.archaius.util;

import com.netflix.archaius.Internal;

import java.util.HashMap;
import java.util.LinkedHashMap;

@Internal
public final class Maps {
private Maps() {}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.netflix.archaius.util;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class IterablesTest {
@Test
public void testSize() {
assertEquals(0, Iterables.size(ImmutableList.of()));
assertEquals(1, Iterables.size(ImmutableList.of(1)));
assertEquals(2, Iterables.size(ImmutableSet.of(1, 2)));
assertEquals(0, Iterables.size(Collections::emptyIterator));
assertEquals(1, Iterables.size(() -> Stream.<Object>of("foo").iterator()));
assertEquals(3, Iterables.size(() -> ImmutableList.<Object>of(1, 2, 3).iterator()));
}
}

0 comments on commit 6dadc2e

Please sign in to comment.