src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java
changeset 50745 a390cbb82d47
parent 50113 caf115bb98ad
child 52413 6372f5af9612
equal deleted inserted replaced
50744:6c306d54366d 50745:a390cbb82d47
    24  */
    24  */
    25 package jdk.jfr.internal.dcmd;
    25 package jdk.jfr.internal.dcmd;
    26 
    26 
    27 import java.io.IOException;
    27 import java.io.IOException;
    28 import java.nio.file.InvalidPathException;
    28 import java.nio.file.InvalidPathException;
    29 import java.util.HashMap;
    29 import java.time.Duration;
    30 import java.util.Map;
    30 import java.time.Instant;
    31 
    31 import java.time.LocalDate;
       
    32 import java.time.LocalDateTime;
       
    33 import java.time.LocalTime;
       
    34 import java.time.ZoneId;
       
    35 import java.time.ZonedDateTime;
       
    36 import java.time.format.DateTimeParseException;
       
    37 
       
    38 import jdk.jfr.FlightRecorder;
    32 import jdk.jfr.Recording;
    39 import jdk.jfr.Recording;
       
    40 import jdk.jfr.internal.LogLevel;
       
    41 import jdk.jfr.internal.LogTag;
       
    42 import jdk.jfr.internal.Logger;
       
    43 import jdk.jfr.internal.PlatformRecorder;
    33 import jdk.jfr.internal.PlatformRecording;
    44 import jdk.jfr.internal.PlatformRecording;
    34 import jdk.jfr.internal.PrivateAccess;
    45 import jdk.jfr.internal.PrivateAccess;
    35 import jdk.jfr.internal.SecuritySupport.SafePath;
    46 import jdk.jfr.internal.SecuritySupport.SafePath;
    36 import jdk.jfr.internal.Utils;
    47 import jdk.jfr.internal.Utils;
    37 import jdk.jfr.internal.WriteableUserPath;
    48 import jdk.jfr.internal.WriteableUserPath;
    38 
    49 
    39 /**
    50 /**
    40  * JFR.dump
    51  * JFR.dump
    41  *
    52  *
    42  */
    53  */
    43 //Instantiated by native
    54 // Instantiated by native
    44 final class DCmdDump extends AbstractDCmd {
    55 final class DCmdDump extends AbstractDCmd {
    45     /**
    56     /**
    46      * Execute JFR.dump.
    57      * Execute JFR.dump.
    47      *
    58      *
    48      * @param recordingText name or id of the recording to dump, or
    59      * @param name name or id of the recording to dump, or <code>null</code> to dump everything
    49      *        <code>null</code>
    60      *
    50      *
    61      * @param filename file path where recording should be written, not null
    51      * @param textPath file path where recording should be written.
    62      * @param maxAge how far back in time to dump, may be null
       
    63      * @param maxSize how far back in size to dump data from, may be null
       
    64      * @param begin point in time to dump data from, may be null
       
    65      * @param end point in time to dump data to, may be null
       
    66      * @param pathToGcRoots if Java heap should be swept for reference chains
    52      *
    67      *
    53      * @return result output
    68      * @return result output
    54      *
    69      *
    55      * @throws DCmdException if the dump could not be completed
    70      * @throws DCmdException if the dump could not be completed
    56      */
    71      */
    57     public String execute(String recordingText, String textPath,  Boolean pathToGcRoots) throws DCmdException {
    72     public String execute(String name, String filename, Long maxAge, Long maxSize, String begin, String end, Boolean pathToGcRoots) throws DCmdException {
    58         if (textPath == null) {
    73         if (LogTag.JFR_DCMD.shouldLog(LogLevel.DEBUG)) {
    59             throw new DCmdException("Failed to dump %s, missing filename.", recordingText);
    74             Logger.log(LogTag.JFR_DCMD, LogLevel.DEBUG,
    60         }
    75                     "Executing DCmdDump: name=" + name +
    61         Recording recording = findRecording(recordingText);
    76                     ", filename=" + filename +
       
    77                     ", maxage=" + maxAge +
       
    78                     ", maxsize=" + maxSize +
       
    79                     ", begin=" + begin +
       
    80                     ", end" + end +
       
    81                     ", path-to-gc-roots=" + pathToGcRoots);
       
    82         }
       
    83 
       
    84         if (FlightRecorder.getFlightRecorder().getRecordings().isEmpty()) {
       
    85             throw new DCmdException("No recordings to dump from. Use JFR.start to start a recording.");
       
    86         }
       
    87 
       
    88         if (maxAge != null) {
       
    89             if (end != null || begin != null) {
       
    90                 throw new DCmdException("Dump failed, maxage can't be combined with begin or end.");
       
    91             }
       
    92 
       
    93             if (maxAge < 0) {
       
    94                 throw new DCmdException("Dump failed, maxage can't be negative.");
       
    95             }
       
    96             if (maxAge == 0) {
       
    97                 maxAge = Long.MAX_VALUE / 2; // a high value that won't overflow
       
    98             }
       
    99         }
       
   100 
       
   101         if (maxSize!= null) {
       
   102             if (maxSize < 0) {
       
   103                 throw new DCmdException("Dump failed, maxsize can't be negative.");
       
   104             }
       
   105             if (maxSize == 0) {
       
   106                 maxSize = Long.MAX_VALUE / 2; // a high value that won't overflow
       
   107             }
       
   108         }
       
   109 
       
   110         Instant beginTime = parseTime(begin, "begin");
       
   111         Instant endTime = parseTime(end, "end");
       
   112 
       
   113         if (beginTime != null && endTime != null) {
       
   114             if (endTime.isBefore(beginTime)) {
       
   115                 throw new DCmdException("Dump failed, begin must preceed end.");
       
   116             }
       
   117         }
       
   118 
       
   119         Duration duration = null;
       
   120         if (maxAge != null) {
       
   121             duration = Duration.ofNanos(maxAge);
       
   122             beginTime = Instant.now().minus(duration);
       
   123         }
       
   124         Recording recording = null;
       
   125         if (name != null) {
       
   126             recording = findRecording(name);
       
   127         }
       
   128         PlatformRecorder recorder = PrivateAccess.getInstance().getPlatformRecorder();
       
   129         synchronized (recorder) {
       
   130             dump(recorder, recording, name, filename, maxSize, pathToGcRoots, beginTime, endTime);
       
   131         }
       
   132         return getResult();
       
   133     }
       
   134 
       
   135     public void dump(PlatformRecorder recorder, Recording recording, String name, String filename, Long maxSize, Boolean pathToGcRoots, Instant beginTime, Instant endTime) throws DCmdException {
       
   136         try (PlatformRecording r = newSnapShot(recorder, recording, pathToGcRoots)) {
       
   137             r.filter(beginTime, endTime, maxSize);
       
   138             if (r.getChunks().isEmpty()) {
       
   139                 throw new DCmdException("Dump failed. No data found in the specified interval.");
       
   140             }
       
   141             SafePath dumpFile = resolvePath(recording, filename);
       
   142 
       
   143             // Needed for JVM
       
   144             Utils.touch(dumpFile.toPath());
       
   145             r.dumpStopped(new WriteableUserPath(dumpFile.toPath()));
       
   146             reportOperationComplete("Dumped", name, dumpFile);
       
   147         } catch (IOException | InvalidPathException e) {
       
   148             throw new DCmdException("Dump failed. Could not copy recording data. %s", e.getMessage());
       
   149         }
       
   150     }
       
   151 
       
   152     private Instant parseTime(String time, String parameter) throws DCmdException {
       
   153         if (time == null) {
       
   154             return null;
       
   155         }
    62         try {
   156         try {
    63             SafePath dumpFile = resolvePath(textPath, "Failed to dump %s");
   157             return Instant.parse(time);
    64             // create file for JVM
   158         } catch (DateTimeParseException dtp) {
    65             Utils.touch(dumpFile.toPath());
   159             // fall through
    66             PlatformRecording r = PrivateAccess.getInstance().getPlatformRecording(recording);
   160         }
    67             WriteableUserPath wup = new WriteableUserPath(dumpFile.toPath());
   161         try {
    68 
   162             LocalDateTime ldt = LocalDateTime.parse(time);
    69             Map<String, String> overlay = new HashMap<>();
   163             return ZonedDateTime.of(ldt, ZoneId.systemDefault()).toInstant();
    70             Utils.updateSettingPathToGcRoots(overlay, pathToGcRoots);
   164         } catch (DateTimeParseException dtp) {
    71 
   165             // fall through
    72             r.copyTo(wup, "Dumped by user", overlay);
   166         }
    73             reportOperationComplete("Dumped", recording, dumpFile);
   167         try {
    74         } catch (IOException | InvalidPathException e) {
   168             LocalTime lt = LocalTime.parse(time);
    75             throw new DCmdException("Failed to dump %s. Could not copy recording for dump. %s", recordingText, e.getMessage());
   169             LocalDate ld = LocalDate.now();
    76         }
   170             Instant instant = ZonedDateTime.of(ld, lt, ZoneId.systemDefault()).toInstant();
    77         return getResult();
   171             Instant now = Instant.now();
       
   172             if (instant.isAfter(now) && !instant.isBefore(now.plusSeconds(3600))) {
       
   173                 // User must have meant previous day
       
   174                 ld = ld.minusDays(1);
       
   175             }
       
   176             return ZonedDateTime.of(ld, lt, ZoneId.systemDefault()).toInstant();
       
   177         } catch (DateTimeParseException dtp) {
       
   178             // fall through
       
   179         }
       
   180 
       
   181         if (time.startsWith("-")) {
       
   182             try {
       
   183                 long durationNanos = Utils.parseTimespan(time.substring(1));
       
   184                 Duration duration = Duration.ofNanos(durationNanos);
       
   185                 return Instant.now().minus(duration);
       
   186             } catch (NumberFormatException nfe) {
       
   187                 // fall through
       
   188             }
       
   189         }
       
   190         throw new DCmdException("Dump failed, not a valid %s time.", parameter);
       
   191     }
       
   192 
       
   193     private PlatformRecording newSnapShot(PlatformRecorder recorder, Recording recording, Boolean pathToGcRoots) throws DCmdException, IOException {
       
   194         if (recording == null) {
       
   195             // Operate on all recordings
       
   196             PlatformRecording snapshot = recorder.newTemporaryRecording();
       
   197             recorder.fillWithRecordedData(snapshot, pathToGcRoots);
       
   198             return snapshot;
       
   199         }
       
   200 
       
   201         PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
       
   202         return pr.newSnapshotClone("Dumped by user", pathToGcRoots);
    78     }
   203     }
    79 
   204 
    80 }
   205 }