src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java
branchJEP-349-branch
changeset 57433 83e4343a6984
child 57434 216bf2e3b542
equal deleted inserted replaced
57432:ba454a26d2c1 57433:83e4343a6984
       
     1 package jdk.jfr.internal.consumer;
       
     2 
       
     3 import java.io.IOException;
       
     4 import java.nio.file.DirectoryStream;
       
     5 import java.nio.file.Files;
       
     6 import java.nio.file.Path;
       
     7 import java.util.ArrayList;
       
     8 import java.util.Collections;
       
     9 import java.util.HashMap;
       
    10 import java.util.HashSet;
       
    11 import java.util.List;
       
    12 import java.util.Map;
       
    13 import java.util.Set;
       
    14 import java.util.SortedMap;
       
    15 import java.util.TreeMap;
       
    16 
       
    17 import jdk.jfr.internal.LogLevel;
       
    18 import jdk.jfr.internal.LogTag;
       
    19 import jdk.jfr.internal.Logger;
       
    20 import jdk.jfr.internal.Repository;
       
    21 
       
    22 public final class RepositoryFiles {
       
    23     private final Path repostory;
       
    24     private final SortedMap<Long, Path> pathSet = new TreeMap<>();
       
    25     private final Map<Path, Long> pathLookup = new HashMap<>();
       
    26     private volatile boolean closed;
       
    27 
       
    28     public RepositoryFiles(Path repostory) {
       
    29         this.repostory = repostory;
       
    30     }
       
    31 
       
    32     public long getTimestamp(Path p) {
       
    33         return pathLookup.get(p);
       
    34     }
       
    35 
       
    36     public Path nextPath(long startTimeNanos) {
       
    37         while (!closed) {
       
    38             SortedMap<Long, Path> after = pathSet.tailMap(startTimeNanos);
       
    39             if (!after.isEmpty()) {
       
    40                 Path path = after.get(after.firstKey());
       
    41                 Logger.log(LogTag.JFR_SYSTEM_STREAMING, LogLevel.TRACE, "Return path " + path + " for start time nanos " + startTimeNanos);
       
    42                 return path;
       
    43             }
       
    44             try {
       
    45                 if (updatePaths(repostory)) {
       
    46                     continue;
       
    47                 }
       
    48             } catch (IOException e) {
       
    49                 Logger.log(LogTag.JFR_SYSTEM_STREAMING, LogLevel.DEBUG, "IOException during repository file scan " + e.getMessage());
       
    50                 // This can happen if a chunk is being removed
       
    51                 // between the file was discovered and an instance
       
    52                 // of an EventSet was constructed. Just ignore,
       
    53                 // and retry later.
       
    54             }
       
    55             try {
       
    56                 synchronized (pathSet) {
       
    57                     pathSet.wait(1000);
       
    58                 }
       
    59             } catch (InterruptedException e) {
       
    60                 // ignore
       
    61             }
       
    62         }
       
    63         return null;
       
    64     }
       
    65 
       
    66     private boolean updatePaths(Path repo) throws IOException {
       
    67         if (repo == null) {
       
    68             repo = Repository.getRepository().getRepositoryPath().toPath();
       
    69         }
       
    70         boolean foundNew = false;
       
    71         List<Path> added = new ArrayList<>();
       
    72         Set<Path> current = new HashSet<>();
       
    73         if (!Files.exists(repo)) {
       
    74             // Repository removed, probably due to shutdown
       
    75             return true;
       
    76         }
       
    77         try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(repo, "*.jfr")) {
       
    78             for (Path p : dirStream) {
       
    79                 if (!pathLookup.containsKey(p)) {
       
    80                     added.add(p);
       
    81                     Logger.log(LogTag.JFR_SYSTEM_STREAMING, LogLevel.DEBUG, "New file found: " + p.toAbsolutePath());
       
    82                 }
       
    83                 current.add(p);
       
    84             }
       
    85         }
       
    86         List<Path> removed = new ArrayList<>();
       
    87         for (Path p : pathLookup.keySet()) {
       
    88             if (!current.contains(p)) {
       
    89                 removed.add(p);
       
    90             }
       
    91         }
       
    92 
       
    93         for (Path remove : removed) {
       
    94             Long time = pathLookup.get(remove);
       
    95             pathSet.remove(time);
       
    96             pathLookup.remove(remove);
       
    97         }
       
    98         Collections.sort(added, (p1, p2) -> p1.compareTo(p2));
       
    99         for (Path p : added) {
       
   100             // Only add files that have a complete header
       
   101             // as the JVM may be in progress writing the file
       
   102             long size = Files.size(p);
       
   103             if (size >= ChunkHeader.HEADER_SIZE) {
       
   104                 long startNanos = readStartTime(p);
       
   105                 pathSet.put(startNanos, p);
       
   106                 pathLookup.put(p, startNanos);
       
   107                 foundNew = true;
       
   108             }
       
   109         }
       
   110         return foundNew;
       
   111     }
       
   112 
       
   113     private long readStartTime(Path p) throws IOException {
       
   114         try (RecordingInput in = new RecordingInput(p.toFile(), 100)) {
       
   115             ChunkHeader c = new ChunkHeader(in);
       
   116             return c.getStartNanos();
       
   117         }
       
   118     }
       
   119 
       
   120     public void close() {
       
   121         synchronized (pathSet) {
       
   122             this.closed = true;
       
   123             pathSet.notify();
       
   124         }
       
   125     }
       
   126 }