Skip to content

Commit 4eb7df4

Browse files
committed
add hbase 2.6.2
1 parent bdccb25 commit 4eb7df4

6 files changed

+604
-0
lines changed
Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
From 3f32872b0c49ed7125803fd599e7f1318ce8c00a Mon Sep 17 00:00:00 2001
2+
From: Siegfried Weber <[email protected]>
3+
Date: Tue, 6 Feb 2024 16:10:54 +0100
4+
Subject: HBASE-28242: Updates async-profiler support
5+
6+
---
7+
.../hadoop/hbase/http/ProfileServlet.java | 205 +++++++++++-------
8+
1 file changed, 121 insertions(+), 84 deletions(-)
9+
10+
diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ProfileServlet.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ProfileServlet.java
11+
index e92b4f9ae0..521ad7c380 100644
12+
--- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ProfileServlet.java
13+
+++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/ProfileServlet.java
14+
@@ -28,9 +28,11 @@ import java.util.concurrent.TimeUnit;
15+
import java.util.concurrent.atomic.AtomicInteger;
16+
import java.util.concurrent.locks.Lock;
17+
import java.util.concurrent.locks.ReentrantLock;
18+
+
19+
import javax.servlet.http.HttpServlet;
20+
import javax.servlet.http.HttpServletRequest;
21+
import javax.servlet.http.HttpServletResponse;
22+
+
23+
import org.apache.hadoop.hbase.util.ProcessUtils;
24+
import org.apache.yetus.audience.InterfaceAudience;
25+
import org.slf4j.Logger;
26+
@@ -40,23 +42,60 @@ import org.apache.hbase.thirdparty.com.google.common.base.Joiner;
27+
28+
/**
29+
* Servlet that runs async-profiler as web-endpoint. Following options from async-profiler can be
30+
- * specified as query paramater. // -e event profiling event: cpu|alloc|lock|cache-misses etc. // -d
31+
- * duration run profiling for 'duration' seconds (integer) // -i interval sampling interval in
32+
- * nanoseconds (long) // -j jstackdepth maximum Java stack depth (integer) // -b bufsize frame
33+
- * buffer size (long) // -t profile different threads separately // -s simple class names instead of
34+
- * FQN // -o fmt[,fmt...] output format: summary|traces|flat|collapsed|svg|tree|jfr|html // --width
35+
- * px SVG width pixels (integer) // --height px SVG frame height pixels (integer) // --minwidth px
36+
- * skip frames smaller than px (double) // --reverse generate stack-reversed FlameGraph / Call tree
37+
- * Example: - To collect 30 second CPU profile of current process (returns FlameGraph svg) curl
38+
- * "http://localhost:10002/prof" - To collect 1 minute CPU profile of current process and output in
39+
- * tree format (html) curl "http://localhost:10002/prof?output=tree&amp;duration=60" - To collect 30
40+
- * second heap allocation profile of current process (returns FlameGraph svg) curl
41+
- * "http://localhost:10002/prof?event=alloc" - To collect lock contention profile of current process
42+
- * (returns FlameGraph svg) curl "http://localhost:10002/prof?event=lock" Following event types are
43+
- * supported (default is 'cpu') (NOTE: not all OS'es support all events) // Perf events: // cpu //
44+
- * page-faults // context-switches // cycles // instructions // cache-references // cache-misses //
45+
- * branches // branch-misses // bus-cycles // L1-dcache-load-misses // LLC-load-misses //
46+
- * dTLB-load-misses // mem:breakpoint // trace:tracepoint // Java events: // alloc // lock
47+
+ * specified as query parameter.
48+
+ * <ul>
49+
+ * <li>-e event profiling event: cpu|alloc|lock|cache-misses etc.</li>
50+
+ * <li>-d duration run profiling for 'duration' seconds (integer), default 10s</li>
51+
+ * <li>-i interval sampling interval in nanoseconds (long), default 10ms</li>
52+
+ * <li>-j jstackdepth maximum Java stack depth (integer), default 2048</li>
53+
+ * <li>-t profile different threads separately</li>
54+
+ * <li>-s simple class names instead of FQN</li>
55+
+ * <li>-g print method signatures</li>
56+
+ * <li>-a annotate Java methods</li>
57+
+ * <li>-l prepend library names</li>
58+
+ * <li>-o fmt output format: flat|traces|collapsed|flamegraph|tree|jfr</li>
59+
+ * <li>--minwidth pct skip frames smaller than pct% (double)</li>
60+
+ * <li>--reverse generate stack-reversed FlameGraph / Call tree</li>
61+
+ * </ul>
62+
+ * Example:
63+
+ * <ul>
64+
+ * <li>To collect 30 second CPU profile of current process (returns FlameGraph svg):
65+
+ * {@code curl http://localhost:10002/prof"}</li>
66+
+ * <li>To collect 1 minute CPU profile of current process and output in tree format (html)
67+
+ * {@code curl "http://localhost:10002/prof?output=tree&amp;duration=60"}</li>
68+
+ * <li>To collect 30 second heap allocation profile of current process (returns FlameGraph):
69+
+ * {@code curl "http://localhost:10002/prof?event=alloc"}</li>
70+
+ * <li>To collect lock contention profile of current process (returns FlameGraph):
71+
+ * {@code curl "http://localhost:10002/prof?event=lock"}</li>
72+
+ * </ul>
73+
+ * Following event types are supported (default is 'cpu') (NOTE: not all OS'es support all
74+
+ * events).<br/>
75+
+ * Basic events:
76+
+ * <ul>
77+
+ * <li>cpu</li>
78+
+ * <li>alloc</li>
79+
+ * <li>lock</li>
80+
+ * <li>wall</li>
81+
+ * <li>itimer</li>
82+
+ * </ul>
83+
+ * Perf events:
84+
+ * <ul>
85+
+ * <li>L1-dcache-load-misses</li>
86+
+ * <li>LLC-load-misses</li>
87+
+ * <li>branch-instructions</li>
88+
+ * <li>branch-misses</li>
89+
+ * <li>bus-cycles</li>
90+
+ * <li>cache-misses</li>
91+
+ * <li>cache-references</li>
92+
+ * <li>context-switches</li>
93+
+ * <li>cpu</li>
94+
+ * <li>cycles</li>
95+
+ * <li>dTLB-load-misses</li>
96+
+ * <li>instructions</li>
97+
+ * <li>mem:breakpoint</li>
98+
+ * <li>page-faults</li>
99+
+ * <li>trace:tracepoint</li>
100+
+ * </ul>
101+
*/
102+
@InterfaceAudience.Private
103+
public class ProfileServlet extends HttpServlet {
104+
@@ -81,19 +120,20 @@ public class ProfileServlet extends HttpServlet {
105+
WALL("wall"),
106+
ALLOC("alloc"),
107+
LOCK("lock"),
108+
- PAGE_FAULTS("page-faults"),
109+
+ ITIMER("itimer"),
110+
+ BRANCH_INSTRUCTIONS("branch-instructions"),
111+
+ BRANCH_MISSES("branch-misses"),
112+
+ BUS_CYCLES("bus-cycles"),
113+
+ CACHE_MISSES("cache-misses"),
114+
+ CACHE_REFERENCES("cache-references"),
115+
CONTEXT_SWITCHES("context-switches"),
116+
CYCLES("cycles"),
117+
+ DTLB_LOAD_MISSES("dTLB-load-misses"),
118+
INSTRUCTIONS("instructions"),
119+
- CACHE_REFERENCES("cache-references"),
120+
- CACHE_MISSES("cache-misses"),
121+
- BRANCHES("branches"),
122+
- BRANCH_MISSES("branch-misses"),
123+
- BUS_CYCLES("bus-cycles"),
124+
L1_DCACHE_LOAD_MISSES("L1-dcache-load-misses"),
125+
LLC_LOAD_MISSES("LLC-load-misses"),
126+
- DTLB_LOAD_MISSES("dTLB-load-misses"),
127+
MEM_BREAKPOINT("mem:breakpoint"),
128+
+ PAGE_FAULTS("page-faults"),
129+
TRACE_TRACEPOINT("trace:tracepoint"),;
130+
131+
private final String internalName;
132+
@@ -102,11 +142,11 @@ public class ProfileServlet extends HttpServlet {
133+
this.internalName = internalName;
134+
}
135+
136+
- public String getInternalName() {
137+
+ String getInternalName() {
138+
return internalName;
139+
}
140+
141+
- public static Event fromInternalName(final String name) {
142+
+ static Event fromInternalName(final String name) {
143+
for (Event event : values()) {
144+
if (event.getInternalName().equalsIgnoreCase(name)) {
145+
return event;
146+
@@ -117,30 +157,26 @@ public class ProfileServlet extends HttpServlet {
147+
}
148+
}
149+
150+
- enum Output {
151+
- SUMMARY,
152+
- TRACES,
153+
- FLAT,
154+
+ private enum Output {
155+
COLLAPSED,
156+
- // No SVG in 2.x asyncprofiler.
157+
- SVG,
158+
- TREE,
159+
+ FLAMEGRAPH,
160+
+ FLAT,
161+
JFR,
162+
- // In 2.x asyncprofiler, this is how you get flamegraphs.
163+
- HTML
164+
+ TRACES,
165+
+ TREE
166+
}
167+
168+
@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED",
169+
justification = "This class is never serialized nor restored.")
170+
- private transient Lock profilerLock = new ReentrantLock();
171+
+ private final transient Lock profilerLock = new ReentrantLock();
172+
private transient volatile Process process;
173+
- private String asyncProfilerHome;
174+
+ private final String asyncProfilerHome;
175+
private Integer pid;
176+
177+
public ProfileServlet() {
178+
this.asyncProfilerHome = getAsyncProfilerHome();
179+
this.pid = ProcessUtils.getPid();
180+
- LOG.info("Servlet process PID: " + pid + " asyncProfilerHome: " + asyncProfilerHome);
181+
+ LOG.info("Servlet process PID: {} asyncProfilerHome: {}", pid, asyncProfilerHome);
182+
}
183+
184+
@Override
185+
@@ -159,9 +195,9 @@ public class ProfileServlet extends HttpServlet {
186+
setResponseHeader(resp);
187+
resp.getWriter()
188+
.write("ASYNC_PROFILER_HOME env is not set.\n\n"
189+
- + "Please ensure the prerequsites for the Profiler Servlet have been installed and the\n"
190+
+ + "Please ensure the prerequisites for the Profiler Servlet have been installed and the\n"
191+
+ "environment is properly configured. For more information please see\n"
192+
- + "http://hbase.apache.org/book.html#profiler\n");
193+
+ + "https://hbase.apache.org/book.html#profiler\n");
194+
return;
195+
}
196+
197+
@@ -177,18 +213,18 @@ public class ProfileServlet extends HttpServlet {
198+
return;
199+
}
200+
201+
- final int duration = getInteger(req, "duration", DEFAULT_DURATION_SECONDS);
202+
- final Output output = getOutput(req);
203+
- final Event event = getEvent(req);
204+
- final Long interval = getLong(req, "interval");
205+
- final Integer jstackDepth = getInteger(req, "jstackdepth", null);
206+
- final Long bufsize = getLong(req, "bufsize");
207+
- final boolean thread = req.getParameterMap().containsKey("thread");
208+
- final boolean simple = req.getParameterMap().containsKey("simple");
209+
- final Integer width = getInteger(req, "width", null);
210+
- final Integer height = getInteger(req, "height", null);
211+
- final Double minwidth = getMinWidth(req);
212+
- final boolean reverse = req.getParameterMap().containsKey("reverse");
213+
+ Event event = getEvent(req);
214+
+ int duration = getInteger(req, "duration", DEFAULT_DURATION_SECONDS);
215+
+ Long interval = getLong(req, "interval");
216+
+ Integer jstackDepth = getInteger(req, "jstackdepth", null);
217+
+ boolean thread = req.getParameterMap().containsKey("thread");
218+
+ boolean simple = req.getParameterMap().containsKey("simple");
219+
+ boolean signature = req.getParameterMap().containsKey("signature");
220+
+ boolean annotate = req.getParameterMap().containsKey("annotate");
221+
+ boolean prependLib = req.getParameterMap().containsKey("prependlib");
222+
+ Output output = getOutput(req);
223+
+ Double minwidth = getMinWidth(req);
224+
+ boolean reverse = req.getParameterMap().containsKey("reverse");
225+
226+
if (process == null || !process.isAlive()) {
227+
try {
228+
@@ -208,11 +244,7 @@ public class ProfileServlet extends HttpServlet {
229+
cmd.add("-e");
230+
cmd.add(event.getInternalName());
231+
cmd.add("-d");
232+
- cmd.add("" + duration);
233+
- cmd.add("-o");
234+
- cmd.add(output.name().toLowerCase());
235+
- cmd.add("-f");
236+
- cmd.add(outputFile.getAbsolutePath());
237+
+ cmd.add(String.valueOf(duration));
238+
if (interval != null) {
239+
cmd.add("-i");
240+
cmd.add(interval.toString());
241+
@@ -221,24 +253,25 @@ public class ProfileServlet extends HttpServlet {
242+
cmd.add("-j");
243+
cmd.add(jstackDepth.toString());
244+
}
245+
- if (bufsize != null) {
246+
- cmd.add("-b");
247+
- cmd.add(bufsize.toString());
248+
- }
249+
if (thread) {
250+
cmd.add("-t");
251+
}
252+
if (simple) {
253+
cmd.add("-s");
254+
}
255+
- if (width != null) {
256+
- cmd.add("--width");
257+
- cmd.add(width.toString());
258+
+ if (signature) {
259+
+ cmd.add("-g");
260+
}
261+
- if (height != null) {
262+
- cmd.add("--height");
263+
- cmd.add(height.toString());
264+
+ if (annotate) {
265+
+ cmd.add("-a");
266+
}
267+
+ if (prependLib) {
268+
+ cmd.add("-l");
269+
+ }
270+
+ cmd.add("-o");
271+
+ cmd.add(output.name().toLowerCase());
272+
+ cmd.add("-f");
273+
+ cmd.add(outputFile.getAbsolutePath());
274+
if (minwidth != null) {
275+
cmd.add("--minwidth");
276+
cmd.add(minwidth.toString());
277+
@@ -246,6 +279,7 @@ public class ProfileServlet extends HttpServlet {
278+
if (reverse) {
279+
cmd.add("--reverse");
280+
}
281+
+
282+
cmd.add(pid.toString());
283+
process = ProcessUtils.runCmdAsync(cmd);
284+
285+
@@ -256,7 +290,10 @@ public class ProfileServlet extends HttpServlet {
286+
resp.getWriter()
287+
.write("Started [" + event.getInternalName()
288+
+ "] profiling. This page will automatically redirect to " + relativeUrl + " after "
289+
- + duration + " seconds.\n\nCommand:\n" + Joiner.on(" ").join(cmd));
290+
+ + duration + " seconds. "
291+
+ + "If empty diagram and Linux 4.6+, see 'Basic Usage' section on the Async "
292+
+ + "Profiler Home Page, https://github.com/jvm-profiling-tools/async-profiler."
293+
+ + "\n\nCommand:\n" + Joiner.on(" ").join(cmd));
294+
295+
// to avoid auto-refresh by ProfileOutputServlet, refreshDelay can be specified
296+
// via url param
297+
@@ -274,8 +311,9 @@ public class ProfileServlet extends HttpServlet {
298+
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
299+
resp.getWriter()
300+
.write("Unable to acquire lock. Another instance of profiler might be running.");
301+
- LOG.warn("Unable to acquire lock in " + lockTimeoutSecs
302+
- + " seconds. Another instance of profiler might be running.");
303+
+ LOG.warn(
304+
+ "Unable to acquire lock in {} seconds. Another instance of profiler might be running.",
305+
+ lockTimeoutSecs);
306+
}
307+
} catch (InterruptedException e) {
308+
LOG.warn("Interrupted while acquiring profile lock.", e);
309+
@@ -288,9 +326,9 @@ public class ProfileServlet extends HttpServlet {
310+
}
311+
}
312+
313+
- private Integer getInteger(final HttpServletRequest req, final String param,
314+
+ private static Integer getInteger(final HttpServletRequest req, final String param,
315+
final Integer defaultValue) {
316+
- final String value = req.getParameter(param);
317+
+ String value = req.getParameter(param);
318+
if (value != null) {
319+
try {
320+
return Integer.valueOf(value);
321+
@@ -301,8 +339,8 @@ public class ProfileServlet extends HttpServlet {
322+
return defaultValue;
323+
}
324+
325+
- private Long getLong(final HttpServletRequest req, final String param) {
326+
- final String value = req.getParameter(param);
327+
+ private static Long getLong(final HttpServletRequest req, final String param) {
328+
+ String value = req.getParameter(param);
329+
if (value != null) {
330+
try {
331+
return Long.valueOf(value);
332+
@@ -313,8 +351,8 @@ public class ProfileServlet extends HttpServlet {
333+
return null;
334+
}
335+
336+
- private Double getMinWidth(final HttpServletRequest req) {
337+
- final String value = req.getParameter("minwidth");
338+
+ private static Double getMinWidth(final HttpServletRequest req) {
339+
+ String value = req.getParameter("minwidth");
340+
if (value != null) {
341+
try {
342+
return Double.valueOf(value);
343+
@@ -325,8 +363,8 @@ public class ProfileServlet extends HttpServlet {
344+
return null;
345+
}
346+
347+
- private Event getEvent(final HttpServletRequest req) {
348+
- final String eventArg = req.getParameter("event");
349+
+ private static Event getEvent(final HttpServletRequest req) {
350+
+ String eventArg = req.getParameter("event");
351+
if (eventArg != null) {
352+
Event event = Event.fromInternalName(eventArg);
353+
return event == null ? Event.CPU : event;
354+
@@ -334,16 +372,16 @@ public class ProfileServlet extends HttpServlet {
355+
return Event.CPU;
356+
}
357+
358+
- private Output getOutput(final HttpServletRequest req) {
359+
- final String outputArg = req.getParameter("output");
360+
+ private static Output getOutput(final HttpServletRequest req) {
361+
+ String outputArg = req.getParameter("output");
362+
if (req.getParameter("output") != null) {
363+
try {
364+
return Output.valueOf(outputArg.trim().toUpperCase());
365+
} catch (IllegalArgumentException e) {
366+
- return Output.HTML;
367+
+ return Output.FLAMEGRAPH;
368+
}
369+
}
370+
- return Output.HTML;
371+
+ return Output.FLAMEGRAPH;
372+
}
373+
374+
static void setResponseHeader(final HttpServletResponse response) {
375+
@@ -375,8 +413,7 @@ public class ProfileServlet extends HttpServlet {
376+
.write("The profiler servlet was disabled at startup.\n\n"
377+
+ "Please ensure the prerequisites for the Profiler Servlet have been installed and the\n"
378+
+ "environment is properly configured. For more information please see\n"
379+
- + "http://hbase.apache.org/book.html#profiler\n");
380+
- return;
381+
+ + "https://hbase.apache.org/book.html#profiler\n");
382+
}
383+
384+
}

0 commit comments

Comments
 (0)