This is an automated email from the ASF dual-hosted git repository. xxyu pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
commit c583f433242f482168db596abd1183bac23f4d72 Author: Junqing Cai <caicai121...@163.com> AuthorDate: Thu Oct 13 15:08:03 2022 +0800 KYLIN-5311 Improve performance of getSubstitutor --- .../kylin/common/ICachedExternalConfigLoader.java | 2 +- .../org/apache/kylin/common/KylinConfigBase.java | 9 +- .../kylin/common/KylinExternalConfigLoader.java | 9 +- .../apache/kylin/common/PropertiesDelegate.java | 34 ++--- .../apache/kylin/common/KylinConfigBaseTest.java | 8 + .../kylin/common/PropertiesDelegateTest.java | 116 ++++++++++++++ .../kylin/common/util/CompositeMapViewTest.java | 167 +++++++++++++++++++++ 7 files changed, 316 insertions(+), 29 deletions(-) diff --git a/src/core-common/src/main/java/org/apache/kylin/common/ICachedExternalConfigLoader.java b/src/core-common/src/main/java/org/apache/kylin/common/ICachedExternalConfigLoader.java index 9af569f8d1..6d805eb85c 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/ICachedExternalConfigLoader.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/ICachedExternalConfigLoader.java @@ -23,5 +23,5 @@ import com.google.common.collect.ImmutableMap; import io.kyligence.config.core.loader.IExternalConfigLoader; public interface ICachedExternalConfigLoader extends IExternalConfigLoader { - ImmutableMap getPropertyEntries(); + ImmutableMap<Object, Object> getPropertyEntries(); } diff --git a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java index 8498eba0e6..d0b4fda104 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java @@ -179,8 +179,8 @@ public abstract class KylinConfigBase implements Serializable { /** * only reload properties */ - volatile PropertiesDelegate properties; - volatile StrSubstitutor substitutor; + final PropertiesDelegate properties; + final transient StrSubstitutor substitutor; protected KylinConfigBase(IExternalConfigLoader configLoader) { this(new Properties(), configLoader); @@ -190,6 +190,7 @@ public abstract class KylinConfigBase implements Serializable { this(props, false, configLoader); } + @SuppressWarnings("rawtypes") protected KylinConfigBase(Properties props, boolean force, IExternalConfigLoader configLoader) { if (props instanceof PropertiesDelegate) { this.properties = (PropertiesDelegate) props; @@ -220,12 +221,12 @@ public abstract class KylinConfigBase implements Serializable { * @return */ protected Properties getProperties(Collection<String> propertyKeys) { - final StrSubstitutor substitutor = getSubstitutor(); + val subStitutorTmp = getSubstitutor(); Properties result = new Properties(); for (Entry<Object, Object> entry : this.properties.entrySet()) { if (propertyKeys == null || propertyKeys.contains(entry.getKey())) { - result.put(entry.getKey(), substitutor.replace((String) entry.getValue())); + result.put(entry.getKey(), subStitutorTmp.replace((String) entry.getValue())); } } diff --git a/src/core-common/src/main/java/org/apache/kylin/common/KylinExternalConfigLoader.java b/src/core-common/src/main/java/org/apache/kylin/common/KylinExternalConfigLoader.java index d4fe301060..206539dd7a 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/KylinExternalConfigLoader.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/KylinExternalConfigLoader.java @@ -33,11 +33,11 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Map; +import java.util.Objects; import java.util.Properties; import javax.annotation.Nonnull; -import com.google.common.collect.Maps; import org.apache.kylin.common.exception.KylinException; import org.apache.kylin.common.util.OrderedProperties; import org.slf4j.Logger; @@ -45,6 +45,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; public class KylinExternalConfigLoader implements ICachedExternalConfigLoader { @@ -153,7 +154,7 @@ public class KylinExternalConfigLoader implements ICachedExternalConfigLoader { @Override public String getConfig() { StringWriter writer = new StringWriter(); - for (Map.Entry<String, String> entry: properties.entrySet()) { + for (Map.Entry<String, String> entry : properties.entrySet()) { writer.append(entry.getKey() + "=" + entry.getValue()).append("\n"); } return writer.toString(); @@ -161,7 +162,7 @@ public class KylinExternalConfigLoader implements ICachedExternalConfigLoader { @Override public String getProperty(String key) { - return properties.get(key); + return Objects.toString(properties.get(key), null); } /** @@ -176,7 +177,7 @@ public class KylinExternalConfigLoader implements ICachedExternalConfigLoader { } @Override - public ImmutableMap getPropertyEntries() { + public ImmutableMap<Object, Object> getPropertyEntries() { return propertyEntries; } } diff --git a/src/core-common/src/main/java/org/apache/kylin/common/PropertiesDelegate.java b/src/core-common/src/main/java/org/apache/kylin/common/PropertiesDelegate.java index 24f28a79cc..54dbf6d096 100644 --- a/src/core-common/src/main/java/org/apache/kylin/common/PropertiesDelegate.java +++ b/src/core-common/src/main/java/org/apache/kylin/common/PropertiesDelegate.java @@ -29,12 +29,13 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; -import io.kyligence.config.core.loader.IExternalConfigLoader; +import javax.validation.constraints.NotNull; + import org.apache.kylin.common.util.CompositeMapView; import com.google.common.collect.Maps; -import io.kyligence.config.external.loader.NacosExternalConfigLoader; +import io.kyligence.config.core.loader.IExternalConfigLoader; import lombok.EqualsAndHashCode; /** @@ -42,28 +43,28 @@ import lombok.EqualsAndHashCode; * A few functions of hashtable are disabled. * In the future, we should replace the java.util.Properties */ -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = false) +@SuppressWarnings("sync-override") public class PropertiesDelegate extends Properties { @EqualsAndHashCode.Include - private final ConcurrentMap<Object, Object> properties = Maps.newConcurrentMap(); + private final transient ConcurrentMap<Object, Object> properties = Maps.newConcurrentMap(); @EqualsAndHashCode.Include private final transient IExternalConfigLoader configLoader; - private final Map delegation; + private final transient Map<Object, Object> delegation; public PropertiesDelegate(Properties properties, IExternalConfigLoader configLoader) { this.properties.putAll(properties); this.configLoader = configLoader; if (configLoader == null) { this.delegation = this.properties; - } else if (configLoader instanceof KylinExternalConfigLoader) { - this.delegation = new CompositeMapView(((ICachedExternalConfigLoader)this.configLoader).getPropertyEntries(), this.properties); - } else if (configLoader instanceof NacosExternalConfigLoader) { - this.delegation = new CompositeMapView((this.configLoader).getProperties(), this.properties); + } else if (configLoader instanceof ICachedExternalConfigLoader) { + this.delegation = new CompositeMapView<>( + ((ICachedExternalConfigLoader) this.configLoader).getPropertyEntries(), this.properties); } else { - this.delegation = new CompositeMapView((this.configLoader).getProperties(), this.properties); + this.delegation = new CompositeMapView<>((this.configLoader).getProperties(), this.properties); } } @@ -110,7 +111,6 @@ public class PropertiesDelegate extends Properties { return delegation.size(); } - @Override public boolean isEmpty() { return delegation.isEmpty(); @@ -142,7 +142,7 @@ public class PropertiesDelegate extends Properties { } @Override - public void putAll(Map<?, ?> t) { + public void putAll(@NotNull Map<?, ?> t) { properties.putAll(t); } @@ -151,11 +151,6 @@ public class PropertiesDelegate extends Properties { properties.clear(); } - @Override - public Object clone() { - throw new UnsupportedOperationException(); - } - @Override public String toString() { throw new UnsupportedOperationException(); @@ -213,13 +208,12 @@ public class PropertiesDelegate extends Properties { } @Override - public synchronized Object compute(Object key, - BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { + public Object compute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { throw new UnsupportedOperationException(); } @Override - public synchronized Object merge(Object key, Object value, + public Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) { throw new UnsupportedOperationException(); } diff --git a/src/core-common/src/test/java/org/apache/kylin/common/KylinConfigBaseTest.java b/src/core-common/src/test/java/org/apache/kylin/common/KylinConfigBaseTest.java index 903fb8f6a0..3630c7bbd1 100644 --- a/src/core-common/src/test/java/org/apache/kylin/common/KylinConfigBaseTest.java +++ b/src/core-common/src/test/java/org/apache/kylin/common/KylinConfigBaseTest.java @@ -1371,6 +1371,14 @@ class KylinConfigBaseTest { config.setProperty("kylin.server.leader-race.heart-beat-timeout-rate", "1"); Assertions.assertEquals(1.0, config.getEpochRenewTimeoutRate()); } + + @Test + void testGetSubstitutor() { + KylinConfig config = KylinConfig.getInstanceFromEnv(); + val sub1 = config.getSubstitutor(); + val sub2 = config.getSubstitutor(); + Assertions.assertSame(sub1, sub2); + } } class EnvironmentUpdateUtils { diff --git a/src/core-common/src/test/java/org/apache/kylin/common/PropertiesDelegateTest.java b/src/core-common/src/test/java/org/apache/kylin/common/PropertiesDelegateTest.java index bea2ab9321..f515659fd2 100644 --- a/src/core-common/src/test/java/org/apache/kylin/common/PropertiesDelegateTest.java +++ b/src/core-common/src/test/java/org/apache/kylin/common/PropertiesDelegateTest.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; @@ -30,6 +31,11 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import lombok.val; + class PropertiesDelegateTest { private PropertiesDelegate delegate; @@ -83,6 +89,19 @@ class PropertiesDelegateTest { Assertions.assertEquals("update_v2", delegate.getProperty("key_in_external")); } + @Test + void testPutAll() { + val originSize = delegate.size(); + val map1 = Maps.<String, String> newHashMap(); + map1.put("k1", "v1"); + map1.put("k2", "v2"); + map1.put("k3", "v3"); + delegate.putAll(map1); + Assertions.assertEquals(originSize + map1.size(), delegate.size()); + + Assertions.assertEquals("v1", delegate.getProperty("k1")); + } + @Test void testSetProperty() { delegate.setProperty("key_in_prop", "update_v0"); @@ -95,6 +114,17 @@ class PropertiesDelegateTest { Assertions.assertEquals("update_v2", delegate.getProperty("key_in_external")); } + @Test + void testSize() { + Assertions.assertEquals(3, delegate.size()); + } + + @Test + void testEntrySet() { + Set<Map.Entry<Object, Object>> entries = delegate.entrySet(); + Assertions.assertEquals(3, entries.size()); + } + @Test void testKeys() { List<String> keys = new ArrayList<>(); @@ -135,4 +165,90 @@ class PropertiesDelegateTest { sets.add(properties); Assertions.assertEquals(4, sets.size()); } + + @Test + void testContainsKey() { + Assertions.assertTrue(delegate.containsKey("key_in_prop")); + Assertions.assertTrue(delegate.containsKey("key_override_external")); + Assertions.assertTrue(delegate.containsKey("key_in_external")); + + Assertions.assertFalse(delegate.containsKey("not_key")); + } + + @Test + void testContainsValue() { + Assertions.assertTrue(delegate.containsValue("v0")); + Assertions.assertTrue(delegate.containsValue("v11")); + Assertions.assertTrue(delegate.containsValue("v2")); + + Assertions.assertFalse(delegate.containsValue("not_value")); + } + + @Test + void testIsEmpty() { + Assertions.assertFalse(delegate.isEmpty()); + + val emptyDelegate = new PropertiesDelegate(new Properties(), null); + Assertions.assertTrue(emptyDelegate.isEmpty()); + } + + @Test + void testClear() { + Assertions.assertEquals(3, delegate.size()); + delegate.clear(); + Assertions.assertEquals(2, delegate.size()); + } + + @Test + void testConstruct() { + Properties properties = new Properties(); + properties.put("key_in_prop", "v0"); + { + val p = new PropertiesDelegate(properties, null); + Assertions.assertEquals(1, p.size()); + } + + { + TestExternalConfigLoader testExternalConfigLoader = new TestExternalConfigLoader(properties); + val p = new PropertiesDelegate(new Properties(), testExternalConfigLoader); + Assertions.assertEquals(1, p.size()); + } + + { + ICachedExternalConfigLoader iCachedExternalConfigLoader = new ICachedExternalConfigLoader() { + @Override + public ImmutableMap<Object, Object> getPropertyEntries() { + return ImmutableMap.of("key_in_prop", "v0"); + } + + @Override + public String getConfig() { + return null; + } + + @Override + public String getProperty(String s) { + return null; + } + }; + val p = new PropertiesDelegate(new Properties(), iCachedExternalConfigLoader); + Assertions.assertEquals(1, p.size()); + } + + } + + @Test + void testNotSupport() { + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.remove("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, delegate::toString); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.forEach((k, v) -> { + })); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.replace("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.replace("a", "b", "b2")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.computeIfAbsent("a", (k) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, + () -> delegate.computeIfPresent("a", (k, v) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.compute("a", (k, v) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> delegate.merge("a", "b", (k, v) -> "")); + } } diff --git a/src/core-common/src/test/java/org/apache/kylin/common/util/CompositeMapViewTest.java b/src/core-common/src/test/java/org/apache/kylin/common/util/CompositeMapViewTest.java new file mode 100644 index 0000000000..f3623fe996 --- /dev/null +++ b/src/core-common/src/test/java/org/apache/kylin/common/util/CompositeMapViewTest.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.kylin.common.util; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import lombok.val; + +class CompositeMapViewTest { + + private CompositeMapView<String, String> compositeMapView; + + @BeforeEach + void setup() { + compositeMapView = prepareData(); + } + + private CompositeMapView<String, String> prepareData() { + val map1 = Maps.<String, String> newHashMap(); + map1.put("k1", "v1"); + map1.put("k2", "v2"); + map1.put("k3", "v3"); + + val map2 = Maps.<String, String> newHashMap(); + map2.put("k1", "vv1"); + map2.put("kk2", "vv2"); + map2.put("kk3", "v3"); + return new CompositeMapView<>(map1, map2); + } + + @Test + void testSize() { + Assertions.assertEquals(5, compositeMapView.size()); + } + + @Test + void testIsEmpty() { + { + Assertions.assertFalse(compositeMapView.isEmpty()); + } + + { + CompositeMapView<String, String> compositeMapView = new CompositeMapView<>(Maps.newHashMap(), + Maps.newHashMap()); + Assertions.assertTrue(compositeMapView.isEmpty()); + } + } + + @Test + void testIsEmpty_Null() { + val emptyMap = Collections.emptyMap(); + Assertions.assertThrows(NullPointerException.class, () -> new CompositeMapView<>(null, null)); + + Assertions.assertThrows(NullPointerException.class, () -> new CompositeMapView<>(emptyMap, null)); + + Assertions.assertThrows(NullPointerException.class, () -> new CompositeMapView<>(null, emptyMap)); + } + + @Test + void testContainsKey() { + + Assertions.assertTrue(compositeMapView.containsKey("k1")); + Assertions.assertTrue(compositeMapView.containsKey("kk3")); + Assertions.assertTrue(compositeMapView.containsKey("k2")); + + Assertions.assertFalse(compositeMapView.containsKey("noKey")); + } + + @Test + void testContainsValue() { + + Assertions.assertTrue(compositeMapView.containsValue("v1")); + Assertions.assertTrue(compositeMapView.containsValue("vv2")); + Assertions.assertTrue(compositeMapView.containsValue("v2")); + + Assertions.assertFalse(compositeMapView.containsValue("noValue")); + } + + @Test + void testGetKey() { + + //both + Assertions.assertEquals("vv1", compositeMapView.get("k1")); + //left only + Assertions.assertEquals("v2", compositeMapView.get("k2")); + //right only + Assertions.assertEquals("v3", compositeMapView.get("kk3")); + + Assertions.assertNull(compositeMapView.get("notKey")); + } + + @Test + void testKeySet() { + + val expectedKeySet = Sets.newHashSet(Arrays.asList("k1", "k2", "k3", "kk2", "kk3")); + Assertions.assertEquals(expectedKeySet, compositeMapView.keySet()); + } + + @Test + void testValues() { + + val expectedValueSet = Sets.newHashSet(Arrays.asList("v1", "v2", "v3", "vv1", "vv2", "v3")); + Assertions.assertTrue(expectedValueSet.containsAll(compositeMapView.values())); + Assertions.assertEquals(expectedValueSet.size(), compositeMapView.values().size()); + } + + @Test + void testEntrySet() { + + val entryList = compositeMapView.entrySet().stream().sorted(Map.Entry.comparingByKey(String::compareTo)) + .map(e -> e.getKey() + "," + e.getValue()).collect(Collectors.toList()); + val expectedEntryList = Arrays.asList("k1,vv1", "k2,v2", "k3,v3", "kk2,vv2", "kk3,v3"); + + Assertions.assertEquals(expectedEntryList, entryList); + } + + @Test + void testNotSupport() { + + val emptyMap = Collections.emptyMap(); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.put("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.putIfAbsent("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.remove("a")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.remove("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.putAll(emptyMap)); + Assertions.assertThrows(UnsupportedOperationException.class, compositeMapView::clear); + Assertions.assertThrows(UnsupportedOperationException.class, compositeMapView::toString); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.forEach((k, v) -> { + })); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.replaceAll((k, v) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.replace("a", "b")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.replace("a", "b", "b2")); + Assertions.assertThrows(UnsupportedOperationException.class, + () -> compositeMapView.computeIfAbsent("a", (k) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, + () -> compositeMapView.computeIfPresent("a", (k, v) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, () -> compositeMapView.compute("a", (k, v) -> "")); + Assertions.assertThrows(UnsupportedOperationException.class, + () -> compositeMapView.merge("a", "b", (k, v) -> "")); + + } +}