-
Notifications
You must be signed in to change notification settings - Fork 10
/
TmfScriptAnalysis.java
187 lines (168 loc) · 8.15 KB
/
TmfScriptAnalysis.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*******************************************************************************
* 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 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
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 static 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 {
// Historically expect files to be ready for reading during this stage.
readStateSystemsIfReady(true);
return true;
}
@SuppressWarnings("null")
private void readStateSystemsIfReady(boolean expectAlwaysReadable) {
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?
*
* Alternatively, this may happen upon an incomplete
* state-system file being read. Likely if it is
* still being created concurrently thus not ready
* for reading yet. Warn only if not expecting this.
*/
if (expectAlwaysReadable) {
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$
}
}
}
@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 despite analysis deemed as completed by now
* @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() {
// Try to always (re)read them from disk, in case they changed up there,
// off-line. Don't expect them to always be ready for reading yet
// though, as some files might still undergo building.
readStateSystemsIfReady(false);
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();
}
}