tmf.ctf: Move each CtfIteratorManager into its own trace object
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ctf.core / src / org / eclipse / tracecompass / tmf / ctf / core / CtfTmfTrace.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Ericsson, École Polytechnique de Montréal
3 *
4 * All rights reserved. This program and the accompanying materials are made
5 * 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
8 *
9 * Contributors:
10 * Matthew Khouzam - Initial API and implementation
11 * Patrick Tasse - Updated for removal of context clone
12 * Geneviève Bastien - Added the createTimestamp function
13 *******************************************************************************/
14
15 package org.eclipse.tracecompass.tmf.ctf.core;
16
17 import java.nio.BufferOverflowException;
18 import java.nio.ByteBuffer;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import org.eclipse.core.resources.IProject;
27 import org.eclipse.core.resources.IResource;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IStatus;
30 import org.eclipse.core.runtime.Status;
31 import org.eclipse.tracecompass.ctf.core.event.CTFClock;
32 import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
33 import org.eclipse.tracecompass.ctf.core.trace.CTFReaderException;
34 import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
35 import org.eclipse.tracecompass.ctf.core.trace.CTFTraceReader;
36 import org.eclipse.tracecompass.internal.tmf.ctf.core.Activator;
37 import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
38 import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
39 import org.eclipse.tracecompass.tmf.core.event.TmfEventField;
40 import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
41 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
42 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
43 import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
44 import org.eclipse.tracecompass.tmf.core.trace.ITmfEventParser;
45 import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceProperties;
46 import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceWithPreDefinedEvents;
47 import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
48 import org.eclipse.tracecompass.tmf.core.trace.TraceValidationStatus;
49 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
50 import org.eclipse.tracecompass.tmf.core.trace.indexer.ITmfTraceIndexer;
51 import org.eclipse.tracecompass.tmf.core.trace.indexer.TmfBTreeTraceIndexer;
52 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.ITmfCheckpoint;
53 import org.eclipse.tracecompass.tmf.core.trace.indexer.checkpoint.TmfCheckpoint;
54 import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
55
56 import com.google.common.collect.ImmutableSet;
57
58 /**
59 * The CTf trace handler
60 *
61 * @version 1.0
62 * @author Matthew khouzam
63 */
64 public class CtfTmfTrace extends TmfTrace
65 implements ITmfEventParser, ITmfTraceProperties, ITmfPersistentlyIndexable,
66 ITmfTraceWithPreDefinedEvents, AutoCloseable {
67
68 // -------------------------------------------
69 // Constants
70 // -------------------------------------------
71 /**
72 * Default cache size for CTF traces
73 */
74 protected static final int DEFAULT_CACHE_SIZE = 50000;
75
76 /*
77 * The Ctf clock unique identifier field
78 */
79 private static final String CLOCK_HOST_PROPERTY = "uuid"; //$NON-NLS-1$
80 private static final int CONFIDENCE = 10;
81
82 // -------------------------------------------
83 // Fields
84 // -------------------------------------------
85
86 private final Map<String, CtfTmfEventType> fContainedEventTypes =
87 Collections.synchronizedMap(new HashMap<String, CtfTmfEventType>());
88
89 private final CtfIteratorManager fIteratorManager =
90 new CtfIteratorManager(this);
91
92 /* Reference to the CTF Trace */
93 private CTFTrace fTrace;
94
95 // -------------------------------------------
96 // TmfTrace Overrides
97 // -------------------------------------------
98 /**
99 * Method initTrace.
100 *
101 * @param resource
102 * The resource associated with this trace
103 * @param path
104 * The path to the trace file
105 * @param eventType
106 * The type of events that will be read from this trace
107 * @throws TmfTraceException
108 * If something went wrong while reading the trace
109 */
110 @Override
111 public void initTrace(final IResource resource, final String path, final Class<? extends ITmfEvent> eventType)
112 throws TmfTraceException {
113 /*
114 * Set the cache size. This has to be done before the call to super()
115 * because the super needs to know the cache size.
116 */
117 setCacheSize();
118
119 super.initTrace(resource, path, eventType);
120
121 try {
122 this.fTrace = new CTFTrace(path);
123 CtfTmfContext ctx;
124 /* Set the start and (current) end times for this trace */
125 ctx = (CtfTmfContext) seekEvent(0L);
126 CtfTmfEvent event = getNext(ctx);
127 if ((ctx.getLocation().equals(CtfIterator.NULL_LOCATION)) || (ctx.getCurrentEvent() == null)) {
128 /* Handle the case where the trace is empty */
129 this.setStartTime(TmfTimestamp.BIG_BANG);
130 } else {
131 final ITmfTimestamp curTime = event.getTimestamp();
132 this.setStartTime(curTime);
133 this.setEndTime(curTime);
134 }
135 /*
136 * Register every event type. When you call getType, it will
137 * register a trace to that type in the TmfEventTypeManager
138 */
139 try (CtfIterator iter = fIteratorManager.getIterator(ctx)) {
140 for (IEventDeclaration ied : iter.getEventDeclarations()) {
141 CtfTmfEventType ctfTmfEventType = fContainedEventTypes.get(ied.getName());
142 if (ctfTmfEventType == null) {
143 List<ITmfEventField> content = new ArrayList<>();
144 /* Should only return null the first time */
145 for (String fieldName : ied.getFields().getFieldsList()) {
146 content.add(new TmfEventField(fieldName, null, null));
147 }
148 ITmfEventField contentTree = new TmfEventField(
149 ITmfEventField.ROOT_FIELD_ID,
150 null,
151 content.toArray(new ITmfEventField[content.size()])
152 );
153
154 ctfTmfEventType = new CtfTmfEventType(ied.getName(), contentTree);
155 fContainedEventTypes.put(ctfTmfEventType.getName(), ctfTmfEventType);
156 }
157 }
158 }
159 } catch (final CTFReaderException e) {
160 /*
161 * If it failed at the init(), we can assume it's because the file
162 * was not found or was not recognized as a CTF trace. Throw into
163 * the new type of exception expected by the rest of TMF.
164 */
165 throw new TmfTraceException(e.getMessage(), e);
166 }
167 }
168
169 /**
170 * Return the iterator manager of this trace
171 *
172 * @return The iterator manager
173 */
174 public CtfIteratorManager getIteratorManager() {
175 return fIteratorManager;
176 }
177
178 @Override
179 public void close() {
180 dispose();
181 }
182
183 @Override
184 public synchronized void dispose() {
185 fIteratorManager.dispose();
186 if (fTrace != null) {
187 fTrace.close();
188 fTrace = null;
189 }
190 super.dispose();
191 }
192
193 /**
194 * {@inheritDoc}
195 * <p>
196 * The default implementation sets the confidence to 10 if the trace is a
197 * valid CTF trace.
198 */
199 @Override
200 public IStatus validate(final IProject project, final String path) {
201 IStatus status = new TraceValidationStatus(CONFIDENCE, Activator.PLUGIN_ID);
202 try (final CTFTrace temp = new CTFTrace(path);) {
203 if (!temp.majorIsSet()) {
204 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_MajorNotSet);
205 } else {
206 try (CTFTraceReader ctfTraceReader = new CTFTraceReader(temp);) {
207 if (!ctfTraceReader.hasMoreEvents()) {
208 // TODO: This will need an additional check when we
209 // support live traces
210 // because having no event is valid for a live trace
211 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_NoEvent);
212 }
213 }
214 }
215 } catch (final CTFReaderException e) {
216 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_ReadingError + ": " + e.toString()); //$NON-NLS-1$
217 } catch (final BufferOverflowException e) {
218 status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.CtfTmfTrace_ReadingError + ": " + Messages.CtfTmfTrace_BufferOverflowErrorMessage); //$NON-NLS-1$
219 }
220
221 return status;
222 }
223
224 /**
225 * Method getCurrentLocation. This is not applicable in CTF
226 *
227 * @return null, since the trace has no knowledge of the current location
228 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getCurrentLocation()
229 * @since 3.0
230 */
231 @Override
232 public ITmfLocation getCurrentLocation() {
233 return null;
234 }
235
236 /**
237 * @since 3.0
238 */
239 @Override
240 public double getLocationRatio(ITmfLocation location) {
241 final CtfLocation curLocation = (CtfLocation) location;
242 final CtfTmfContext context = new CtfTmfContext(this);
243 context.setLocation(curLocation);
244 context.seek(curLocation.getLocationInfo());
245 final CtfLocationInfo currentTime = ((CtfLocationInfo) context.getLocation().getLocationInfo());
246 final long startTime = fIteratorManager.getIterator(context).getStartTime();
247 final long endTime = fIteratorManager.getIterator(context).getEndTime();
248 return ((double) currentTime.getTimestamp() - startTime)
249 / (endTime - startTime);
250 }
251
252 /**
253 * Method seekEvent.
254 *
255 * @param location
256 * ITmfLocation<?>
257 * @return ITmfContext
258 * @since 3.0
259 */
260 @Override
261 public synchronized ITmfContext seekEvent(final ITmfLocation location) {
262 CtfLocation currentLocation = (CtfLocation) location;
263 CtfTmfContext context = new CtfTmfContext(this);
264 if (fTrace == null) {
265 context.setLocation(null);
266 context.setRank(ITmfContext.UNKNOWN_RANK);
267 return context;
268 }
269 /*
270 * The rank is set to 0 if the iterator seeks the beginning. If not, it
271 * will be set to UNKNOWN_RANK, since CTF traces don't support seeking
272 * by rank for now.
273 */
274 if (currentLocation == null) {
275 currentLocation = new CtfLocation(new CtfLocationInfo(0L, 0L));
276 context.setRank(0);
277 }
278 if (currentLocation.getLocationInfo() == CtfLocation.INVALID_LOCATION) {
279 currentLocation = new CtfLocation(getCTFTrace().getCurrentEndTime() + 1, 0L);
280 }
281 context.setLocation(currentLocation);
282 if (location == null) {
283 long timestamp = fIteratorManager.getIterator(context).getCurrentTimestamp();
284 currentLocation = new CtfLocation(timestamp, 0);
285 }
286 if (context.getRank() != 0) {
287 context.setRank(ITmfContext.UNKNOWN_RANK);
288 }
289 return context;
290 }
291
292 @Override
293 public synchronized ITmfContext seekEvent(double ratio) {
294 CtfTmfContext context = new CtfTmfContext(this);
295 if (fTrace == null) {
296 context.setLocation(null);
297 context.setRank(ITmfContext.UNKNOWN_RANK);
298 return context;
299 }
300 final long end = getCTFTrace().getCurrentEndTime();
301 final long start = getCTFTrace().getCurrentStartTime();
302 final long diff = end - start;
303 final long ratioTs = Math.round(diff * ratio) + start;
304 context.seek(ratioTs);
305 context.setRank(ITmfContext.UNKNOWN_RANK);
306 return context;
307 }
308
309 /**
310 * Method readNextEvent.
311 *
312 * @param context
313 * ITmfContext
314 * @return CtfTmfEvent
315 * @see org.eclipse.tracecompass.tmf.core.trace.ITmfTrace#getNext(ITmfContext)
316 */
317 @Override
318 public synchronized CtfTmfEvent getNext(final ITmfContext context) {
319 if (fTrace == null) {
320 return null;
321 }
322 CtfTmfEvent event = null;
323 if (context instanceof CtfTmfContext) {
324 if (context.getLocation() == null || CtfLocation.INVALID_LOCATION.equals(context.getLocation().getLocationInfo())) {
325 return null;
326 }
327 CtfTmfContext ctfContext = (CtfTmfContext) context;
328 event = ctfContext.getCurrentEvent();
329
330 if (event != null) {
331 updateAttributes(context, event.getTimestamp());
332 ctfContext.advance();
333 ctfContext.increaseRank();
334 }
335 }
336
337 return event;
338 }
339
340 /**
341 * gets the CTFtrace that this is wrapping
342 *
343 * @return the CTF trace
344 */
345 public CTFTrace getCTFTrace() {
346 return fTrace;
347 }
348
349 /**
350 * Ctf traces have a clock with a unique uuid that will be used to identify
351 * the host. Traces with the same clock uuid will be known to have been made
352 * on the same machine.
353 *
354 * Note: uuid is an optional field, it may not be there for a clock.
355 */
356 @Override
357 public String getHostId() {
358 CTFClock clock = getCTFTrace().getClock();
359 if (clock != null) {
360 String clockHost = (String) clock.getProperty(CLOCK_HOST_PROPERTY);
361 if (clockHost != null) {
362 return clockHost;
363 }
364 }
365 return super.getHostId();
366 }
367
368 // -------------------------------------------
369 // ITmfTraceProperties
370 // -------------------------------------------
371
372 /**
373 * @since 2.0
374 */
375 @Override
376 public Map<String, String> getTraceProperties() {
377 Map<String, String> properties = new HashMap<>();
378 properties.putAll(fTrace.getEnvironment());
379 properties.put(Messages.CtfTmfTrace_HostID, getHostId());
380 return properties;
381 }
382
383 // -------------------------------------------
384 // Clocks
385 // -------------------------------------------
386
387 /**
388 * gets the clock offset
389 *
390 * @return the clock offset in ns
391 */
392 public long getOffset() {
393 if (fTrace != null) {
394 return fTrace.getOffset();
395 }
396 return 0;
397 }
398
399 /**
400 * Gets the list of declared events
401 *
402 * @since 3.0
403 */
404 @Override
405 public Set<CtfTmfEventType> getContainedEventTypes() {
406 return ImmutableSet.copyOf(fContainedEventTypes.values());
407 }
408
409 /**
410 * Register an event type to this trace.
411 *
412 * Package-visible so that {@link CtfTmfEvent#getType} can call it.
413 *
414 * FIXME This could probably be made cleaner?
415 */
416 void registerEventType(CtfTmfEventType eventType) {
417 fContainedEventTypes.put(eventType.getName(), eventType);
418 }
419
420 // -------------------------------------------
421 // Parser
422 // -------------------------------------------
423
424 @Override
425 public CtfTmfEvent parseEvent(ITmfContext context) {
426 CtfTmfEvent event = null;
427 if (context instanceof CtfTmfContext) {
428 final ITmfContext tmpContext = seekEvent(context.getLocation());
429 event = getNext(tmpContext);
430 }
431 return event;
432 }
433
434 /**
435 * Sets the cache size for a CtfTmfTrace.
436 */
437 protected void setCacheSize() {
438 setCacheSize(DEFAULT_CACHE_SIZE);
439 }
440
441 // -------------------------------------------
442 // Helpers
443 // -------------------------------------------
444
445 /**
446 * Get an iterator to the trace
447 *
448 * @return an iterator to the trace
449 * @since 2.0
450 */
451 public CtfIterator createIterator() {
452 try {
453 return new CtfIterator(this);
454 } catch (CTFReaderException e) {
455 Activator.getDefault().logError(e.getMessage(), e);
456 }
457 return null;
458 }
459
460 // ------------------------------------------------------------------------
461 // Timestamp transformation functions
462 // ------------------------------------------------------------------------
463
464 /**
465 * @since 3.0
466 */
467 @Override
468 public CtfTmfTimestamp createTimestamp(long ts) {
469 return new CtfTmfTimestamp(getTimestampTransform().transform(ts));
470 }
471
472 private static int fCheckpointSize = -1;
473
474 /**
475 * @since 3.0
476 */
477 @Override
478 public synchronized int getCheckpointSize() {
479 if (fCheckpointSize == -1) {
480 TmfCheckpoint c = new TmfCheckpoint(new CtfTmfTimestamp(0), new CtfLocation(0, 0), 0);
481 ByteBuffer b = ByteBuffer.allocate(ITmfCheckpoint.MAX_SERIALIZE_SIZE);
482 b.clear();
483 c.serialize(b);
484 fCheckpointSize = b.position();
485 }
486
487 return fCheckpointSize;
488 }
489
490 @Override
491 protected ITmfTraceIndexer createIndexer(int interval) {
492 return new TmfBTreeTraceIndexer(this, interval);
493 }
494
495 /**
496 * @since 3.0
497 */
498 @Override
499 public ITmfLocation restoreLocation(ByteBuffer bufferIn) {
500 return new CtfLocation(bufferIn);
501 }
502
503 @Override
504 public boolean isComplete() {
505 if (getResource() == null) {
506 return true;
507 }
508
509 String host = null;
510 String port = null;
511 String sessionName = null;
512 try {
513 host = getResource().getPersistentProperty(CtfConstants.LIVE_HOST);
514 port = getResource().getPersistentProperty(CtfConstants.LIVE_PORT);
515 sessionName = getResource().getPersistentProperty(CtfConstants.LIVE_SESSION_NAME);
516 } catch (CoreException e) {
517 Activator.getDefault().logError(e.getMessage(), e);
518 // Something happened to the resource, assume we won't get any more data from it
519 return true;
520 }
521 return host == null || port == null || sessionName == null;
522 }
523
524 @Override
525 public void setComplete(final boolean isComplete) {
526 super.setComplete(isComplete);
527 try {
528 if (isComplete) {
529 getResource().setPersistentProperty(CtfConstants.LIVE_HOST, null);
530 getResource().setPersistentProperty(CtfConstants.LIVE_PORT, null);
531 getResource().setPersistentProperty(CtfConstants.LIVE_SESSION_NAME, null);
532 }
533 } catch (CoreException e) {
534 Activator.getDefault().logError(e.getMessage(), e);
535 }
536 }
537 }
This page took 0.050452 seconds and 5 git commands to generate.