You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2022/06/13 06:23:34 UTC

[dubbo] branch 3.0 updated: [3.0] Improve compressed URL param performance (#10125)

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 67e36cdd27 [3.0] Improve compressed URL param performance (#10125)
67e36cdd27 is described below

commit 67e36cdd27b9ae988c1d0d50a459545be07387b1
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Mon Jun 13 14:23:27 2022 +0800

    [3.0] Improve compressed URL param performance (#10125)
---
 .../dubbo/common/url/component/URLParam.java       | 211 +++++++--------------
 .../dubbo/common/url/component/URLPlainParam.java  |   6 +-
 .../url/component/param/DynamicParamTable.java     |  77 +++++---
 .../common/url/component/param/DynamicValues.java  |  28 ++-
 .../url/component/param/FixedParamValue.java       |   9 +-
 .../common/url/component/param/ParamValue.java     |  11 +-
 6 files changed, 136 insertions(+), 206 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
index 01434ac8e4..05deabe572 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLParam.java
@@ -49,10 +49,11 @@ import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
  * <br/>
  * URLParam should operate as Copy-On-Write, each modify actions will return a new Object
  * <br/>
- *
+ * <p>
  * NOTE: URLParam is not support serialization! {@link DynamicParamTable} is related with
  * current running environment. If you want to make URL as a parameter, please call
  * {@link URL#toSerializableURL()} to create {@link URLPlainParam} instead.
+ *
  * @since 3.0
  */
 public class URLParam {
@@ -77,14 +78,9 @@ public class URLParam {
     private final BitSet KEY;
 
     /**
-     * using bit to save if value is default value (reduce VALUE size)
-     */
-    private final BitSet DEFAULT_KEY;
-
-    /**
-     * a compressed (those key not exist or value is default value are bring removed in this array) array which contains value-offset
+     * an array which contains value-offset
      */
-    private final Integer[] VALUE;
+    private final int[] VALUE;
 
     /**
      * store extra parameters which key not match in {@link DynamicParamTable}
@@ -115,7 +111,6 @@ public class URLParam {
     protected URLParam() {
         this.rawParam = null;
         this.KEY = null;
-        this.DEFAULT_KEY = null;
         this.VALUE = null;
         this.EXTRA_PARAMS = null;
         this.METHOD_PARAMETERS = null;
@@ -124,18 +119,14 @@ public class URLParam {
 
     protected URLParam(BitSet key, Map<Integer, Integer> value, Map<String, String> extraParams, Map<String, Map<String, String>> methodParameters, String rawParam) {
         this.KEY = key;
-        this.DEFAULT_KEY = new BitSet(KEY.size());
-        this.VALUE = new Integer[value.size()];
-
-        // compress VALUE
+        this.VALUE = new int[value.size()];
         for (int i = key.nextSetBit(0), offset = 0; i >= 0; i = key.nextSetBit(i + 1)) {
             if (value.containsKey(i)) {
                 VALUE[offset++] = value.get(i);
             } else {
-                DEFAULT_KEY.set(i);
+                throw new IllegalArgumentException();
             }
         }
-
         this.EXTRA_PARAMS = Collections.unmodifiableMap((extraParams == null ? new HashMap<>() : new HashMap<>(extraParams)));
         this.METHOD_PARAMETERS = Collections.unmodifiableMap((methodParameters == null) ? Collections.emptyMap() : new LinkedHashMap<>(methodParameters));
         this.rawParam = rawParam;
@@ -144,16 +135,12 @@ public class URLParam {
         this.enableCompressed = true;
     }
 
-    protected URLParam(BitSet key, BitSet defaultKey, Integer[] value, Map<String, String> extraParams, Map<String, Map<String, String>> methodParameters, String rawParam) {
+    protected URLParam(BitSet key, int[] value, Map<String, String> extraParams, Map<String, Map<String, String>> methodParameters, String rawParam) {
         this.KEY = key;
-        this.DEFAULT_KEY = defaultKey;
-
         this.VALUE = value;
-
         this.EXTRA_PARAMS = Collections.unmodifiableMap((extraParams == null ? new HashMap<>() : new HashMap<>(extraParams)));
         this.METHOD_PARAMETERS = Collections.unmodifiableMap((methodParameters == null) ? Collections.emptyMap() : new LinkedHashMap<>(methodParameters));
         this.rawParam = rawParam;
-
         this.timestamp = System.currentTimeMillis();
         this.enableCompressed = true;
     }
@@ -387,12 +374,8 @@ public class URLParam {
             Set<String> set = new LinkedHashSet<>((int) ((urlParam.VALUE.length + urlParam.EXTRA_PARAMS.size()) / 0.75) + 1);
             for (int i = urlParam.KEY.nextSetBit(0); i >= 0; i = urlParam.KEY.nextSetBit(i + 1)) {
                 String value;
-                if (urlParam.DEFAULT_KEY.get(i)) {
-                    value = DynamicParamTable.getDefaultValue(i);
-                } else {
-                    Integer offset = urlParam.keyIndexToOffset(i);
-                    value = DynamicParamTable.getValue(i, offset);
-                }
+                int offset = urlParam.keyIndexToOffset(i);
+                value = DynamicParamTable.getValue(i, offset);
                 set.add(value);
             }
 
@@ -407,12 +390,8 @@ public class URLParam {
             Set<Entry<String, String>> set = new LinkedHashSet<>((int) ((urlParam.KEY.cardinality() + urlParam.EXTRA_PARAMS.size()) / 0.75) + 1);
             for (int i = urlParam.KEY.nextSetBit(0); i >= 0; i = urlParam.KEY.nextSetBit(i + 1)) {
                 String value;
-                if (urlParam.DEFAULT_KEY.get(i)) {
-                    value = DynamicParamTable.getDefaultValue(i);
-                } else {
-                    Integer offset = urlParam.keyIndexToOffset(i);
-                    value = DynamicParamTable.getValue(i, offset);
-                }
+                int offset = urlParam.keyIndexToOffset(i);
+                value = DynamicParamTable.getValue(i, offset);
                 set.add(new Node(DynamicParamTable.getKey(i), value));
             }
 
@@ -561,8 +540,7 @@ public class URLParam {
     private URLParam doAddParameters(Map<String, String> parameters, boolean skipIfPresent) {
         // lazy init, null if no modify
         BitSet newKey = null;
-        BitSet defaultKey = null;
-        Integer[] newValueArray = null;
+        int[] newValueArray = null;
         Map<Integer, Integer> newValueMap = null;
         Map<String, String> newExtraParams = null;
         Map<String, Map<String, String>> newMethodParams = null;
@@ -573,8 +551,8 @@ public class URLParam {
             if (entry.getKey() == null || entry.getValue() == null) {
                 continue;
             }
-            Integer keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, entry.getKey());
-            if (keyIndex == null) {
+            int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, entry.getKey());
+            if (keyIndex < 0) {
                 // entry key is not present in DynamicParamTable, add it to EXTRA_PARAMS
                 if (newExtraParams == null) {
                     newExtraParams = new HashMap<>(EXTRA_PARAMS);
@@ -594,29 +572,11 @@ public class URLParam {
                     if (parameters.size() > ADD_PARAMETER_ON_MOVE_THRESHOLD) {
                         // recover VALUE back to Map, use map to replace key pair
                         if (newValueMap == null) {
-                            newValueMap = recoverCompressedValue();
+                            newValueMap = recoverValue();
                         }
                         newValueMap.put(keyIndex, DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
-                    } else if (!DynamicParamTable.isDefaultValue(entry.getKey(), entry.getValue())) {
-                        // new value is not the default key
-                        if (DEFAULT_KEY.get(keyIndex)) {
-                            // old value is the default value
-                            // value is default value, add to defaultKey directly
-                            if (defaultKey == null) {
-                                defaultKey = (BitSet) DEFAULT_KEY.clone();
-                            }
-                            defaultKey.set(keyIndex, false);
-                            newValueArray = addByMove(VALUE, keyIndexToCompressIndex(KEY, DEFAULT_KEY, keyIndex), DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
-                        } else {
-                            // old value is not the default key, replace offset in VALUE array
-                            newValueArray = replaceOffset(VALUE, keyIndexToCompressIndex(KEY, DEFAULT_KEY, keyIndex), DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
-                        }
                     } else {
-                        // value is default value, add to defaultKey directly
-                        if (defaultKey == null) {
-                            defaultKey = (BitSet) DEFAULT_KEY.clone();
-                        }
-                        defaultKey.set(keyIndex);
+                        newValueArray = replaceOffset(VALUE, keyIndexToIndex(KEY, keyIndex), DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
                     }
                 } else {
                     // key is absent, add it
@@ -628,18 +588,12 @@ public class URLParam {
                     if (parameters.size() > ADD_PARAMETER_ON_MOVE_THRESHOLD) {
                         // recover VALUE back to Map
                         if (newValueMap == null) {
-                            newValueMap = recoverCompressedValue();
+                            newValueMap = recoverValue();
                         }
                         newValueMap.put(keyIndex, DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
-                    } else if (!DynamicParamTable.isDefaultValue(entry.getKey(), entry.getValue())) {
-                        // add parameter by moving array, only support for adding once
-                        newValueArray = addByMove(VALUE, keyIndexToCompressIndex(newKey, DEFAULT_KEY, keyIndex), DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
                     } else {
-                        // value is default value, add to defaultKey directly
-                        if (defaultKey == null) {
-                            defaultKey = (BitSet) DEFAULT_KEY.clone();
-                        }
-                        defaultKey.set(keyIndex);
+                        // add parameter by moving array, only support for adding once
+                        newValueArray = addByMove(VALUE, keyIndexToIndex(newKey, keyIndex), DynamicParamTable.getValueIndex(entry.getKey(), entry.getValue()));
                     }
                 }
             }
@@ -647,9 +601,6 @@ public class URLParam {
         if (newKey == null) {
             newKey = KEY;
         }
-        if (defaultKey == null) {
-            defaultKey = DEFAULT_KEY;
-        }
         if (newValueArray == null && newValueMap == null) {
             newValueArray = VALUE;
         }
@@ -660,28 +611,26 @@ public class URLParam {
             newMethodParams = METHOD_PARAMETERS;
         }
         if (newValueMap == null) {
-            return new URLParam(newKey, defaultKey, newValueArray, newExtraParams, newMethodParams, null);
+            return new URLParam(newKey, newValueArray, newExtraParams, newMethodParams, null);
         } else {
             return new URLParam(newKey, newValueMap, newExtraParams, newMethodParams, null);
         }
     }
 
-    private Map<Integer, Integer> recoverCompressedValue() {
+    private Map<Integer, Integer> recoverValue() {
         Map<Integer, Integer> map = new HashMap<>((int) (KEY.size() / 0.75) + 1);
         for (int i = KEY.nextSetBit(0), offset = 0; i >= 0; i = KEY.nextSetBit(i + 1)) {
-            if (!DEFAULT_KEY.get(i)) {
-                map.put(i, VALUE[offset++]);
-            }
+            map.put(i, VALUE[offset++]);
         }
         return map;
     }
 
-    private Integer[] addByMove(Integer[] array, int index, Integer value) {
+    private int[] addByMove(int[] array, int index, Integer value) {
         if (index < 0 || index > array.length) {
             throw new IllegalArgumentException();
         }
         // copy-on-write
-        Integer[] result = new Integer[array.length + 1];
+        int[] result = new int[array.length + 1];
 
         System.arraycopy(array, 0, result, 0, index);
         result[index] = value;
@@ -690,12 +639,12 @@ public class URLParam {
         return result;
     }
 
-    private Integer[] replaceOffset(Integer[] array, int index, Integer value) {
+    private int[] replaceOffset(int[] array, int index, Integer value) {
         if (index < 0 || index > array.length) {
             throw new IllegalArgumentException();
         }
         // copy-on-write
-        Integer[] result = new Integer[array.length];
+        int[] result = new int[array.length];
 
         System.arraycopy(array, 0, result, 0, array.length);
         result[index] = value;
@@ -715,32 +664,23 @@ public class URLParam {
         }
         // lazy init, null if no modify
         BitSet newKey = null;
-        BitSet defaultKey = null;
-        Integer[] newValueArray = null;
+        int[] newValueArray = null;
         Map<String, String> newExtraParams = null;
         Map<String, Map<String, String>> newMethodParams = null;
         for (String key : keys) {
-            Integer keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
-            if (keyIndex != null && KEY.get(keyIndex)) {
+            int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
+            if (keyIndex >= 0 && KEY.get(keyIndex)) {
                 if (newKey == null) {
                     newKey = (BitSet) KEY.clone();
                 }
                 newKey.clear(keyIndex);
-                if (DEFAULT_KEY.get(keyIndex)) {
-                    // is default value, remove in DEFAULT_KEY
-                    if (defaultKey == null) {
-                        defaultKey = (BitSet) DEFAULT_KEY.clone();
-                    }
-                    defaultKey.clear(keyIndex);
-                } else {
-                    // which offset is in VALUE array, set value as -1, compress in the end
-                    if (newValueArray == null) {
-                        newValueArray = new Integer[VALUE.length];
-                        System.arraycopy(VALUE, 0, newValueArray, 0, VALUE.length);
-                    }
-                    // KEY is immutable
-                    newValueArray[keyIndexToCompressIndex(KEY, DEFAULT_KEY, keyIndex)] = -1;
+                // which offset is in VALUE array, set value as -1, compress in the end
+                if (newValueArray == null) {
+                    newValueArray = new int[VALUE.length];
+                    System.arraycopy(VALUE, 0, newValueArray, 0, VALUE.length);
                 }
+                // KEY is immutable
+                newValueArray[keyIndexToIndex(KEY, keyIndex)] = -1;
             }
             if (EXTRA_PARAMS.containsKey(key)) {
                 if (newExtraParams == null) {
@@ -764,9 +704,6 @@ public class URLParam {
         if (newKey == null) {
             newKey = KEY;
         }
-        if (defaultKey == null) {
-            defaultKey = DEFAULT_KEY;
-        }
         if (newValueArray == null) {
             newValueArray = VALUE;
         } else {
@@ -783,11 +720,11 @@ public class URLParam {
             // empty, directly return cache
             return EMPTY_PARAM;
         } else {
-            return new URLParam(newKey, defaultKey, newValueArray, newExtraParams, newMethodParams, null);
+            return new URLParam(newKey, newValueArray, newExtraParams, newMethodParams, null);
         }
     }
 
-    private Integer[] compressArray(Integer[] array) {
+    private int[] compressArray(int[] array) {
         int total = 0;
         for (int i : array) {
             if (i > -1) {
@@ -795,10 +732,10 @@ public class URLParam {
             }
         }
         if (total == 0) {
-            return new Integer[0];
+            return new int[0];
         }
 
-        Integer[] result = new Integer[total];
+        int[] result = new int[total];
         for (int i = 0, offset = 0; i < array.length; i++) {
             // skip if value if less than 0
             if (array[i] > -1) {
@@ -824,8 +761,8 @@ public class URLParam {
      * @return present or not
      */
     public boolean hasParameter(String key) {
-        Integer keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
-        if (keyIndex == null) {
+        int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
+        if (keyIndex < 0) {
             return EXTRA_PARAMS.containsKey(key);
         }
         return KEY.get(keyIndex);
@@ -838,47 +775,34 @@ public class URLParam {
      * @return value, null if key is absent
      */
     public String getParameter(String key) {
-        Integer keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
-        if (keyIndex == null) {
-            if (EXTRA_PARAMS.containsKey(key)) {
-                return EXTRA_PARAMS.get(key);
-            }
-            return null;
+        int keyIndex = DynamicParamTable.getKeyIndex(enableCompressed, key);
+        if (keyIndex < 0) {
+            return EXTRA_PARAMS.get(key);
         }
         if (KEY.get(keyIndex)) {
             String value;
-            if (DEFAULT_KEY.get(keyIndex)) {
-                value = DynamicParamTable.getDefaultValue(keyIndex);
-            } else {
-                Integer offset = keyIndexToOffset(keyIndex);
-                value = DynamicParamTable.getValue(keyIndex, offset);
-            }
-            if (StringUtils.isEmpty(value)) {
-                // Forward compatible, make sure key dynamic increment can work.
-                // In that case, some values which are proceed before increment will set in EXTRA_PARAMS.
-                return EXTRA_PARAMS.get(key);
-            } else {
-                return value;
-            }
+            int offset = keyIndexToOffset(keyIndex);
+            value = DynamicParamTable.getValue(keyIndex, offset);
+
+            return value;
+//            if (StringUtils.isEmpty(value)) {
+//                // Forward compatible, make sure key dynamic increment can work.
+//                // In that case, some values which are proceed before increment will set in EXTRA_PARAMS.
+//                return EXTRA_PARAMS.get(key);
+//            } else {
+//                return value;
+//            }
         }
         return null;
     }
 
 
-    private int keyIndexToCompressIndex(BitSet key, BitSet defaultKey, int keyIndex) {
-        int index = 0;
-        for (int i = 0; i < keyIndex; i++) {
-            if (key.get(i)) {
-                if (!defaultKey.get(i)) {
-                    index++;
-                }
-            }
-        }
-        return index;
+    private int keyIndexToIndex(BitSet key, int keyIndex) {
+        return key.get(0, keyIndex).cardinality();
     }
 
-    private Integer keyIndexToOffset(int keyIndex) {
-        int arrayOffset = keyIndexToCompressIndex(KEY, DEFAULT_KEY, keyIndex);
+    private int keyIndexToOffset(int keyIndex) {
+        int arrayOffset = keyIndexToIndex(KEY, keyIndex);
         return VALUE[arrayOffset];
     }
 
@@ -919,8 +843,7 @@ public class URLParam {
         URLParam urlParam = (URLParam) o;
 
         if (Objects.equals(KEY, urlParam.KEY)
-                && Objects.equals(DEFAULT_KEY, urlParam.DEFAULT_KEY)
-                && Arrays.equals(VALUE, urlParam.VALUE)) {
+            && Arrays.equals(VALUE, urlParam.VALUE)) {
             if (CollectionUtils.isNotEmptyMap(EXTRA_PARAMS)) {
                 if (CollectionUtils.isEmptyMap(urlParam.EXTRA_PARAMS) || EXTRA_PARAMS.size() != urlParam.EXTRA_PARAMS.size()) {
                     return false;
@@ -954,7 +877,6 @@ public class URLParam {
                 hashCodeCache = hashCodeCache * 31 + value;
             }
             hashCodeCache = hashCodeCache * 31 + ((KEY == null) ? 0 : KEY.hashCode());
-            hashCodeCache = hashCodeCache * 31 + ((DEFAULT_KEY == null) ? 0 : DEFAULT_KEY.hashCode());
         }
         return hashCodeCache;
     }
@@ -971,8 +893,7 @@ public class URLParam {
         StringJoiner stringJoiner = new StringJoiner("&");
         for (int i = KEY.nextSetBit(0); i >= 0; i = KEY.nextSetBit(i + 1)) {
             String key = DynamicParamTable.getKey(i);
-            String value = DEFAULT_KEY.get(i) ?
-                    DynamicParamTable.getDefaultValue(i) : DynamicParamTable.getValue(i, keyIndexToOffset(i));
+            String value = DynamicParamTable.getValue(i, keyIndexToOffset(i));
             value = value == null ? "" : value.trim();
             stringJoiner.add(String.format("%s=%s", key, value));
         }
@@ -1083,9 +1004,9 @@ public class URLParam {
 
     private static void addParameter(BitSet keyBit, Map<Integer, Integer> valueMap, Map<String, String> extraParam,
                                      Map<String, Map<String, String>> methodParameters, String key, String value, boolean skipIfPresent) {
-        Integer keyIndex = DynamicParamTable.getKeyIndex(true, key);
+        int keyIndex = DynamicParamTable.getKeyIndex(true, key);
         if (skipIfPresent) {
-            if (keyIndex == null) {
+            if (keyIndex < 0) {
                 if (extraParam.containsKey(key)) {
                     return;
                 }
@@ -1096,7 +1017,7 @@ public class URLParam {
             }
         }
 
-        if (keyIndex == null) {
+        if (keyIndex < 0) {
             extraParam.put(key, value);
             String[] methodSplit = key.split("\\.", 2);
             if (methodSplit.length == 2) {
@@ -1104,9 +1025,7 @@ public class URLParam {
                 methodMap.put(methodSplit[0], value);
             }
         } else {
-            if (!DynamicParamTable.isDefaultValue(key, value)) {
-                valueMap.put(keyIndex, DynamicParamTable.getValueIndex(key, value));
-            }
+            valueMap.put(keyIndex, DynamicParamTable.getValueIndex(key, value));
             keyBit.set(keyIndex);
         }
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLPlainParam.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLPlainParam.java
index 011fe2c7bd..b4fc76e10c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLPlainParam.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/URLPlainParam.java
@@ -31,14 +31,14 @@ public class URLPlainParam extends URLParam implements Serializable {
 
     private static final long serialVersionUID = 4722019979665434393L;
 
-    protected URLPlainParam(BitSet key, BitSet defaultKey, Integer[] value, Map<String, String> extraParams, Map<String, Map<String, String>> methodParameters, String rawParam) {
-        super(key, defaultKey, value, extraParams, methodParameters, rawParam);
+    protected URLPlainParam(BitSet key, int[] value, Map<String, String> extraParams, Map<String, Map<String, String>> methodParameters, String rawParam) {
+        super(key, value, extraParams, methodParameters, rawParam);
         this.enableCompressed = false;
     }
 
     public static URLPlainParam toURLPlainParam(URLParam urlParam) {
         Map<String, String> params = Collections.unmodifiableMap(new HashMap<>(urlParam.getParameters()));
-        return new URLPlainParam(new BitSet(), new BitSet(), new Integer[0], params, urlParam.getMethodParameters(), urlParam.getRawParam());
+        return new URLPlainParam(new BitSet(), new int[0], params, urlParam.getMethodParameters(), urlParam.getRawParam());
     }
 
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamTable.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamTable.java
index 7abac950aa..a86919ff94 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamTable.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicParamTable.java
@@ -18,20 +18,28 @@ package org.apache.dubbo.common.url.component.param;
 
 import org.apache.dubbo.common.extension.ExtensionLoader;
 
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.TreeMap;
 
 /**
  * Global Param Cache Table
  * Not support method parameters
  */
 public final class DynamicParamTable {
-    private static final List<String> KEYS = new CopyOnWriteArrayList<>();
-    private static final List<ParamValue> VALUES = new CopyOnWriteArrayList<>();
+    /**
+     * Keys array, value is key's identity hashcode ( assume key is in constant pool )
+     */
+    private static int[] KEYS;
+    /**
+     * Keys array, value is string
+     */
+    private static String[] ORIGIN_KEYS;
+    private static ParamValue[] VALUES;
     private static final Map<String, Integer> KEY2INDEX = new HashMap<>(64);
 
     private DynamicParamTable() {
@@ -42,36 +50,36 @@ public final class DynamicParamTable {
         init();
     }
 
-    public static Integer getKeyIndex(boolean enabled, String key) {
+    public static int getKeyIndex(boolean enabled, String key) {
         if (!enabled) {
-            return null;
+            return -1;
         }
-        return KEY2INDEX.get(key);
+        // assume key is in constant pool
+        int identityHashCode = System.identityHashCode(key);
+        int index = Arrays.binarySearch(KEYS, identityHashCode);
+        if (index >= 0) {
+            return index;
+        }
+        // fallback to key2index map
+        Integer indexFromMap = KEY2INDEX.get(key);
+        return indexFromMap == null ? -1 : indexFromMap;
     }
 
-    public static Integer getValueIndex(String key, String value) {
-        Integer idx = getKeyIndex(true, key);
-        if (idx == null) {
+    public static int getValueIndex(String key, String value) {
+        int idx = getKeyIndex(true, key);
+        if (idx < 0) {
             throw new IllegalArgumentException("Cannot found key in url param:" + key);
         }
-        ParamValue paramValue = VALUES.get(idx);
+        ParamValue paramValue = VALUES[idx];
         return paramValue.getIndex(value);
     }
 
     public static String getKey(int offset) {
-        return KEYS.get(offset);
-    }
-
-    public static boolean isDefaultValue(String key, String value) {
-        return Objects.equals(value, VALUES.get(getKeyIndex(true, key)).defaultVal());
-    }
-
-    public static String getValue(int vi, Integer offset) {
-        return VALUES.get(vi).getN(offset);
+        return ORIGIN_KEYS[offset];
     }
 
-    public static String getDefaultValue(int vi) {
-        return VALUES.get(vi).defaultVal();
+    public static String getValue(int vi, int offset) {
+        return VALUES[vi].getN(offset);
     }
 
     private static void init() {
@@ -82,19 +90,26 @@ public final class DynamicParamTable {
         values.add(new DynamicValues(null));
 
         ExtensionLoader.getExtensionLoader(DynamicParamSource.class)
-                .getSupportedExtensionInstances().forEach(source -> source.init(keys, values));
+            .getSupportedExtensionInstances().forEach(source -> source.init(keys, values));
 
+        TreeMap<String, ParamValue> resultMap = new TreeMap<>(Comparator.comparingInt(System::identityHashCode));
         for (int i = 0; i < keys.size(); i++) {
-            if (!KEYS.contains(keys.get(i))) {
-                KEYS.add(keys.get(i));
-                VALUES.add(values.get(i));
-            }
+            resultMap.put(keys.get(i), values.get(i));
         }
 
-        for (int i = 0; i < KEYS.size(); i++) {
-            if (!KEYS.get(i).isEmpty()) {
-                key2Index.put(KEYS.get(i), i);
-            }
+        // assume key is in constant pool, store identity hashCode as index
+        KEYS = resultMap.keySet()
+            .stream()
+            .map(System::identityHashCode)
+            .mapToInt(x -> x)
+            .toArray();
+
+        ORIGIN_KEYS = resultMap.keySet().toArray(new String[0]);
+
+        VALUES = resultMap.values().toArray(new ParamValue[0]);
+
+        for (int i = 0; i < ORIGIN_KEYS.length; i++) {
+            key2Index.put(ORIGIN_KEYS[i], i);
         }
         KEY2INDEX.putAll(key2Index);
     }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicValues.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicValues.java
index 6b025e9d29..2d710dd6e2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicValues.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/DynamicValues.java
@@ -20,7 +20,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 public class DynamicValues implements ParamValue {
-    private final Map<Integer, String> index2Value = new ConcurrentHashMap<>();
+    private volatile String[] index2Value = new String[1];
     private final Map<String, Integer> value2Index = new ConcurrentHashMap<>();
     private int indexSeq = 0;
 
@@ -40,8 +40,15 @@ public class DynamicValues implements ParamValue {
             synchronized (this) {
                 // thread safe
                 if (!value2Index.containsKey(value)) {
+                    if (indexSeq == Integer.MAX_VALUE) {
+                        throw new IllegalStateException("URL Param Cache is full.");
+                    }
+                    // copy on write, only support append now
+                    String[] newValues = new String[indexSeq + 1];
+                    System.arraycopy(index2Value, 0, newValues, 0, indexSeq);
+                    newValues[indexSeq] = value;
+                    index2Value = newValues;
                     value2Index.put(value, indexSeq);
-                    index2Value.put(indexSeq, value);
                     indexSeq += 1;
                 }
             }
@@ -50,21 +57,22 @@ public class DynamicValues implements ParamValue {
     }
 
     @Override
-    public String getN(Integer n) {
-        return index2Value.get(n);
+    public String getN(int n) {
+        if (n == -1) {
+            return null;
+        }
+        return index2Value[n];
     }
 
     @Override
-    public Integer getIndex(String value) {
+    public int getIndex(String value) {
+        if (value == null) {
+            return -1;
+        }
         Integer index = value2Index.get(value);
         if (index == null) {
             return add(value);
         }
         return index;
     }
-
-    @Override
-    public String defaultVal() {
-        return getN(0);
-    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/FixedParamValue.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/FixedParamValue.java
index d9a3bec900..6d6de7f459 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/FixedParamValue.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/FixedParamValue.java
@@ -48,12 +48,12 @@ public class FixedParamValue implements ParamValue {
      * @param n
      */
     @Override
-    public String getN(Integer n) {
+    public String getN(int n) {
         return values[n];
     }
 
     @Override
-    public Integer getIndex(String value) {
+    public int getIndex(String value) {
         Integer offset = val2Index.get(value.toLowerCase(Locale.ROOT));
         if (offset == null) {
             throw new IllegalArgumentException("unrecognized value " + value
@@ -62,9 +62,4 @@ public class FixedParamValue implements ParamValue {
         }
         return offset;
     }
-
-    @Override
-    public String defaultVal() {
-        return values[0];
-    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/ParamValue.java b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/ParamValue.java
index 54271cccf6..60c41e5e4a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/ParamValue.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/url/component/param/ParamValue.java
@@ -23,7 +23,7 @@ public interface ParamValue {
      * @param n the nth value
      * @return the value stored at index = n
      */
-    String getN(Integer n);
+    String getN(int n);
 
 
     /**
@@ -32,12 +32,5 @@ public interface ParamValue {
      * @param value the stored value
      * @return the index of value
      */
-    Integer getIndex(String value);
-
-    /**
-     * get default value
-     *
-     * @return the default value stored at index = 0
-     */
-    String defaultVal();
+    int getIndex(String value);
 }