Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
<url>${project.parent.url}</url>

<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
6 changes: 6 additions & 0 deletions api/src/main/java/com/microsoft/gctoolkit/GCToolKit.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.microsoft.gctoolkit.aggregator.EventSource;
import com.microsoft.gctoolkit.io.DataSource;
import com.microsoft.gctoolkit.io.GCLogFile;
import com.microsoft.gctoolkit.io.LogFileReadLimitExceededException;
import com.microsoft.gctoolkit.io.RotatingGCLogFile;
import com.microsoft.gctoolkit.io.SingleGCLogFile;
import com.microsoft.gctoolkit.jvm.Diary;
Expand All @@ -16,6 +17,7 @@
import com.microsoft.gctoolkit.message.JVMEventChannel;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
Expand Down Expand Up @@ -312,6 +314,10 @@ public JavaVirtualMachine analyze(DataSource<?> dataSource) throws IOException
long start = System.currentTimeMillis();
javaVirtualMachine.analyze(filteredAggregators, jvmEventChannel, dataSourceChannel);
LOGGER.log(Level.FINE,() -> "Analysis completed in " + (System.currentTimeMillis() - start) + "ms");
} catch (LogFileReadLimitExceededException limitExceeded) {
throw limitExceeded;
} catch (UncheckedIOException uncheckedIOException) {
throw uncheckedIOException.getCause();
} catch(Throwable t) {
LOGGER.log(Level.SEVERE, "Internal Error: Cannot invoke analyze method", t);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
package com.microsoft.gctoolkit.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.Consumer;

final class BoundedLineSpliterator implements Spliterator<String> {

private static final int NO_PENDING_CHARACTER = -2;

private final BufferedReader reader;
private final int maximumLineCharacters;
private final Path path;
private final String archiveEntry;
private int pendingCharacter = NO_PENDING_CHARACTER;
private boolean closed;

BoundedLineSpliterator(
Reader reader,
int maximumLineCharacters,
Path path,
String archiveEntry) {
this.reader = new BufferedReader(reader);
this.maximumLineCharacters = maximumLineCharacters;
this.path = path;
this.archiveEntry = archiveEntry;
}

@Override
public boolean tryAdvance(Consumer<? super String> action) {

Check failure on line 37 in api/src/main/java/com/microsoft/gctoolkit/io/BoundedLineSpliterator.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 22 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=microsoft_gctoolkit&issues=AaBj9UZMhhjEdvdJIteC&open=AaBj9UZMhhjEdvdJIteC&pullRequest=587
Objects.requireNonNull(action);
if (closed) {
return false;
}

StringBuilder line = new StringBuilder(Math.min(maximumLineCharacters, 8192));
try {
while (true) {
int character = readCharacter();
if (character == -1) {
close();
if (line.length() == 0) {
return false;
}
action.accept(line.toString());
return true;
}
if (character == '\n') {
action.accept(line.toString());
return true;
}
if (character == '\r') {
int following = readCharacter();
if (following != '\n' && following != -1) {
pendingCharacter = following;
}
action.accept(line.toString());
if (following == -1) {
close();
}
return true;
}
if (line.length() == maximumLineCharacters) {
throw new LogFileReadLimitExceededException(
LogFileReadLimitExceededException.LimitType.LINE_CHARACTERS,
path,
archiveEntry,
Integer.toString(maximumLineCharacters),
Integer.toString(maximumLineCharacters + 1));
}
line.append((char) character);
}
} catch (IOException exception) {
closeAfterFailure(exception);
throw new UncheckedIOException(exception);
} catch (RuntimeException exception) {
closeAfterFailure(exception);
throw exception;
}
}

private int readCharacter() throws IOException {
if (pendingCharacter != NO_PENDING_CHARACTER) {
int character = pendingCharacter;
pendingCharacter = NO_PENDING_CHARACTER;
return character;
}
return reader.read();
}

private void closeAfterFailure(Throwable failure) {
try {
close();
} catch (IOException closeException) {
failure.addSuppressed(closeException);
}
}

void closeUnchecked() {
try {
close();
} catch (IOException exception) {
throw new UncheckedIOException(exception);
}
}

private void close() throws IOException {
if (!closed) {
closed = true;
reader.close();
}
}

@Override
public Spliterator<String> trySplit() {
return null;
}

@Override
public long estimateSize() {
return Long.MAX_VALUE;
}

@Override
public int characteristics() {
return ORDERED | NONNULL;
}
}
2 changes: 2 additions & 0 deletions api/src/main/java/com/microsoft/gctoolkit/io/DataSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public interface DataSource<T> {
* @return A stream of the data.
* @throws IOException Thrown if the data cannot be streamed,
* or an IOException is raised while streaming.
* @throws LogFileReadLimitExceededException if a log-file resource limit is exceeded during a
* lazy terminal operation
*/
Stream<T> stream() throws IOException;

Expand Down
35 changes: 28 additions & 7 deletions api/src/main/java/com/microsoft/gctoolkit/io/GCLogFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,33 @@ public abstract class GCLogFile extends FileDataSource<String> {
private Diary diary;
private TripleState unifiedFormat = TripleState.UNKNOWN;
private JavaVirtualMachine jvm = null;
private final LogFileReadLimits readLimits;

/**
* Subclass only.
* @param path The path to the GCLogFile or, in the case of rotating log files, the parent directory.
*/
protected GCLogFile(Path path) {
this(path, LogFileReadLimits.defaults());
}

/**
* Subclass only.
* @param path The path to the GCLogFile or, in the case of rotating log files, the parent directory.
* @param readLimits resource limits applied while streaming the log
*/
protected GCLogFile(Path path, LogFileReadLimits readLimits) {
super(path);
this.readLimits = Objects.requireNonNull(readLimits, "readLimits");
}

/**
* Returns the resource limits applied while streaming this log.
*
* @return immutable read limits
*/
public final LogFileReadLimits getReadLimits() {
return readLimits;
}

/**
Expand Down Expand Up @@ -96,13 +116,14 @@ private Diarizer diarizer() {
public Diary diary() throws IOException {
if ( diary == null) {
Diarizer diarizer = diarizer();
stream()
.filter(Objects::nonNull)
.map(String::trim)
.filter(s -> s.length() > 0)
.map(diarizer::diarize)
.filter(completed -> completed)
.findFirst();
try (Stream<String> lines = stream()) {
lines.filter(Objects::nonNull)
.map(String::trim)
.filter(s -> s.length() > 0)
.map(diarizer::diarize)
.filter(completed -> completed)
.findFirst();
}
this.diary = diarizer.getDiary();
}
return diary;
Expand Down
Loading
Loading