blob: 03f703f08914ae6b63e225873533529738916ed3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2019 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.tracecompass.incubator.internal.scripting.core.analysis;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.incubator.internal.scripting.core.Activator;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
/**
* An analysis class to encapsulate all scripted analyses and views, so that
* they are part of Trace Compass and views API.
*
* The state systems generated by this analysis are to be handled and built by
* the callers of this analysis, this only provides the state systems. It is the
* builder's responsibility to close them at appropriate time by calling
* {@link ITmfStateSystemBuilder#closeHistory(long)} method at the end of
* reading the trace.
*
* @author Geneviève Bastien
*/
public class TmfScriptAnalysis extends TmfAbstractAnalysisModule implements ITmfAnalysisModuleWithStateSystems {
/**
* ID of this analysis
*/
public static final String ID = "org.eclipse.tracecompass.incubator.scripting.analysis"; //$NON-NLS-1$
private static final String SUPP_FOLDER = "scripts"; //$NON-NLS-1$
private static final String STATE_SYSTEM_FOLDER = "stateSystem"; //$NON-NLS-1$
/*
* Size of the blocking queue to use when building a state history
*/
private final int QUEUE_SIZE = 10000;
// Save the state systems
private final Map<String, ITmfStateSystem> fStateSystems = new HashMap<>();
private Path getStateSystemFolder() {
// Get the supplementary files associated with this analysis
ITmfTrace trace = Objects.requireNonNull(getTrace());
/* All state systems should be in a supplementary folder */
String suppDir = TmfTraceManager.getSupplementaryFileDir(trace);
return Objects.requireNonNull(Paths.get(suppDir, SUPP_FOLDER, STATE_SYSTEM_FOLDER));
}
@Override
protected boolean executeAnalysis(IProgressMonitor monitor) throws TmfAnalysisException {
// Read the state systems of this analysis
Path suppFolder = getStateSystemFolder();
if (Files.exists(suppFolder)) {
try {
Files.walkFileTree(suppFolder, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, @Nullable BasicFileAttributes attrs) throws IOException {
try {
String ssid = String.valueOf(file.getFileName());
IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendExistingFile(
ssid, Objects.requireNonNull(file.toFile()), 1);
ITmfStateSystem stateSystem = StateSystemFactory.newStateSystem(backend, false);
fStateSystems.put(ssid, stateSystem);
} catch (IOException e) {
/*
* This may happen if the file is not a state
* system. A script may save other files in the
* supplementary file, like segment stores or
* internal files.
*
* TODO: Support a version ID?
*/
Activator.getInstance().logWarning("Error opening a file that should contain a state system: " + file.getFileName(), e); //$NON-NLS-1$
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
Activator.getInstance().logWarning("Uncaught error opening state system files", e); //$NON-NLS-1$
}
}
return true;
}
@Override
protected void canceling() {
// Nothing to do
}
@Override
public @Nullable ITmfStateSystem getStateSystem(String id) {
return fStateSystems.get(id);
}
/**
* Get a state system, using an existing one if already available
*
* @param id
* The ID of the state system to get
* @param useExisting
* Whether to use a pre-existing state system with that name or
* create a new one
* @return A new state system
*/
public @Nullable ITmfStateSystem getStateSystem(String id, boolean useExisting) {
ITmfStateSystem ss = fStateSystems.get(id);
if (ss != null && useExisting) {
return ss;
}
// Create a state system with that ID
try {
ITmfTrace trace = Objects.requireNonNull(getTrace());
Path ssFolder = getStateSystemFolder();
Files.createDirectories(ssFolder);
Path ssFile = Paths.get(ssFolder.toString(), id);
IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendNewFile(
id, Objects.requireNonNull(ssFile.toFile()), 1, trace.getStartTime().toNanos(), QUEUE_SIZE);
ITmfStateSystemBuilder stateSystem = StateSystemFactory.newStateSystem(backend);
fStateSystems.put(id, stateSystem);
return stateSystem;
} catch (IOException e) {
Activator.getInstance().logError("Error creating the state system", e); //$NON-NLS-1$
}
return ss;
}
@Override
public Iterable<ITmfStateSystem> getStateSystems() {
return fStateSystems.values();
}
@Override
public boolean waitForInitialization() {
// Wait for state systems to be read. Since the analysis is to just
// create the state systems, wait for the analysis to be completed
// FIXME: When the script analyses support segment stores as well, maybe
// this will need to change
return waitForCompletion();
}
}