Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
e73a4ba5 | 2 | * Copyright (c) 2009, 2013 Ericsson, École Polytechnique de Montréal |
0bfb7d06 | 3 | * |
8c8bf09f ASL |
4 | * All rights reserved. This program and the accompanying materials are |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
0bfb7d06 | 8 | * |
8c8bf09f | 9 | * Contributors: |
20658947 FC |
10 | * Francois Chouinard - Initial API and implementation |
11 | * Francois Chouinard - Updated as per TMF Trace Model 1.0 | |
ea271da6 | 12 | * Patrick Tasse - Updated for removal of context clone |
e73a4ba5 GB |
13 | * Geneviève Bastien - Added timestamp transforms, its saving to file and |
14 | * timestamp creation functions | |
8c8bf09f ASL |
15 | *******************************************************************************/ |
16 | ||
6c13869b | 17 | package org.eclipse.linuxtools.tmf.core.trace; |
8c8bf09f | 18 | |
6f4a1d2b | 19 | import java.io.File; |
e73a4ba5 GB |
20 | import java.io.FileInputStream; |
21 | import java.io.FileNotFoundException; | |
22 | import java.io.FileOutputStream; | |
23 | import java.io.IOException; | |
24 | import java.io.ObjectInputStream; | |
25 | import java.io.ObjectOutputStream; | |
35c160d9 AM |
26 | import java.util.Collections; |
27 | import java.util.LinkedHashMap; | |
a51b2b9f | 28 | import java.util.Map; |
8c8bf09f | 29 | |
e73a4ba5 | 30 | import org.eclipse.core.resources.IFolder; |
828e5592 | 31 | import org.eclipse.core.resources.IResource; |
faa38350 | 32 | import org.eclipse.core.runtime.CoreException; |
42459d24 | 33 | import org.eclipse.core.runtime.IStatus; |
b22a582a | 34 | import org.eclipse.core.runtime.MultiStatus; |
032ecd45 | 35 | import org.eclipse.core.runtime.Path; |
42459d24 | 36 | import org.eclipse.core.runtime.Status; |
b22a582a | 37 | import org.eclipse.linuxtools.internal.tmf.core.Activator; |
e73a4ba5 | 38 | import org.eclipse.linuxtools.tmf.core.TmfCommonConstants; |
6c13869b | 39 | import org.eclipse.linuxtools.tmf.core.component.TmfEventProvider; |
72f1e62a | 40 | import org.eclipse.linuxtools.tmf.core.event.ITmfEvent; |
b4f71e4a | 41 | import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException; |
5419a136 AM |
42 | import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest; |
43 | import org.eclipse.linuxtools.tmf.core.request.ITmfEventRequest; | |
faa38350 | 44 | import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler; |
fec1ac0b | 45 | import org.eclipse.linuxtools.tmf.core.signal.TmfSignalManager; |
faa38350 PT |
46 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceOpenedSignal; |
47 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceRangeUpdatedSignal; | |
032ecd45 | 48 | import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal; |
7898bb21 | 49 | import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem; |
200789b3 | 50 | import org.eclipse.linuxtools.tmf.core.statistics.ITmfStatistics; |
1c0de632 | 51 | import org.eclipse.linuxtools.tmf.core.statistics.TmfStateStatistics; |
e73a4ba5 GB |
52 | import org.eclipse.linuxtools.tmf.core.synchronization.ITmfTimestampTransform; |
53 | import org.eclipse.linuxtools.tmf.core.synchronization.TmfTimestampTransform; | |
3bd46eef AM |
54 | import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp; |
55 | import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange; | |
56 | import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp; | |
a3db8436 AM |
57 | import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfTraceIndexer; |
58 | import org.eclipse.linuxtools.tmf.core.trace.indexer.checkpoint.TmfCheckpointIndexer; | |
59 | import org.eclipse.linuxtools.tmf.core.trace.location.ITmfLocation; | |
8c8bf09f ASL |
60 | |
61 | /** | |
09e86496 FC |
62 | * Abstract implementation of ITmfTrace. |
63 | * <p> | |
13cb5f43 FC |
64 | * Since the concept of 'location' is trace specific, the concrete classes have |
65 | * to provide the related methods, namely: | |
66 | * <ul> | |
67 | * <li> public ITmfLocation<?> getCurrentLocation() | |
68 | * <li> public double getLocationRatio(ITmfLocation<?> location) | |
69 | * <li> public ITmfContext seekEvent(ITmfLocation<?> location) | |
70 | * <li> public ITmfContext seekEvent(double ratio) | |
da1a4b39 | 71 | * <li> public IStatus validate(IProject project, String path) |
13cb5f43 FC |
72 | * </ul> |
73 | * A concrete trace must provide its corresponding parser. A common way to | |
74 | * accomplish this is by making the concrete class extend TmfTrace and | |
75 | * implement ITmfEventParser. | |
76 | * <p> | |
77 | * The concrete class can either specify its own indexer or use the provided | |
78 | * TmfCheckpointIndexer (default). In this case, the trace cache size will be | |
79 | * used as checkpoint interval. | |
0bfb7d06 | 80 | * |
f7703ed6 FC |
81 | * @version 1.0 |
82 | * @author Francois Chouinard | |
83 | * | |
f7703ed6 FC |
84 | * @see ITmfEvent |
85 | * @see ITmfTraceIndexer | |
86 | * @see ITmfEventParser | |
8c8bf09f | 87 | */ |
6256d8ad | 88 | public abstract class TmfTrace extends TmfEventProvider implements ITmfTrace { |
62d1696a | 89 | |
e31e01e8 | 90 | // ------------------------------------------------------------------------ |
8c8bf09f | 91 | // Attributes |
e31e01e8 | 92 | // ------------------------------------------------------------------------ |
8c8bf09f | 93 | |
09e86496 FC |
94 | // The resource used for persistent properties for this trace |
95 | private IResource fResource; | |
96 | ||
b0a282fb | 97 | // The trace path |
12c155f5 | 98 | private String fPath; |
b0a282fb | 99 | |
0316808c FC |
100 | // The trace cache page size |
101 | private int fCacheSize = ITmfTrace.DEFAULT_TRACE_CACHE_SIZE; | |
62d1696a | 102 | |
0316808c FC |
103 | // The number of events collected (so far) |
104 | private long fNbEvents = 0; | |
62d1696a FC |
105 | |
106 | // The time span of the event stream | |
9cbe7899 | 107 | private ITmfTimestamp fStartTime = TmfTimestamp.BIG_BANG; |
a4115405 | 108 | private ITmfTimestamp fEndTime = TmfTimestamp.BIG_BANG; |
62d1696a | 109 | |
0316808c FC |
110 | // The trace streaming interval (0 = no streaming) |
111 | private long fStreamingInterval = 0; | |
085d898f | 112 | |
0316808c | 113 | // The trace indexer |
6256d8ad | 114 | private ITmfTraceIndexer fIndexer; |
20658947 | 115 | |
0316808c | 116 | // The trace parser |
6256d8ad | 117 | private ITmfEventParser fParser; |
7e6347b0 | 118 | |
200789b3 AM |
119 | // The trace's statistics |
120 | private ITmfStatistics fStatistics; | |
121 | ||
a51b2b9f AM |
122 | /** |
123 | * The collection of state systems that are registered with this trace. Each | |
124 | * sub-class can decide to add its (one or many) state system to this map | |
125 | * during their {@link #buildStateSystem()}. | |
126 | * | |
127 | * @since 2.0 | |
128 | */ | |
129 | protected final Map<String, ITmfStateSystem> fStateSystems = | |
35c160d9 | 130 | new LinkedHashMap<String, ITmfStateSystem>(); |
a51b2b9f | 131 | |
e73a4ba5 GB |
132 | private ITmfTimestampTransform fTsTransform; |
133 | ||
134 | private static final String SYNCHRONIZATION_FORMULA_FILE = "sync_formula"; //$NON-NLS-1$ | |
135 | ||
e31e01e8 | 136 | // ------------------------------------------------------------------------ |
3791b5df | 137 | // Construction |
e31e01e8 | 138 | // ------------------------------------------------------------------------ |
8c8bf09f | 139 | |
62d1696a | 140 | /** |
3791b5df | 141 | * The default, parameterless, constructor |
62d1696a | 142 | */ |
3791b5df FC |
143 | public TmfTrace() { |
144 | super(); | |
05bd3318 FC |
145 | } |
146 | ||
147 | /** | |
8cf330ae | 148 | * Full constructor. |
0bfb7d06 | 149 | * |
8cf330ae AM |
150 | * @param resource |
151 | * The resource associated to the trace | |
152 | * @param type | |
153 | * The type of events that will be read from this trace | |
154 | * @param path | |
155 | * The path to the trace on the filesystem | |
156 | * @param cacheSize | |
157 | * The trace cache size. Pass '-1' to use the default specified | |
158 | * in {@link ITmfTrace#DEFAULT_TRACE_CACHE_SIZE} | |
159 | * @param interval | |
160 | * The trace streaming interval. You can use '0' for post-mortem | |
161 | * traces. | |
162 | * @param indexer | |
163 | * The trace indexer. You can pass 'null' to use a default | |
164 | * checkpoint indexer. | |
165 | * @param parser | |
166 | * The trace event parser. Use 'null' if (and only if) the trace | |
167 | * object itself is also the ITmfEventParser to be used. | |
168 | * @throws TmfTraceException | |
169 | * If something failed during the opening | |
20658947 | 170 | */ |
8cf330ae AM |
171 | protected TmfTrace(final IResource resource, |
172 | final Class<? extends ITmfEvent> type, | |
173 | final String path, | |
174 | final int cacheSize, | |
175 | final long interval, | |
176 | final ITmfTraceIndexer indexer, | |
177 | final ITmfEventParser parser) | |
178 | throws TmfTraceException { | |
00641a97 | 179 | super(); |
0316808c | 180 | fCacheSize = (cacheSize > 0) ? cacheSize : ITmfTrace.DEFAULT_TRACE_CACHE_SIZE; |
3791b5df | 181 | fStreamingInterval = interval; |
13cb5f43 | 182 | fParser = parser; |
032ecd45 | 183 | fIndexer = indexer; |
09e86496 | 184 | initialize(resource, path, type); |
8c8bf09f ASL |
185 | } |
186 | ||
3791b5df FC |
187 | /** |
188 | * Copy constructor | |
0bfb7d06 | 189 | * |
3791b5df | 190 | * @param trace the original trace |
063f0d27 | 191 | * @throws TmfTraceException Should not happen usually |
3791b5df | 192 | */ |
6256d8ad | 193 | public TmfTrace(final TmfTrace trace) throws TmfTraceException { |
3791b5df | 194 | super(); |
0316808c | 195 | if (trace == null) { |
3791b5df | 196 | throw new IllegalArgumentException(); |
0316808c | 197 | } |
20658947 FC |
198 | fCacheSize = trace.getCacheSize(); |
199 | fStreamingInterval = trace.getStreamingInterval(); | |
13cb5f43 FC |
200 | fParser = trace.fParser; |
201 | initialize(trace.getResource(), trace.getPath(), trace.getEventType()); | |
3791b5df FC |
202 | } |
203 | ||
032ecd45 MAL |
204 | /** |
205 | * Creates the indexer instance. Classes extending this class can override | |
206 | * this to provide a different indexer implementation. | |
207 | * | |
208 | * @param interval the checkpoints interval | |
209 | * | |
210 | * @return the indexer | |
211 | * @since 3.0 | |
212 | */ | |
213 | protected ITmfTraceIndexer createIndexer(int interval) { | |
214 | return new TmfCheckpointIndexer(this, interval); | |
215 | } | |
216 | ||
7e6347b0 FC |
217 | // ------------------------------------------------------------------------ |
218 | // ITmfTrace - Initializers | |
219 | // ------------------------------------------------------------------------ | |
220 | ||
7e6347b0 | 221 | @Override |
6256d8ad | 222 | public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> type) throws TmfTraceException { |
7e6347b0 | 223 | initialize(resource, path, type); |
7e6347b0 FC |
224 | } |
225 | ||
09e86496 | 226 | /** |
1703b536 | 227 | * Initialize the trace common attributes and the base component. |
0bfb7d06 MK |
228 | * |
229 | * @param resource the Eclipse resource (trace) | |
1703b536 FC |
230 | * @param path the trace path |
231 | * @param type the trace event type | |
0bfb7d06 | 232 | * |
6f4e8ec0 | 233 | * @throws TmfTraceException If something failed during the initialization |
3791b5df | 234 | */ |
248af329 AM |
235 | protected void initialize(final IResource resource, |
236 | final String path, | |
237 | final Class<? extends ITmfEvent> type) | |
238 | throws TmfTraceException { | |
0316808c | 239 | if (path == null) { |
b4f71e4a | 240 | throw new TmfTraceException("Invalid trace path"); //$NON-NLS-1$ |
0316808c | 241 | } |
3791b5df | 242 | fPath = path; |
1703b536 | 243 | fResource = resource; |
25e48683 | 244 | String traceName = (resource != null) ? resource.getName() : null; |
1703b536 FC |
245 | // If no resource was provided, extract the display name the trace path |
246 | if (traceName == null) { | |
032ecd45 | 247 | traceName = new Path(path).lastSegment(); |
1703b536 | 248 | } |
2352aed9 FC |
249 | if (fParser == null) { |
250 | if (this instanceof ITmfEventParser) { | |
6256d8ad | 251 | fParser = (ITmfEventParser) this; |
2352aed9 FC |
252 | } else { |
253 | throw new TmfTraceException("Invalid trace parser"); //$NON-NLS-1$ | |
254 | } | |
255 | } | |
3791b5df | 256 | super.init(traceName, type); |
fec1ac0b BH |
257 | // register as VIP after super.init() because TmfComponent registers to signal manager there |
258 | TmfSignalManager.registerVIP(this); | |
032ecd45 MAL |
259 | if (fIndexer == null) { |
260 | fIndexer = createIndexer(fCacheSize); | |
261 | } | |
3791b5df FC |
262 | } |
263 | ||
2352aed9 FC |
264 | /** |
265 | * Indicates if the path points to an existing file/directory | |
0bfb7d06 | 266 | * |
2352aed9 FC |
267 | * @param path the path to test |
268 | * @return true if the file/directory exists | |
3791b5df | 269 | */ |
2352aed9 | 270 | protected boolean fileExists(final String path) { |
085d898f | 271 | final File file = new File(path); |
3791b5df FC |
272 | return file.exists(); |
273 | } | |
274 | ||
c7e1020d | 275 | /** |
51e75066 | 276 | * @since 2.0 |
c7e1020d | 277 | */ |
51e75066 AM |
278 | @Override |
279 | public void indexTrace(boolean waitForCompletion) { | |
9e0640dc | 280 | getIndexer().buildIndex(0, TmfTimeRange.ETERNITY, waitForCompletion); |
c7e1020d FC |
281 | } |
282 | ||
200789b3 | 283 | /** |
6f4e8ec0 | 284 | * The default implementation of TmfTrace uses a TmfStatistics back-end. |
200789b3 AM |
285 | * Override this if you want to specify another type (or none at all). |
286 | * | |
b22a582a AM |
287 | * @return An IStatus indicating if the statistics could be built |
288 | * successfully or not. | |
289 | * @since 3.0 | |
200789b3 | 290 | */ |
b22a582a | 291 | protected IStatus buildStatistics() { |
200789b3 AM |
292 | /* |
293 | * Initialize the statistics provider, but only if a Resource has been | |
294 | * set (so we don't build it for experiments, for unit tests, etc.) | |
295 | */ | |
b22a582a AM |
296 | try { |
297 | fStatistics = (fResource == null ? null : new TmfStateStatistics(this) ); | |
298 | } catch (TmfTraceException e) { | |
299 | return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getMessage(), e); | |
300 | } | |
301 | return Status.OK_STATUS; | |
200789b3 AM |
302 | } |
303 | ||
faa38350 PT |
304 | /** |
305 | * Build the state system(s) associated with this trace type. | |
306 | * | |
42459d24 AM |
307 | * @return An IStatus indicating if the state system could be build |
308 | * successfully or not. | |
309 | * @since 3.0 | |
faa38350 | 310 | */ |
42459d24 | 311 | protected IStatus buildStateSystem() { |
faa38350 PT |
312 | /* |
313 | * Nothing is done in the base implementation, please specify | |
a51b2b9f | 314 | * how/if to register a new state system in derived classes. |
faa38350 | 315 | */ |
42459d24 | 316 | return Status.OK_STATUS; |
faa38350 PT |
317 | } |
318 | ||
b5ee6881 FC |
319 | /** |
320 | * Clears the trace | |
321 | */ | |
322 | @Override | |
323 | public synchronized void dispose() { | |
1a4205d9 | 324 | /* Clean up the index if applicable */ |
77551cc2 FC |
325 | if (getIndexer() != null) { |
326 | getIndexer().dispose(); | |
327 | } | |
1a4205d9 AM |
328 | |
329 | /* Clean up the statistics */ | |
330 | if (fStatistics != null) { | |
331 | fStatistics.dispose(); | |
332 | } | |
a51b2b9f AM |
333 | |
334 | /* Clean up the state systems */ | |
335 | for (ITmfStateSystem ss : fStateSystems.values()) { | |
336 | ss.dispose(); | |
337 | } | |
338 | ||
b5ee6881 FC |
339 | super.dispose(); |
340 | } | |
341 | ||
3791b5df | 342 | // ------------------------------------------------------------------------ |
09e86496 | 343 | // ITmfTrace - Basic getters |
e31e01e8 | 344 | // ------------------------------------------------------------------------ |
8c8bf09f | 345 | |
25e48683 | 346 | @Override |
6256d8ad AM |
347 | public Class<ITmfEvent> getEventType() { |
348 | return (Class<ITmfEvent>) super.getType(); | |
25e48683 FC |
349 | } |
350 | ||
d4011df2 | 351 | @Override |
09e86496 FC |
352 | public IResource getResource() { |
353 | return fResource; | |
8c8bf09f ASL |
354 | } |
355 | ||
d4011df2 | 356 | @Override |
09e86496 FC |
357 | public String getPath() { |
358 | return fPath; | |
8c8bf09f ASL |
359 | } |
360 | ||
20658947 FC |
361 | @Override |
362 | public int getCacheSize() { | |
363 | return fCacheSize; | |
364 | } | |
365 | ||
20658947 FC |
366 | @Override |
367 | public long getStreamingInterval() { | |
368 | return fStreamingInterval; | |
369 | } | |
370 | ||
0316808c FC |
371 | /** |
372 | * @return the trace indexer | |
a3db8436 | 373 | * @since 3.0 |
0316808c | 374 | */ |
6256d8ad | 375 | protected ITmfTraceIndexer getIndexer() { |
0316808c FC |
376 | return fIndexer; |
377 | } | |
378 | ||
379 | /** | |
380 | * @return the trace parser | |
381 | */ | |
6256d8ad | 382 | protected ITmfEventParser getParser() { |
0316808c FC |
383 | return fParser; |
384 | } | |
385 | ||
200789b3 AM |
386 | /** |
387 | * @since 2.0 | |
388 | */ | |
389 | @Override | |
390 | public ITmfStatistics getStatistics() { | |
391 | return fStatistics; | |
392 | } | |
393 | ||
7898bb21 AM |
394 | /** |
395 | * @since 2.0 | |
396 | */ | |
397 | @Override | |
35c160d9 AM |
398 | public final Map<String, ITmfStateSystem> getStateSystems() { |
399 | return Collections.unmodifiableMap(fStateSystems); | |
7898bb21 AM |
400 | } |
401 | ||
6c5e0863 AM |
402 | /** |
403 | * @since 2.0 | |
404 | */ | |
405 | @Override | |
406 | public final void registerStateSystem(String id, ITmfStateSystem ss) { | |
407 | fStateSystems.put(id, ss); | |
408 | } | |
409 | ||
09e86496 FC |
410 | // ------------------------------------------------------------------------ |
411 | // ITmfTrace - Trace characteristics getters | |
412 | // ------------------------------------------------------------------------ | |
413 | ||
d4011df2 | 414 | @Override |
5419a136 | 415 | public synchronized long getNbEvents() { |
3791b5df | 416 | return fNbEvents; |
b0a282fb FC |
417 | } |
418 | ||
3bd46eef AM |
419 | /** |
420 | * @since 2.0 | |
62d1696a | 421 | */ |
d4011df2 | 422 | @Override |
12c155f5 | 423 | public TmfTimeRange getTimeRange() { |
cb866e08 | 424 | return new TmfTimeRange(fStartTime, fEndTime); |
8c8bf09f ASL |
425 | } |
426 | ||
3bd46eef AM |
427 | /** |
428 | * @since 2.0 | |
e31e01e8 | 429 | */ |
d4011df2 | 430 | @Override |
4df4581d | 431 | public ITmfTimestamp getStartTime() { |
4593bd5b | 432 | return fStartTime; |
146a887c FC |
433 | } |
434 | ||
3bd46eef AM |
435 | /** |
436 | * @since 2.0 | |
e31e01e8 | 437 | */ |
d4011df2 | 438 | @Override |
4df4581d | 439 | public ITmfTimestamp getEndTime() { |
4593bd5b | 440 | return fEndTime; |
20658947 FC |
441 | } |
442 | ||
d7ee91bb | 443 | /** |
d7ee91bb PT |
444 | * @since 2.0 |
445 | */ | |
66262ad8 BH |
446 | @Override |
447 | public ITmfTimestamp getInitialRangeOffset() { | |
d7ee91bb PT |
448 | final long DEFAULT_INITIAL_OFFSET_VALUE = (1L * 100 * 1000 * 1000); // .1sec |
449 | return new TmfTimestamp(DEFAULT_INITIAL_OFFSET_VALUE, ITmfTimestamp.NANOSECOND_SCALE); | |
450 | } | |
451 | ||
bb52f9bc GB |
452 | /** |
453 | * @since 3.0 | |
454 | */ | |
455 | @Override | |
456 | public String getHostId() { | |
457 | return this.getName(); | |
458 | } | |
459 | ||
20658947 | 460 | // ------------------------------------------------------------------------ |
d7ee91bb | 461 | // Convenience setters |
20658947 FC |
462 | // ------------------------------------------------------------------------ |
463 | ||
0316808c FC |
464 | /** |
465 | * Set the trace cache size. Must be done at initialization time. | |
0bfb7d06 | 466 | * |
0316808c FC |
467 | * @param cacheSize The trace cache size |
468 | */ | |
469 | protected void setCacheSize(final int cacheSize) { | |
470 | fCacheSize = cacheSize; | |
471 | } | |
472 | ||
473 | /** | |
474 | * Set the trace known number of events. This can be quite dynamic | |
475 | * during indexing or for live traces. | |
0bfb7d06 | 476 | * |
0316808c FC |
477 | * @param nbEvents The number of events |
478 | */ | |
479 | protected synchronized void setNbEvents(final long nbEvents) { | |
480 | fNbEvents = (nbEvents > 0) ? nbEvents : 0; | |
481 | } | |
482 | ||
20658947 FC |
483 | /** |
484 | * Update the trace events time range | |
0bfb7d06 | 485 | * |
20658947 | 486 | * @param range the new time range |
3bd46eef | 487 | * @since 2.0 |
20658947 FC |
488 | */ |
489 | protected void setTimeRange(final TmfTimeRange range) { | |
4593bd5b AM |
490 | fStartTime = range.getStartTime(); |
491 | fEndTime = range.getEndTime(); | |
20658947 FC |
492 | } |
493 | ||
494 | /** | |
495 | * Update the trace chronologically first event timestamp | |
0bfb7d06 | 496 | * |
20658947 | 497 | * @param startTime the new first event timestamp |
3bd46eef | 498 | * @since 2.0 |
20658947 FC |
499 | */ |
500 | protected void setStartTime(final ITmfTimestamp startTime) { | |
4593bd5b | 501 | fStartTime = startTime; |
20658947 FC |
502 | } |
503 | ||
504 | /** | |
505 | * Update the trace chronologically last event timestamp | |
0bfb7d06 | 506 | * |
20658947 | 507 | * @param endTime the new last event timestamp |
3bd46eef | 508 | * @since 2.0 |
20658947 FC |
509 | */ |
510 | protected void setEndTime(final ITmfTimestamp endTime) { | |
4593bd5b | 511 | fEndTime = endTime; |
20658947 FC |
512 | } |
513 | ||
514 | /** | |
0316808c | 515 | * Set the polling interval for live traces (default = 0 = no streaming). |
0bfb7d06 | 516 | * |
20658947 FC |
517 | * @param interval the new trace streaming interval |
518 | */ | |
519 | protected void setStreamingInterval(final long interval) { | |
1703b536 | 520 | fStreamingInterval = (interval > 0) ? interval : 0; |
146a887c FC |
521 | } |
522 | ||
0316808c FC |
523 | /** |
524 | * Set the trace indexer. Must be done at initialization time. | |
0bfb7d06 | 525 | * |
0316808c | 526 | * @param indexer the trace indexer |
a3db8436 | 527 | * @since 3.0 |
0316808c | 528 | */ |
6256d8ad | 529 | protected void setIndexer(final ITmfTraceIndexer indexer) { |
0316808c FC |
530 | fIndexer = indexer; |
531 | } | |
532 | ||
533 | /** | |
534 | * Set the trace parser. Must be done at initialization time. | |
0bfb7d06 | 535 | * |
0316808c FC |
536 | * @param parser the new trace parser |
537 | */ | |
6256d8ad | 538 | protected void setParser(final ITmfEventParser parser) { |
0316808c FC |
539 | fParser = parser; |
540 | } | |
541 | ||
09e86496 | 542 | // ------------------------------------------------------------------------ |
7e6347b0 | 543 | // ITmfTrace - SeekEvent operations (returning a trace context) |
09e86496 FC |
544 | // ------------------------------------------------------------------------ |
545 | ||
1b70b6dc | 546 | @Override |
7e6347b0 | 547 | public synchronized ITmfContext seekEvent(final long rank) { |
09e86496 | 548 | |
7e6347b0 | 549 | // A rank <= 0 indicates to seek the first event |
2352aed9 | 550 | if (rank <= 0) { |
1e1bef82 | 551 | ITmfContext context = seekEvent((ITmfLocation) null); |
2352aed9 FC |
552 | context.setRank(0); |
553 | return context; | |
554 | } | |
09e86496 | 555 | |
09e86496 | 556 | // Position the trace at the checkpoint |
7e6347b0 | 557 | final ITmfContext context = fIndexer.seekIndex(rank); |
09e86496 FC |
558 | |
559 | // And locate the requested event context | |
7e6347b0 FC |
560 | long pos = context.getRank(); |
561 | if (pos < rank) { | |
c32744d6 | 562 | ITmfEvent event = getNext(context); |
0bfb7d06 | 563 | while ((event != null) && (++pos < rank)) { |
c32744d6 | 564 | event = getNext(context); |
7e6347b0 | 565 | } |
09e86496 FC |
566 | } |
567 | return context; | |
1b70b6dc PT |
568 | } |
569 | ||
3bd46eef AM |
570 | /** |
571 | * @since 2.0 | |
09e86496 FC |
572 | */ |
573 | @Override | |
7e6347b0 | 574 | public synchronized ITmfContext seekEvent(final ITmfTimestamp timestamp) { |
09e86496 | 575 | |
7e6347b0 | 576 | // A null timestamp indicates to seek the first event |
2352aed9 | 577 | if (timestamp == null) { |
1e1bef82 | 578 | ITmfContext context = seekEvent((ITmfLocation) null); |
2352aed9 FC |
579 | context.setRank(0); |
580 | return context; | |
581 | } | |
09e86496 | 582 | |
1703b536 | 583 | // Position the trace at the checkpoint |
408e65d2 | 584 | ITmfContext context = fIndexer.seekIndex(timestamp); |
09e86496 FC |
585 | |
586 | // And locate the requested event context | |
ea271da6 PT |
587 | ITmfLocation previousLocation = context.getLocation(); |
588 | long previousRank = context.getRank(); | |
589 | ITmfEvent event = getNext(context); | |
7e6347b0 | 590 | while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) { |
ea271da6 PT |
591 | previousLocation = context.getLocation(); |
592 | previousRank = context.getRank(); | |
593 | event = getNext(context); | |
09e86496 | 594 | } |
0316808c FC |
595 | if (event == null) { |
596 | context.setLocation(null); | |
597 | context.setRank(ITmfContext.UNKNOWN_RANK); | |
ea271da6 PT |
598 | } else { |
599 | context.dispose(); | |
600 | context = seekEvent(previousLocation); | |
601 | context.setRank(previousRank); | |
0316808c | 602 | } |
09e86496 FC |
603 | return context; |
604 | } | |
0283f7ff | 605 | |
09e86496 FC |
606 | // ------------------------------------------------------------------------ |
607 | // ITmfTrace - Read operations (returning an actual event) | |
608 | // ------------------------------------------------------------------------ | |
609 | ||
d4011df2 | 610 | @Override |
6256d8ad | 611 | public synchronized ITmfEvent getNext(final ITmfContext context) { |
09e86496 | 612 | // parseEvent() does not update the context |
6256d8ad | 613 | final ITmfEvent event = fParser.parseEvent(context); |
09e86496 | 614 | if (event != null) { |
d337369a | 615 | updateAttributes(context, event.getTimestamp()); |
09e86496 FC |
616 | context.setLocation(getCurrentLocation()); |
617 | context.increaseRank(); | |
618 | processEvent(event); | |
619 | } | |
620 | return event; | |
621 | } | |
622 | ||
623 | /** | |
d337369a | 624 | * Hook for special event processing by the concrete class |
7e6347b0 | 625 | * (called by TmfTrace.getEvent()) |
0bfb7d06 | 626 | * |
d337369a | 627 | * @param event the event |
09e86496 FC |
628 | */ |
629 | protected void processEvent(final ITmfEvent event) { | |
d337369a | 630 | // Do nothing |
09e86496 FC |
631 | } |
632 | ||
d337369a FC |
633 | /** |
634 | * Update the trace attributes | |
0bfb7d06 | 635 | * |
d337369a | 636 | * @param context the current trace context |
2848c377 | 637 | * @param timestamp the corresponding timestamp |
3bd46eef | 638 | * @since 2.0 |
d337369a FC |
639 | */ |
640 | protected synchronized void updateAttributes(final ITmfContext context, final ITmfTimestamp timestamp) { | |
0bfb7d06 | 641 | if (fStartTime.equals(TmfTimestamp.BIG_BANG) || (fStartTime.compareTo(timestamp, false) > 0)) { |
4593bd5b | 642 | fStartTime = timestamp; |
09e86496 | 643 | } |
0bfb7d06 | 644 | if (fEndTime.equals(TmfTimestamp.BIG_CRUNCH) || (fEndTime.compareTo(timestamp, false) < 0)) { |
4593bd5b | 645 | fEndTime = timestamp; |
09e86496 FC |
646 | } |
647 | if (context.hasValidRank()) { | |
d337369a | 648 | long rank = context.getRank(); |
09e86496 FC |
649 | if (fNbEvents <= rank) { |
650 | fNbEvents = rank + 1; | |
651 | } | |
200789b3 AM |
652 | if (fIndexer != null) { |
653 | fIndexer.updateIndex(context, timestamp); | |
654 | } | |
09e86496 | 655 | } |
abfad0aa FC |
656 | } |
657 | ||
3791b5df | 658 | // ------------------------------------------------------------------------ |
d337369a | 659 | // TmfDataProvider |
3791b5df FC |
660 | // ------------------------------------------------------------------------ |
661 | ||
77c4a6df AM |
662 | /** |
663 | * @since 2.0 | |
d337369a | 664 | */ |
3791b5df | 665 | @Override |
5419a136 | 666 | public synchronized ITmfContext armRequest(final ITmfDataRequest request) { |
faa38350 PT |
667 | if (executorIsShutdown()) { |
668 | return null; | |
669 | } | |
5419a136 AM |
670 | if ((request instanceof ITmfEventRequest) |
671 | && !TmfTimestamp.BIG_BANG.equals(((ITmfEventRequest) request).getRange().getStartTime()) | |
672 | && (request.getIndex() == 0)) | |
673 | { | |
674 | final ITmfContext context = seekEvent(((ITmfEventRequest) request).getRange().getStartTime()); | |
675 | ((ITmfEventRequest) request).setStartIndex((int) context.getRank()); | |
8584dc20 | 676 | return context; |
8584dc20 | 677 | |
5419a136 AM |
678 | } |
679 | return seekEvent(request.getIndex()); | |
3791b5df FC |
680 | } |
681 | ||
faa38350 PT |
682 | // ------------------------------------------------------------------------ |
683 | // Signal handlers | |
684 | // ------------------------------------------------------------------------ | |
685 | ||
686 | /** | |
687 | * Handler for the Trace Opened signal | |
688 | * | |
689 | * @param signal | |
690 | * The incoming signal | |
691 | * @since 2.0 | |
692 | */ | |
693 | @TmfSignalHandler | |
694 | public void traceOpened(TmfTraceOpenedSignal signal) { | |
b9a5bf8f AM |
695 | boolean signalIsForUs = false; |
696 | for (ITmfTrace trace : TmfTraceManager.getTraceSet(signal.getTrace())) { | |
697 | if (trace == this) { | |
698 | signalIsForUs = true; | |
fe0c44c4 | 699 | break; |
faa38350 PT |
700 | } |
701 | } | |
faa38350 | 702 | |
b9a5bf8f | 703 | if (!signalIsForUs) { |
fe0c44c4 AM |
704 | return; |
705 | } | |
706 | ||
707 | /* | |
b9a5bf8f | 708 | * The signal is either for this trace, or for an experiment containing |
fe0c44c4 AM |
709 | * this trace. |
710 | */ | |
b22a582a AM |
711 | MultiStatus status = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, null, null); |
712 | status.add(buildStatistics()); | |
713 | status.add(buildStateSystem()); | |
714 | if (!status.isOK()) { | |
715 | Activator.log(status); | |
fe0c44c4 AM |
716 | } |
717 | ||
718 | /* Refresh the project, so it can pick up new files that got created. */ | |
719 | try { | |
720 | if (fResource != null) { | |
721 | fResource.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); | |
faa38350 | 722 | } |
fe0c44c4 AM |
723 | } catch (CoreException e) { |
724 | e.printStackTrace(); | |
faa38350 | 725 | } |
fe0c44c4 | 726 | |
faa38350 | 727 | if (signal.getTrace() == this) { |
f8fc4a3a | 728 | /* Additionally, the signal is directly for this trace. */ |
faa38350 PT |
729 | if (getNbEvents() == 0) { |
730 | return; | |
731 | } | |
732 | ||
f8fc4a3a PT |
733 | /* For a streaming trace, the range updated signal should be sent |
734 | * by the subclass when a new safe time is determined. | |
735 | */ | |
736 | if (getStreamingInterval() > 0) { | |
737 | return; | |
738 | } | |
739 | ||
faa38350 PT |
740 | final TmfTimeRange timeRange = new TmfTimeRange(getStartTime(), TmfTimestamp.BIG_CRUNCH); |
741 | final TmfTraceRangeUpdatedSignal rangeUpdatedsignal = new TmfTraceRangeUpdatedSignal(this, this, timeRange); | |
742 | ||
743 | // Broadcast in separate thread to prevent deadlock | |
744 | new Thread() { | |
745 | @Override | |
746 | public void run() { | |
747 | broadcast(rangeUpdatedsignal); | |
748 | } | |
749 | }.start(); | |
750 | return; | |
751 | } | |
752 | } | |
753 | ||
754 | /** | |
755 | * Signal handler for the TmfTraceRangeUpdatedSignal signal | |
756 | * | |
757 | * @param signal The incoming signal | |
758 | * @since 2.0 | |
759 | */ | |
760 | @TmfSignalHandler | |
761 | public void traceRangeUpdated(final TmfTraceRangeUpdatedSignal signal) { | |
762 | if (signal.getTrace() == this) { | |
763 | getIndexer().buildIndex(getNbEvents(), signal.getRange(), false); | |
764 | } | |
765 | } | |
766 | ||
032ecd45 MAL |
767 | /** |
768 | * Signal handler for the TmfTraceUpdatedSignal signal | |
769 | * | |
770 | * @param signal The incoming signal | |
771 | * @since 2.0 | |
772 | */ | |
773 | @TmfSignalHandler | |
774 | public void traceUpdated(final TmfTraceUpdatedSignal signal) { | |
775 | if (signal.getSource() == getIndexer()) { | |
776 | fNbEvents = signal.getNbEvents(); | |
777 | fStartTime = signal.getRange().getStartTime(); | |
778 | fEndTime = signal.getRange().getEndTime(); | |
779 | } | |
780 | } | |
781 | ||
e73a4ba5 GB |
782 | /** |
783 | * Returns the file resource used to store synchronization formula. The file | |
784 | * may not exist. | |
785 | * | |
786 | * @return the synchronization file | |
787 | */ | |
788 | private File getSyncFormulaFile() { | |
789 | File file = null; | |
790 | if (fResource instanceof IFolder) { | |
791 | try { | |
792 | String supplDirectory; | |
793 | ||
794 | supplDirectory = fResource.getPersistentProperty(TmfCommonConstants.TRACE_SUPPLEMENTARY_FOLDER); | |
795 | ||
796 | file = new File(supplDirectory + File.separator + SYNCHRONIZATION_FORMULA_FILE); | |
797 | ||
798 | } catch (CoreException e) { | |
799 | ||
800 | } | |
801 | } | |
802 | return file; | |
803 | } | |
804 | ||
805 | // ------------------------------------------------------------------------ | |
806 | // Timestamp transformation functions | |
807 | // ------------------------------------------------------------------------ | |
808 | ||
809 | /** | |
810 | * @since 3.0 | |
811 | */ | |
812 | @Override | |
813 | public ITmfTimestampTransform getTimestampTransform() { | |
814 | if (fTsTransform == null) { | |
815 | /* Check if a formula is stored somewhere in the resources */ | |
816 | File sync_file = getSyncFormulaFile(); | |
817 | if (sync_file != null && sync_file.exists()) { | |
818 | ||
819 | try { | |
820 | FileInputStream fis = new FileInputStream(sync_file); | |
821 | ObjectInputStream ois = new ObjectInputStream(fis); | |
822 | fTsTransform = (ITmfTimestampTransform) ois.readObject(); | |
823 | ||
824 | ois.close(); | |
825 | fis.close(); | |
826 | } catch (ClassNotFoundException e1) { | |
827 | fTsTransform = TmfTimestampTransform.IDENTITY; | |
828 | } catch (FileNotFoundException e1) { | |
829 | fTsTransform = TmfTimestampTransform.IDENTITY; | |
830 | } catch (IOException e1) { | |
831 | fTsTransform = TmfTimestampTransform.IDENTITY; | |
832 | } | |
833 | } else { | |
834 | fTsTransform = TmfTimestampTransform.IDENTITY; | |
835 | } | |
836 | } | |
837 | return fTsTransform; | |
838 | } | |
839 | ||
840 | /** | |
841 | * @since 3.0 | |
842 | */ | |
843 | @Override | |
844 | public void setTimestampTransform(final ITmfTimestampTransform tt) { | |
845 | fTsTransform = tt; | |
846 | ||
847 | /* Save the timestamp transform to a file */ | |
848 | File sync_file = getSyncFormulaFile(); | |
849 | if (sync_file != null) { | |
850 | if (sync_file.exists()) { | |
851 | sync_file.delete(); | |
852 | } | |
853 | FileOutputStream fos; | |
854 | ObjectOutputStream oos; | |
855 | ||
856 | /* Save the header of the file */ | |
857 | try { | |
858 | fos = new FileOutputStream(sync_file, false); | |
859 | oos = new ObjectOutputStream(fos); | |
860 | ||
861 | oos.writeObject(fTsTransform); | |
862 | oos.close(); | |
863 | fos.close(); | |
864 | } catch (IOException e1) { | |
865 | Activator.logError("Error writing timestamp transform for trace", e1); //$NON-NLS-1$ | |
866 | } | |
867 | } | |
868 | } | |
869 | ||
870 | /** | |
871 | * @since 3.0 | |
872 | */ | |
873 | @Override | |
874 | public ITmfTimestamp createTimestamp(long ts) { | |
875 | return new TmfTimestamp(getTimestampTransform().transform(ts)); | |
876 | } | |
877 | ||
3791b5df | 878 | // ------------------------------------------------------------------------ |
09e86496 | 879 | // toString |
3791b5df FC |
880 | // ------------------------------------------------------------------------ |
881 | ||
12c155f5 | 882 | @Override |
09e86496 | 883 | @SuppressWarnings("nls") |
5419a136 | 884 | public synchronized String toString() { |
20658947 FC |
885 | return "TmfTrace [fPath=" + fPath + ", fCacheSize=" + fCacheSize |
886 | + ", fNbEvents=" + fNbEvents + ", fStartTime=" + fStartTime | |
887 | + ", fEndTime=" + fEndTime + ", fStreamingInterval=" + fStreamingInterval + "]"; | |
12c155f5 FC |
888 | } |
889 | ||
8c8bf09f | 890 | } |