You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ha...@apache.org on 2021/08/18 06:40:09 UTC

[hbase] branch branch-2 updated: HBASE-26087 JVM crash when displaying RPC params by MonitoredRPCHandler (#3489)

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

haxiaolin pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new 4ccd215  HBASE-26087 JVM crash when displaying RPC params by MonitoredRPCHandler (#3489)
4ccd215 is described below

commit 4ccd21535482c4812ffd30f08b01313b8efffca7
Author: Xiaolin Ha <ha...@apache.org>
AuthorDate: Wed Aug 18 13:28:46 2021 +0800

    HBASE-26087 JVM crash when displaying RPC params by MonitoredRPCHandler (#3489)
    
    Signed-off-by: stack <st...@apache.org>
---
 .../hbase/monitoring/MonitoredRPCHandlerImpl.java  | 16 ++++-
 .../hadoop/hbase/monitoring/TestTaskMonitor.java   | 71 +++++++++++++++++++++-
 2 files changed, 82 insertions(+), 5 deletions(-)

diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/monitoring/MonitoredRPCHandlerImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/monitoring/MonitoredRPCHandlerImpl.java
index 96fffa4..5c1b01c 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/monitoring/MonitoredRPCHandlerImpl.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/monitoring/MonitoredRPCHandlerImpl.java
@@ -22,10 +22,11 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.yetus.audience.InterfaceAudience;
 import org.apache.hadoop.hbase.client.Operation;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
+
+import org.apache.yetus.audience.InterfaceAudience;
 import org.apache.hbase.thirdparty.com.google.protobuf.Message;
 
 /**
@@ -43,6 +44,8 @@ public class MonitoredRPCHandlerImpl extends MonitoredTaskImpl
   private String methodName = "";
   private Object [] params = {};
   private Message packet;
+  private boolean snapshot = false;
+  private Map<String, Object> callInfoMap = new HashMap<>();
 
   public MonitoredRPCHandlerImpl() {
     super();
@@ -53,11 +56,14 @@ public class MonitoredRPCHandlerImpl extends MonitoredTaskImpl
 
   @Override
   public synchronized MonitoredRPCHandlerImpl clone() {
-    return (MonitoredRPCHandlerImpl) super.clone();
+    MonitoredRPCHandlerImpl clone = (MonitoredRPCHandlerImpl) super.clone();
+    clone.callInfoMap = generateCallInfoMap();
+    clone.snapshot = true;
+    return clone;
   }
 
   /**
-   * Gets the status of this handler; if it is currently servicing an RPC, 
+   * Gets the status of this handler; if it is currently servicing an RPC,
    * this status will include the RPC information.
    * @return a String describing the current status.
    */
@@ -233,6 +239,10 @@ public class MonitoredRPCHandlerImpl extends MonitoredTaskImpl
 
   @Override
   public synchronized Map<String, Object> toMap() {
+    return this.snapshot ? this.callInfoMap : generateCallInfoMap();
+  }
+
+  private Map<String, Object> generateCallInfoMap() {
     // only include RPC info if the Handler is actively servicing an RPC call
     Map<String, Object> map = super.toMap();
     if (getState() != State.RUNNING) {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/monitoring/TestTaskMonitor.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/monitoring/TestTaskMonitor.java
index 1145131..c9a9fc9 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/monitoring/TestTaskMonitor.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/monitoring/TestTaskMonitor.java
@@ -17,10 +17,13 @@
  */
 package org.apache.hadoop.hbase.monitoring;
 
-import static org.junit.Assert.*;
-
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseClassTestRule;
@@ -34,9 +37,12 @@ import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 @Category({MiscTests.class, SmallTests.class})
 public class TestTaskMonitor {
+  private static final Logger LOG = LoggerFactory.getLogger(TestTaskMonitor.class);
 
   @ClassRule
   public static final HBaseClassTestRule CLASS_RULE =
@@ -226,5 +232,66 @@ public class TestTaskMonitor {
     assertEquals("status3", task.getStatusJournal().get(1).getStatus());
     tm.shutdown();
   }
+
+  @Test
+  public void testClone() throws Exception {
+    MonitoredRPCHandlerImpl monitor = new MonitoredRPCHandlerImpl();
+    monitor.abort("abort RPC");
+    TestParam testParam = new TestParam("param1");
+    monitor.setRPC("method1", new Object[]{ testParam }, 0);
+    MonitoredRPCHandlerImpl clone = monitor.clone();
+    assertEquals(clone.getDescription(), monitor.getDescription());
+    assertEquals(clone.getState(), monitor.getState());
+    assertEquals(clone.getStatus(), monitor.getStatus());
+    assertEquals(clone.toString(), monitor.toString());
+    assertEquals(clone.toMap(), monitor.toMap());
+    assertEquals(clone.toJSON(), monitor.toJSON());
+
+    // mark complete and make param dirty
+    monitor.markComplete("complete RPC");
+    testParam.setParam("dirtyParam");
+    assertEquals(clone.getDescription(), monitor.getDescription());
+    assertNotEquals(clone.getState(), monitor.getState());
+    assertNotEquals(clone.getStatus(), monitor.getStatus());
+    monitor.setState(MonitoredTask.State.RUNNING);
+    try {
+      // when markComplete, the param in monitor is set null, so toMap should fail here
+      monitor.toMap();
+      fail("Should not call toMap successfully, because param=null");
+    } catch (Exception e) {
+    }
+    // the param of clone monitor should not be dirty
+    assertNotEquals("[dirtyString]",
+      String.valueOf(((Map<String, Object>) clone.toMap().get("rpcCall")).get("params")));
+
+    monitor.resume("resume");
+    monitor.setRPC("method2", new Object[]{new TestParam("param2")}, 1);
+    assertNotEquals(((Map<String, Object>) clone.toMap().get("rpcCall")).get("params"),
+      ((Map<String, Object>) monitor.toMap().get("rpcCall")).get(
+        "params"));
+    LOG.info(String.valueOf(clone.toMap()));
+    LOG.info(String.valueOf(monitor.toMap()));
+    assertNotEquals(clone.toString(), monitor.toString());
+    assertNotEquals(clone.getRPCQueueTime(), monitor.getRPCQueueTime());
+    assertNotEquals(clone.toMap(), monitor.toMap());
+    assertNotEquals(clone.toJSON(), monitor.toJSON());
+  }
+
+  private class TestParam {
+    public String param = null;
+
+    public TestParam(String param) {
+      this.param = param;
+    }
+
+    public void setParam(String param) {
+      this.param = param;
+    }
+
+    @Override
+    public String toString() {
+      return param;
+    }
+  }
 }