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 2021/11/25 06:20:28 UTC

[dubbo] 42/45: fix concurrent modification, copy on context switch

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

liujun pushed a commit to branch release/3.0.14-rpccontext-bugfix
in repository https://gitbox.apache.org/repos/asf/dubbo.git

commit d91e414f2232ada40b17566810e4719a623c39a0
Author: ken.lj <ke...@gmail.com>
AuthorDate: Mon Nov 22 22:27:10 2021 +0800

    fix concurrent modification, copy on context switch
---
 .../main/java/org/apache/dubbo/rpc/RpcContext.java | 34 +++++++++++++++++++---
 .../org/apache/dubbo/rpc/filter/ContextFilter.java | 24 +++++++++++++--
 2 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
index 66ac06f..eab2a54 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java
@@ -71,8 +71,8 @@ public class RpcContext {
         }
     };
 
-    protected final Map<String, Object> attachments = new HashMap<>();
-    private final Map<String, Object> values = new HashMap<String, Object>();
+    protected Map<String, Object> attachments = new HashMap<>();
+    private Map<String, Object> values = new HashMap<String, Object>();
 
     private List<URL> urls;
 
@@ -109,6 +109,32 @@ public class RpcContext {
     protected RpcContext() {
     }
 
+    protected RpcContext(RpcContext context) {
+        if (context.attachments != null) {
+            this.attachments = new HashMap(context.attachments);
+        }
+        if (context.values != null) {
+            this.values = new HashMap(context.values);
+        }
+        if (context.urls != null) {
+            this.urls = new ArrayList<>(context.urls);
+        }
+        this.url = context.url;
+        this.methodName = context.methodName;
+        this.parameterTypes = context.parameterTypes;
+        this.arguments = context.arguments;
+        this.localAddress = context.localAddress;
+        this.remoteAddress = context.remoteAddress;
+        this.remoteApplicationName = context.remoteApplicationName;
+        this.invokers = context.invokers;
+        this.invoker = context.invoker;
+        this.invocation = context.invocation;
+        this.request = context.request;
+        this.response = context.response;
+        this.asyncContext = context.asyncContext;
+        this.remove = context.remove;
+    }
+
     /**
      * get server side context.
      *
@@ -119,7 +145,7 @@ public class RpcContext {
     }
 
     public static void restoreServerContext(RpcContext oldServerContext) {
-        SERVER_LOCAL.set(oldServerContext);
+        SERVER_LOCAL.set(new RpcContext(oldServerContext));
     }
 
     /**
@@ -149,7 +175,7 @@ public class RpcContext {
     }
 
     public static void restoreContext(RpcContext oldContext) {
-        LOCAL.set(oldContext);
+        LOCAL.set(new RpcContext(oldContext));
     }
 
     /**
diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java
index 291601a..d165558 100644
--- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java
+++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java
@@ -17,6 +17,8 @@
 package org.apache.dubbo.rpc.filter;
 
 import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.rpc.Filter;
 import org.apache.dubbo.rpc.Invocation;
@@ -28,11 +30,17 @@ import org.apache.dubbo.rpc.RpcInvocation;
 import org.apache.dubbo.rpc.TimeoutCountDown;
 import org.apache.dubbo.rpc.support.RpcUtils;
 
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
 import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
@@ -57,7 +65,7 @@ import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
  */
 @Activate(group = PROVIDER, order = -10000)
 public class ContextFilter implements Filter, Filter.Listener {
-
+    private static final Logger logger = LoggerFactory.getLogger(ContextFilter.class);
     private static final String TAG_KEY = "dubbo.tag";
 
     private static final Set<String> UNLOADING_KEYS;
@@ -138,7 +146,19 @@ public class ContextFilter implements Filter, Filter.Listener {
     @Override
     public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
         // pass attachments to result
-        appResponse.addObjectAttachments(RpcContext.getServerContext().getObjectAttachments());
+        Map<String, Object> attachments = RpcContext.getServerContext().getObjectAttachments();
+        try {
+            appResponse.addObjectAttachments(attachments);
+        } catch (ConcurrentModificationException e) {
+            logger.error(Thread.currentThread().getName() + "  " + attachments);
+            ThreadMXBean bean = ManagementFactory.getThreadMXBean();
+            ThreadInfo[] infos = bean.dumpAllThreads(true, true);
+            logger.error(Arrays.stream(infos).map(Object::toString)
+                    .collect(Collectors.joining()));
+
+            logger.error(e);
+            throw e;
+        }
     }
 
     @Override