Skip to content

Commit 36cf6d2

Browse files
committed
HBASE-26087 JVM crash when displaying RPC params by MonitoredRPCHandler
1 parent 0836695 commit 36cf6d2

File tree

3 files changed

+206
-4
lines changed

3 files changed

+206
-4
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/monitoring/MonitoredRPCHandlerImpl.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,20 @@ public MonitoredRPCHandlerImpl() {
5353

5454
@Override
5555
public synchronized MonitoredRPCHandlerImpl clone() {
56-
return (MonitoredRPCHandlerImpl) super.clone();
56+
MonitoredRPCHandlerImpl clone = (MonitoredRPCHandlerImpl) super.clone();
57+
return wrap(clone);
58+
}
59+
60+
public synchronized WrappedMonitoredRPCHandlerImpl wrap(MonitoredRPCHandlerImpl
61+
monitoredRPCHandler) {
62+
WrappedMonitoredRPCHandlerImpl wrappedMonitoredRPCHandler =
63+
new WrappedMonitoredRPCHandlerImpl(monitoredRPCHandler);
64+
wrappedMonitoredRPCHandler.setCallInfoMap(toMap());
65+
return wrappedMonitoredRPCHandler;
5766
}
5867

5968
/**
60-
* Gets the status of this handler; if it is currently servicing an RPC,
69+
* Gets the status of this handler; if it is currently servicing an RPC,
6170
* this status will include the RPC information.
6271
* @return a String describing the current status.
6372
*/
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.monitoring;
19+
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
import org.apache.yetus.audience.InterfaceAudience;
23+
24+
/**
25+
* A wrap of MonitoredRPCHandlerImpl, it has the call info from the call param.
26+
* Please use this class to avoid read offheap param data.
27+
*/
28+
@InterfaceAudience.Private
29+
public class WrappedMonitoredRPCHandlerImpl extends MonitoredRPCHandlerImpl
30+
implements MonitoredTask {
31+
private Map<String, Object> callInfoMap = new HashMap<>();
32+
private MonitoredRPCHandlerImpl monitoredRPCHandler;
33+
34+
public WrappedMonitoredRPCHandlerImpl(MonitoredRPCHandlerImpl monitoredRPCHandler) {
35+
this.monitoredRPCHandler = monitoredRPCHandler;
36+
}
37+
38+
public void setCallInfoMap(Map<String, Object> callInfoMap) {
39+
this.callInfoMap = callInfoMap;
40+
}
41+
42+
@Override
43+
public long getStartTime() {
44+
return monitoredRPCHandler.getStartTime();
45+
}
46+
47+
@Override
48+
public String getDescription() {
49+
return monitoredRPCHandler.getDescription();
50+
}
51+
52+
@Override
53+
public String getStatus() {
54+
return monitoredRPCHandler.getStatus();
55+
}
56+
57+
@Override
58+
public long getStatusTime() {
59+
return monitoredRPCHandler.getStatusTime();
60+
}
61+
62+
@Override
63+
public State getState() {
64+
return monitoredRPCHandler.getState();
65+
}
66+
67+
@Override
68+
public long getStateTime() {
69+
return monitoredRPCHandler.getStateTime();
70+
}
71+
72+
@Override
73+
public long getCompletionTimestamp() {
74+
return monitoredRPCHandler.getCompletionTimestamp();
75+
}
76+
77+
@Override
78+
public String getRPC() {
79+
return monitoredRPCHandler.getRPC(false);
80+
}
81+
82+
@Override
83+
public String getRPC(boolean withParams) {
84+
throw new UnsupportedOperationException();
85+
}
86+
87+
@Override
88+
public long getRPCStartTime() {
89+
return monitoredRPCHandler.getRPCStartTime();
90+
}
91+
92+
@Override
93+
public long getRPCQueueTime() {
94+
return monitoredRPCHandler.getRPCQueueTime();
95+
}
96+
97+
@Override
98+
public boolean isOperationRunning() {
99+
return monitoredRPCHandler.isOperationRunning();
100+
}
101+
102+
@Override
103+
public long getRPCPacketLength() {
104+
return monitoredRPCHandler.getRPCPacketLength();
105+
}
106+
107+
@Override
108+
public String getClient() {
109+
return monitoredRPCHandler.getClient();
110+
}
111+
112+
@Override
113+
public boolean isRPCRunning() {
114+
return monitoredRPCHandler.isRPCRunning();
115+
}
116+
117+
@Override
118+
public Map<String, Object> toMap() {
119+
return callInfoMap;
120+
}
121+
122+
@Override
123+
public String toString() {
124+
return monitoredRPCHandler.toString();
125+
}
126+
}

hbase-server/src/test/java/org/apache/hadoop/hbase/monitoring/TestTaskMonitor.java

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
*/
1818
package org.apache.hadoop.hbase.monitoring;
1919

20-
import static org.junit.Assert.*;
21-
20+
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertNotEquals;
22+
import static org.junit.Assert.assertTrue;
23+
import static org.junit.Assert.fail;
2224
import java.util.ArrayList;
2325
import java.util.List;
26+
import java.util.Map;
2427
import java.util.concurrent.atomic.AtomicBoolean;
2528
import org.apache.hadoop.conf.Configuration;
2629
import org.apache.hadoop.hbase.HBaseClassTestRule;
@@ -34,9 +37,12 @@
3437
import org.junit.ClassRule;
3538
import org.junit.Test;
3639
import org.junit.experimental.categories.Category;
40+
import org.slf4j.Logger;
41+
import org.slf4j.LoggerFactory;
3742

3843
@Category({MiscTests.class, SmallTests.class})
3944
public class TestTaskMonitor {
45+
private static final Logger LOG = LoggerFactory.getLogger(TestTaskMonitor.class);
4046

4147
@ClassRule
4248
public static final HBaseClassTestRule CLASS_RULE =
@@ -226,5 +232,66 @@ public void testStatusJournal() {
226232
assertEquals("status3", task.getStatusJournal().get(1).getStatus());
227233
tm.shutdown();
228234
}
235+
236+
@Test
237+
public void testClone() throws Exception {
238+
MonitoredRPCHandlerImpl monitor = new MonitoredRPCHandlerImpl();
239+
monitor.abort("abort RPC");
240+
TestParam testParam = new TestParam("param1");
241+
monitor.setRPC("method1", new Object[]{ testParam }, 0);
242+
MonitoredRPCHandlerImpl clone = monitor.clone();
243+
assertEquals(clone.getDescription(), monitor.getDescription());
244+
assertEquals(clone.getState(), monitor.getState());
245+
assertEquals(clone.getStatus(), monitor.getStatus());
246+
assertEquals(clone.toString(), monitor.toString());
247+
assertEquals(clone.toMap(), monitor.toMap());
248+
assertEquals(clone.toJSON(), monitor.toJSON());
249+
250+
// mark complete and make param dirty
251+
monitor.markComplete("complete RPC");
252+
testParam.setParam("dirtyParam");
253+
assertEquals(clone.getDescription(), monitor.getDescription());
254+
assertNotEquals(clone.getState(), monitor.getState());
255+
assertNotEquals(clone.getStatus(), monitor.getStatus());
256+
monitor.setState(MonitoredTask.State.RUNNING);
257+
try {
258+
// when markComplete, the param in monitor is set null, so toMap should fail here
259+
monitor.toMap();
260+
fail("Should not call toMap successfully, because param=null");
261+
} catch (Exception e) {
262+
}
263+
// the param of clone monitor should not be dirty
264+
assertNotEquals("[dirtyString]",
265+
String.valueOf(((Map<String, Object>) clone.toMap().get("rpcCall")).get("params")));
266+
267+
monitor.resume("resume");
268+
monitor.setRPC("method2", new Object[]{new TestParam("param2")}, 1);
269+
assertNotEquals(((Map<String, Object>) clone.toMap().get("rpcCall")).get("params"),
270+
((Map<String, Object>) monitor.toMap().get("rpcCall")).get(
271+
"params"));
272+
LOG.info(String.valueOf(clone.toMap()));
273+
LOG.info(String.valueOf(monitor.toMap()));
274+
assertNotEquals(clone.toString(), monitor.toString());
275+
assertNotEquals(clone.getRPCQueueTime(), monitor.getRPCQueueTime());
276+
assertNotEquals(clone.toMap(), monitor.toMap());
277+
assertNotEquals(clone.toJSON(), monitor.toJSON());
278+
}
279+
280+
private class TestParam {
281+
public String param = null;
282+
283+
public TestParam(String param) {
284+
this.param = param;
285+
}
286+
287+
public void setParam(String param) {
288+
this.param = param;
289+
}
290+
291+
@Override
292+
public String toString() {
293+
return param;
294+
}
295+
}
229296
}
230297

0 commit comments

Comments
 (0)