Remove HotSpot specifics from HeapDumper strategy interface

Closes gh-27533
pull/32405/head
Andy Wilkinson 2 years ago
parent f731279fef
commit 5cb68eab1e

@ -16,7 +16,9 @@
package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation; package org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation;
import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.nio.file.Files;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -66,7 +68,11 @@ class HeapDumpWebEndpointDocumentationTests extends MockMvcEndpointDocumentation
@Override @Override
protected HeapDumper createHeapDumper() { protected HeapDumper createHeapDumper() {
return (file, live) -> FileCopyUtils.copy("<<binary content>>", new FileWriter(file)); return (live) -> {
File file = Files.createTempFile("heap-", ".hprof").toFile();
FileCopyUtils.copy("<<binary content>>", new FileWriter(file));
return file;
};
} }
}; };

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -77,7 +77,7 @@ public class HeapDumpWebEndpoint {
try { try {
if (this.lock.tryLock(this.timeout, TimeUnit.MILLISECONDS)) { if (this.lock.tryLock(this.timeout, TimeUnit.MILLISECONDS)) {
try { try {
return new WebEndpointResponse<>(dumpHeap((live != null) ? live : true)); return new WebEndpointResponse<>(dumpHeap(live));
} }
finally { finally {
this.lock.unlock(); this.lock.unlock();
@ -96,29 +96,14 @@ public class HeapDumpWebEndpoint {
return new WebEndpointResponse<>(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS); return new WebEndpointResponse<>(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS);
} }
private Resource dumpHeap(boolean live) throws IOException, InterruptedException { private Resource dumpHeap(Boolean live) throws IOException, InterruptedException {
if (this.heapDumper == null) { if (this.heapDumper == null) {
this.heapDumper = createHeapDumper(); this.heapDumper = createHeapDumper();
} }
File file = createTempFile(); File file = this.heapDumper.dumpHeap(live);
this.heapDumper.dumpHeap(file, live);
return new TemporaryFileSystemResource(file); return new TemporaryFileSystemResource(file);
} }
private File createTempFile() throws IOException {
String date = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm").format(LocalDateTime.now());
File file = File.createTempFile("heap-" + date, "." + determineDumpSuffix());
file.delete();
return file;
}
private String determineDumpSuffix() {
if (this.heapDumper instanceof OpenJ9DiagnosticsMXBeanHeapDumper) {
return "phd";
}
return "hprof";
}
/** /**
* Factory method used to create the {@link HeapDumper}. * Factory method used to create the {@link HeapDumper}.
* @return the heap dumper to use * @return the heap dumper to use
@ -140,14 +125,17 @@ public class HeapDumpWebEndpoint {
protected interface HeapDumper { protected interface HeapDumper {
/** /**
* Dump the current heap to the specified file. * Dump the current heap to a file.
* @param file the file to dump the heap to
* @param live if only <em>live</em> objects (i.e. objects that are reachable from * @param live if only <em>live</em> objects (i.e. objects that are reachable from
* others) should be dumped * others) should be dumped. May be {@code null} to use a JVM-specific default.
* @return the file containing the heap dump
* @throws IOException on IO error * @throws IOException on IO error
* @throws InterruptedException on thread interruption * @throws InterruptedException on thread interruption
* @throws IllegalArgumentException if live is non-null and is not supported by
* the JVM
* @since 3.0.0
*/ */
void dumpHeap(File file, boolean live) throws IOException, InterruptedException; File dumpHeap(Boolean live) throws IOException, InterruptedException;
} }
@ -177,8 +165,18 @@ public class HeapDumpWebEndpoint {
} }
@Override @Override
public void dumpHeap(File file, boolean live) { public File dumpHeap(Boolean live) throws IOException {
ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, file.getAbsolutePath(), live); File file = createTempFile();
ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, file.getAbsolutePath(),
(live != null) ? live : true);
return file;
}
private File createTempFile() throws IOException {
String date = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm").format(LocalDateTime.now());
File file = File.createTempFile("heap-" + date, ".hprof");
file.delete();
return file;
} }
} }
@ -209,8 +207,13 @@ public class HeapDumpWebEndpoint {
} }
@Override @Override
public void dumpHeap(File file, boolean live) throws IOException, InterruptedException { public File dumpHeap(Boolean live) throws IOException, InterruptedException {
ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, "heap", file.getAbsolutePath()); if (live != null) {
throw new IllegalArgumentException(
"OpenJ9DiagnosticsMXBean does not support live parameter when dumping the heap");
}
return new File(
(String) ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, "heap", null));
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.boot.actuate.management; package org.springframework.boot.actuate.management;
import java.nio.file.Files;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -37,9 +38,10 @@ class HeapDumpWebEndpointTests {
@Override @Override
protected HeapDumper createHeapDumper() { protected HeapDumper createHeapDumper() {
return (file, live) -> { return (live) -> {
dumpingLatch.countDown(); dumpingLatch.countDown();
blockingLatch.await(); blockingLatch.await();
return Files.createTempFile("heap-", ".dump").toFile();
}; };
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2021 the original author or authors. * Copyright 2012-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,7 @@
package org.springframework.boot.actuate.management; package org.springframework.boot.actuate.management;
import java.io.File; import java.io.File;
import java.io.IOException; import java.nio.file.Files;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -98,15 +98,13 @@ class HeapDumpWebEndpointWebIntegrationTests {
@Override @Override
protected HeapDumper createHeapDumper() { protected HeapDumper createHeapDumper() {
return (file, live) -> { return (live) -> {
this.file = file; this.file = Files.createTempFile("heap-", ".dump").toFile();
if (!TestHeapDumpWebEndpoint.this.available) { if (!TestHeapDumpWebEndpoint.this.available) {
throw new HeapDumperUnavailableException("Not available", null); throw new HeapDumperUnavailableException("Not available", null);
} }
if (file.exists()) { FileCopyUtils.copy(TestHeapDumpWebEndpoint.this.heapDump.getBytes(), this.file);
throw new IOException("File exists"); return this.file;
}
FileCopyUtils.copy(TestHeapDumpWebEndpoint.this.heapDump.getBytes(), file);
}; };
} }

Loading…
Cancel
Save