Skip to content

Commit 336a23e

Browse files
committedApr 3, 2023
8303229: JFR: Preserve disk repository after exit
Reviewed-by: dholmes, mgronlun
1 parent ecec611 commit 336a23e

File tree

10 files changed

+235
-45
lines changed

10 files changed

+235
-45
lines changed
 

‎src/hotspot/share/jfr/dcmd/jfrDcmds.cpp

+50-40
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,15 @@ GrowableArray<const char*>* JfrDCmd::argument_name_array() const {
367367
JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
368368
bool heap) : DCmdWithParser(output, heap),
369369
_repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
370-
_dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
371-
_stack_depth("stackdepth", "Stack Depth", "JULONG", false, "64"),
370+
_dump_path("dumppath", "Path to dump, e.g. \\\"My Dump path\\\"", "STRING", false, NULL),
371+
_stack_depth("stackdepth", "Stack depth", "JULONG", false, "64"),
372372
_global_buffer_count("globalbuffercount", "Number of global buffers,", "JULONG", false, "20"),
373373
_global_buffer_size("globalbuffersize", "Size of a global buffers,", "MEMORY SIZE", false, "512k"),
374374
_thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "MEMORY SIZE", false, "8k"),
375375
_memory_size("memorysize", "Overall memory size, ", "MEMORY SIZE", false, "10m"),
376376
_max_chunk_size("maxchunksize", "Size of an individual disk chunk", "MEMORY SIZE", false, "12m"),
377-
_sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true"),
377+
_sample_threads("samplethreads", "Activate thread sampling", "BOOLEAN", false, "true"),
378+
_preserve_repository("preserve-repository", "Preserve the disk repository after JVM exit", "BOOLEAN", false, "false"),
378379
_verbose(true) {
379380
_dcmdparser.add_dcmd_option(&_repository_path);
380381
_dcmdparser.add_dcmd_option(&_dump_path);
@@ -385,56 +386,60 @@ JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* out
385386
_dcmdparser.add_dcmd_option(&_memory_size);
386387
_dcmdparser.add_dcmd_option(&_max_chunk_size);
387388
_dcmdparser.add_dcmd_option(&_sample_threads);
389+
_dcmdparser.add_dcmd_option(&_preserve_repository);
388390
};
389391

390392
void JfrConfigureFlightRecorderDCmd::print_help(const char* name) const {
391393
outputStream* out = output();
392394
// 0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890
393395
out->print_cr("Options:");
394396
out->print_cr("");
395-
out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy");
396-
out->print_cr(" option: change the memorysize parameter to alter the number of");
397-
out->print_cr(" global buffers. This value cannot be changed once JFR has been");
398-
out->print_cr(" initialized. (STRING, default determined by the value for");
399-
out->print_cr(" memorysize)");
397+
out->print_cr(" globalbuffercount (Optional) Number of global buffers. This option is a legacy");
398+
out->print_cr(" option: change the memorysize parameter to alter the number of");
399+
out->print_cr(" global buffers. This value cannot be changed once JFR has been");
400+
out->print_cr(" initialized. (STRING, default determined by the value for");
401+
out->print_cr(" memorysize)");
400402
out->print_cr("");
401-
out->print_cr(" globalbuffersize (Optional) Size of the global buffers, in bytes. This option is a");
402-
out->print_cr(" legacy option: change the memorysize parameter to alter the size");
403-
out->print_cr(" of the global buffers. This value cannot be changed once JFR has");
404-
out->print_cr(" been initialized. (STRING, default determined by the value for");
405-
out->print_cr(" memorysize)");
403+
out->print_cr(" globalbuffersize (Optional) Size of the global buffers, in bytes. This option is a");
404+
out->print_cr(" legacy option: change the memorysize parameter to alter the size");
405+
out->print_cr(" of the global buffers. This value cannot be changed once JFR has");
406+
out->print_cr(" been initialized. (STRING, default determined by the value for");
407+
out->print_cr(" memorysize)");
406408
out->print_cr("");
407-
out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if");
408-
out->print_cr(" one of the following suffixes is not used: 'm' or 'M' for");
409-
out->print_cr(" megabytes OR 'g' or 'G' for gigabytes. This value cannot be");
410-
out->print_cr(" changed once JFR has been initialized. (STRING, 12M)");
409+
out->print_cr(" maxchunksize (Optional) Maximum size of an individual data chunk in bytes if");
410+
out->print_cr(" one of the following suffixes is not used: 'm' or 'M' for");
411+
out->print_cr(" megabytes OR 'g' or 'G' for gigabytes. This value cannot be");
412+
out->print_cr(" changed once JFR has been initialized. (STRING, 12M)");
411413
out->print_cr("");
412-
out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following");
413-
out->print_cr(" suffixes is not used: 'm' or 'M' for megabytes OR 'g' or 'G' for");
414-
out->print_cr(" gigabytes. This value cannot be changed once JFR has been");
415-
out->print_cr(" initialized. (STRING, 10M)");
414+
out->print_cr(" memorysize (Optional) Overall memory size, in bytes if one of the following");
415+
out->print_cr(" suffixes is not used: 'm' or 'M' for megabytes OR 'g' or 'G' for");
416+
out->print_cr(" gigabytes. This value cannot be changed once JFR has been");
417+
out->print_cr(" initialized. (STRING, 10M)");
416418
out->print_cr("");
417-
out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until");
418-
out->print_cr(" they are written to a permanent file. (STRING, The default");
419-
out->print_cr(" location is the temporary directory for the operating system. On");
420-
out->print_cr(" Linux operating systems, the temporary directory is /tmp. On");
421-
out->print_cr(" Windows, the temporary directory is specified by the TMP");
422-
out->print_cr(" environment variable)");
419+
out->print_cr(" repositorypath (Optional) Path to the location where recordings are stored until");
420+
out->print_cr(" they are written to a permanent file. (STRING, The default");
421+
out->print_cr(" location is the temporary directory for the operating system. On");
422+
out->print_cr(" Linux operating systems, the temporary directory is /tmp. On");
423+
out->print_cr(" Windows, the temporary directory is specified by the TMP");
424+
out->print_cr(" environment variable)");
423425
out->print_cr("");
424-
out->print_cr(" dumppath (Optional) Path to the location where a recording file is written");
425-
out->print_cr(" in case the VM runs into a critical error, such as a system");
426-
out->print_cr(" crash. (STRING, The default location is the current directory)");
426+
out->print_cr(" dumppath (Optional) Path to the location where a recording file is written");
427+
out->print_cr(" in case the VM runs into a critical error, such as a system");
428+
out->print_cr(" crash. (STRING, The default location is the current directory)");
427429
out->print_cr("");
428-
out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value");
429-
out->print_cr(" greater than the default of 64 may cause a performance");
430-
out->print_cr(" degradation. This value cannot be changed once JFR has been");
431-
out->print_cr(" initialized. (LONG, 64)");
430+
out->print_cr(" stackdepth (Optional) Stack depth for stack traces. Setting this value");
431+
out->print_cr(" greater than the default of 64 may cause a performance");
432+
out->print_cr(" degradation. This value cannot be changed once JFR has been");
433+
out->print_cr(" initialized. (LONG, 64)");
432434
out->print_cr("");
433-
out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of");
434-
out->print_cr(" the following suffixes is not used: 'k' or 'K' for kilobytes or");
435-
out->print_cr(" 'm' or 'M' for megabytes. Overriding this parameter could reduce");
436-
out->print_cr(" performance and is not recommended. This value cannot be changed");
437-
out->print_cr(" once JFR has been initialized. (STRING, 8k)");
435+
out->print_cr(" thread_buffer_size (Optional) Local buffer size for each thread in bytes if one of");
436+
out->print_cr(" the following suffixes is not used: 'k' or 'K' for kilobytes or");
437+
out->print_cr(" 'm' or 'M' for megabytes. Overriding this parameter could reduce");
438+
out->print_cr(" performance and is not recommended. This value cannot be changed");
439+
out->print_cr(" once JFR has been initialized. (STRING, 8k)");
440+
out->print_cr("");
441+
out->print_cr(" preserve-repository (Optional) Preserve files stored in the disk repository after the");
442+
out->print_cr(" Java Virtual Machine has exited. (BOOLEAN, false)");
438443
out->print_cr("");
439444
out->print_cr("Options must be specified using the <key> or <key>=<value> syntax.");
440445
out->print_cr("");
@@ -480,6 +485,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
480485
jobject thread_buffer_size = NULL;
481486
jobject max_chunk_size = NULL;
482487
jobject memory_size = NULL;
488+
jobject preserve_repository = nullptr;
483489

484490
if (!JfrRecorder::is_created()) {
485491
if (_stack_depth.is_set()) {
@@ -510,12 +516,15 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
510516
}
511517
}
512518
}
519+
if (_preserve_repository.is_set()) {
520+
preserve_repository = JfrJavaSupport::new_java_lang_Boolean(_preserve_repository.value(), CHECK);
521+
}
513522

514523
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
515524
static const char method[] = "execute";
516525
static const char signature[] = "(ZLjava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
517526
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
518-
"Ljava/lang/Long;)[Ljava/lang/String;";
527+
"Ljava/lang/Long;Ljava/lang/Boolean;)[Ljava/lang/String;";
519528

520529
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
521530
execute_args.set_receiver(h_dcmd_instance);
@@ -530,6 +539,7 @@ void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
530539
execute_args.push_jobject(thread_buffer_size);
531540
execute_args.push_jobject(memory_size);
532541
execute_args.push_jobject(max_chunk_size);
542+
execute_args.push_jobject(preserve_repository);
533543

534544
JfrJavaSupport::call_virtual(&execute_args, THREAD);
535545
handle_dcmd_result(output(), result.get_oop(), source, THREAD);

‎src/hotspot/share/jfr/dcmd/jfrDcmds.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
157157
DCmdArgument<MemorySizeArgument> _memory_size;
158158
DCmdArgument<MemorySizeArgument> _max_chunk_size;
159159
DCmdArgument<bool> _sample_threads;
160+
DCmdArgument<bool> _preserve_repository;
160161
bool _verbose;
161162

162163
public:
@@ -177,7 +178,7 @@ class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
177178
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
178179
return p;
179180
}
180-
static int num_arguments() { return 9; }
181+
static int num_arguments() { return 10; }
181182
virtual void execute(DCmdSource source, TRAPS);
182183
virtual void print_help(const char* name) const;
183184
};

‎src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ const char* const default_sample_threads = "true";
165165
const char* const default_stack_depth = "64";
166166
const char* const default_retransform = "true";
167167
const char* const default_old_object_queue_size = "256";
168+
const char* const default_preserve_repository = "false";
168169
DEBUG_ONLY(const char* const default_sample_protection = "false";)
169170

170171
// statics
@@ -254,6 +255,13 @@ static DCmdArgument<bool> _dcmd_retransform(
254255
true,
255256
default_retransform);
256257

258+
static DCmdArgument<bool> _dcmd_preserve_repository(
259+
"preserve-repository",
260+
"Preserve disk repository after JVM exit",
261+
"BOOLEAN",
262+
false,
263+
default_preserve_repository);
264+
257265
static DCmdParser _parser;
258266

259267
static void register_parser_options() {
@@ -268,6 +276,7 @@ static void register_parser_options() {
268276
_parser.add_dcmd_option(&_dcmd_sample_threads);
269277
_parser.add_dcmd_option(&_dcmd_retransform);
270278
_parser.add_dcmd_option(&_dcmd_old_object_queue_size);
279+
_parser.add_dcmd_option(&_dcmd_preserve_repository);
271280
DEBUG_ONLY(_parser.add_dcmd_option(&_dcmd_sample_protection);)
272281
}
273282

@@ -379,6 +388,9 @@ bool JfrOptionSet::configure(TRAPS) {
379388
configure._sample_threads.set_is_set(_dcmd_sample_threads.is_set());
380389
configure._sample_threads.set_value(_dcmd_sample_threads.value());
381390

391+
configure._preserve_repository.set_is_set(_dcmd_preserve_repository.is_set());
392+
configure._preserve_repository.set_value(_dcmd_preserve_repository.value());
393+
382394
configure.set_verbose(false);
383395
configure.execute(DCmd_Source_Internal, THREAD);
384396

‎src/java.base/share/man/java.1

+6
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,12 @@ buffers.
13371337
Maximum number of old objects to track.
13381338
By default, the number of objects is set to 256.
13391339
.TP
1340+
\f[V]preserve-repository=\f[R]{\f[V]true\f[R]|\f[V]false\f[R]}
1341+
Specifies whether files stored in the disk repository should be kept
1342+
after the JVM has exited.
1343+
If false, files are deleted.
1344+
By default, this parameter is disabled.
1345+
.TP
13401346
\f[V]repository=\f[R]\f[I]path\f[R]
13411347
Specifies the repository (a directory) for temporary disk storage.
13421348
By default, the system\[aq]s temporary directory is used.

‎src/jdk.jcmd/share/man/jcmd.1

+6
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,12 @@ On Linux operating systems, the temporary directory is \f[V]/tmp\f[R].
402402
On Windwows, the temporary directory is specified by the \f[V]TMP\f[R]
403403
environment variable.)
404404
.IP \[bu] 2
405+
\f[V]preserve-repository=\f[R]{\f[V]true\f[R]|\f[V]false\f[R]} :
406+
Specifies whether files stored in the disk repository should be kept
407+
after the JVM has exited.
408+
If false, files are deleted.
409+
By default, this parameter is disabled.
410+
.IP \[bu] 2
405411
\f[V]stackdepth\f[R]: (Optional) Stack depth for stack traces.
406412
Setting this value greater than the default of 64 may cause a
407413
performance degradation.

‎src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java

+11
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,15 @@ public final class Options {
5252
private static final int DEFAULT_STACK_DEPTH = 64;
5353
private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024;
5454
private static final SafePath DEFAULT_DUMP_PATH = null;
55+
private static final boolean DEFAULT_PRESERVE_REPOSITORY = false;
5556

5657
private static long memorySize;
5758
private static long globalBufferSize;
5859
private static long globalBufferCount;
5960
private static long threadBufferSize;
6061
private static int stackDepth;
6162
private static long maxChunkSize;
63+
private static boolean preserveRepository;
6264

6365
static {
6466
final long pageSize = Unsafe.getUnsafe().pageSize();
@@ -138,6 +140,14 @@ public static synchronized int getStackDepth() {
138140
return stackDepth;
139141
}
140142

143+
public static synchronized void setPreserveRepository(boolean preserve) {
144+
preserveRepository = preserve;
145+
}
146+
147+
public static synchronized boolean getPreserveRepository() {
148+
return preserveRepository;
149+
}
150+
141151
private static synchronized void reset() {
142152
setMaxChunkSize(DEFAULT_MAX_CHUNK_SIZE);
143153
setMemorySize(DEFAULT_MEMORY_SIZE);
@@ -150,6 +160,7 @@ private static synchronized void reset() {
150160
}
151161
setStackDepth(DEFAULT_STACK_DEPTH);
152162
setThreadBufferSize(DEFAULT_THREAD_BUFFER_SIZE);
163+
setPreserveRepository(DEFAULT_PRESERVE_REPOSITORY);
153164
}
154165

155166
static synchronized long getWaitInterval() {

‎src/jdk.jfr/share/classes/jdk/jfr/internal/Repository.java

+4
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ private static boolean tryToUseAsRepository(final SafePath path) {
160160
}
161161

162162
synchronized void clear() {
163+
if (Options.getPreserveRepository()) {
164+
return;
165+
}
166+
163167
for (SafePath p : cleanupDirectories) {
164168
try {
165169
SecuritySupport.clearDirectory(p);

‎src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdConfigure.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ final class DCmdConfigure extends AbstractDCmd {
5151
* @param globalBufferCount number of global buffers
5252
* @param globalBufferSize size of global buffers
5353
* @param threadBufferSize size of thread buffer for events
54+
* @param memorySize Size of in memory buffer
5455
* @param maxChunkSize threshold at which a new chunk is created in the disk repository
55-
* @param sampleThreads if thread sampling should be enabled
56-
*
56+
* @param preserveRepository if files in the repository should be deleted on exit.
5757
* @return result
5858
5959
* @throws DCmdException
@@ -69,7 +69,8 @@ final class DCmdConfigure extends AbstractDCmd {
6969
Long globalBufferSize,
7070
Long threadBufferSize,
7171
Long memorySize,
72-
Long maxChunkSize
72+
Long maxChunkSize,
73+
Boolean preserveRepository
7374

7475
) throws DCmdException {
7576
if (Logger.shouldLog(LogTag.JFR_DCMD, LogLevel.DEBUG)) {
@@ -80,7 +81,8 @@ final class DCmdConfigure extends AbstractDCmd {
8081
", globalbuffersize=" + globalBufferSize +
8182
", thread_buffer_size=" + threadBufferSize +
8283
", memorysize=" + memorySize +
83-
", maxchunksize=" + maxChunkSize);
84+
", maxchunksize=" + maxChunkSize +
85+
", preserveRepository=" + preserveRepository);
8486
}
8587

8688

@@ -103,6 +105,14 @@ final class DCmdConfigure extends AbstractDCmd {
103105
updated = true;
104106
}
105107

108+
if (preserveRepository != null) {
109+
Options.setPreserveRepository(preserveRepository.booleanValue());
110+
if (verbose) {
111+
printPreserveRepository();
112+
}
113+
updated = true;
114+
}
115+
106116
if (dumpPath != null) {
107117
try {
108118
Options.setDumpPath(new SafePath(dumpPath));
@@ -176,6 +186,7 @@ final class DCmdConfigure extends AbstractDCmd {
176186
if (!updated) {
177187
println("Current configuration:");
178188
println();
189+
printPreserveRepository();
179190
printRepositoryPath();
180191
printDumpPath();
181192
printStackDepth();
@@ -194,6 +205,10 @@ private void printRepositoryPath() {
194205
println();
195206
}
196207

208+
private void printPreserveRepository() {
209+
println("Preserve repository: " + Options.getPreserveRepository());
210+
}
211+
197212
private void printDumpPath() {
198213
print("Dump path: ");
199214
printPath(Options.getDumpPath());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
package jdk.jfr.jcmd;
25+
26+
import java.io.File;
27+
import java.nio.file.Files;
28+
import java.nio.file.Path;
29+
import java.util.Optional;
30+
31+
import jdk.test.lib.jfr.FileHelper;
32+
import jdk.test.lib.process.OutputAnalyzer;
33+
import jdk.test.lib.process.ProcessTools;
34+
import jdk.test.lib.Utils;
35+
/**
36+
* @test
37+
* @summary Test verifies that files are left after preserve-repository has been set using jcmd JFR.configure
38+
* @key jfr
39+
* @requires vm.hasJFR
40+
* @library /test/lib /test/jdk
41+
* @run main/othervm jdk.jfr.jcmd.TestJcmdPreserveRepository
42+
*/
43+
public class TestJcmdPreserveRepository {
44+
45+
public static class TestProcess {
46+
public static void main(String... args) {
47+
OutputAnalyzer output = JcmdHelper.jcmd("JFR.configure", "preserve-repository=true");
48+
System.exit(output.getExitValue());
49+
}
50+
}
51+
52+
public static void main(String[] args) throws Throwable {
53+
Path path = Path.of("./preserved");
54+
String[] arguments = {
55+
"-XX:StartFlightRecording",
56+
"-XX:FlightRecorderOptions:repository=" + path,
57+
"-Dtest.jdk=" + System.getProperty("test.jdk"),
58+
TestProcess.class.getName()
59+
};
60+
OutputAnalyzer output = ProcessTools.executeTestJvm(arguments);
61+
output.shouldHaveExitValue(0);
62+
Optional<Path> p = Files.find(path, 99, (a,b) -> a.getFileName().toString().endsWith(".jfr")).findAny();
63+
if (p.isEmpty()) {
64+
throw new Exception("Could not find preserved files in repository");
65+
}
66+
}
67+
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.jfr.startupargs;
24+
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.util.Optional;
28+
29+
import jdk.test.lib.process.OutputAnalyzer;
30+
import jdk.test.lib.process.ProcessTools;
31+
/**
32+
* @test
33+
* @summary Tests that -XX:FlightRecorderOptions:preserve-repository works
34+
* @key jfr
35+
* @requires vm.hasJFR
36+
* @modules jdk.jfr
37+
* @library /test/lib
38+
* @run main/othervm jdk.jfr.startupargs.TestPreserveRepository
39+
*/
40+
public class TestPreserveRepository {
41+
42+
public static void main(String... args) throws Exception {
43+
Path path = Path.of("./preserved");
44+
String[] arguments = {
45+
"-XX:StartFlightRecording",
46+
"-XX:FlightRecorderOptions:repository=" + path + ",preserve-repository=true",
47+
"-version"
48+
};
49+
ProcessBuilder pb = ProcessTools.createTestJvm(arguments);
50+
OutputAnalyzer output = ProcessTools.executeProcess(pb);
51+
output.shouldHaveExitValue(0);
52+
Optional<Path> p = Files.find(path, 99, (a,b) -> a.getFileName().toString().endsWith(".jfr")).findAny();
53+
if (p.isEmpty()) {
54+
throw new Exception("Could not find preserved files in repository");
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)
Please sign in to comment.