1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
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
10 * Alvaro Sanchez-Leon (alvsan09@gmail.com) - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.lttng
.state
;
15 import java
.util
.Collections
;
16 import java
.util
.HashMap
;
17 import java
.util
.Iterator
;
18 import java
.util
.Observable
;
20 import java
.util
.Vector
;
22 import org
.eclipse
.linuxtools
.lttng
.TraceDebug
;
23 import org
.eclipse
.linuxtools
.lttng
.event
.LttngEvent
;
24 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
25 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.AbsEventProcessorFactory
;
26 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.EventProcessorProxy
;
27 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.IEventProcessing
;
28 import org
.eclipse
.linuxtools
.lttng
.state
.model
.ILttngStateInputRef
;
29 import org
.eclipse
.linuxtools
.lttng
.state
.model
.LttngTraceState
;
30 import org
.eclipse
.linuxtools
.lttng
.state
.model
.StateModelFactory
;
31 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
32 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
33 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
34 import org
.eclipse
.linuxtools
.tmf
.experiment
.TmfExperiment
;
35 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
36 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfCheckpoint
;
37 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfLocation
;
38 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
45 public class StateManager
extends Observable
{
47 private static final long LTTNG_STATE_SAVE_INTERVAL
= 5000000L;
49 // These are used in the building of the data request.
50 private static final long DEFAULT_OFFSET
= 0L;
51 private static final int DEFAULT_CHUNK
= 1;
53 // ========================================================================
55 // =======================================================================
56 private TmfExperiment
<LttngEvent
> fExperiment
= null;
57 private TmfTrace
<LttngEvent
> fEventLog
= null;
58 private StateStacksHandler stateIn
= null;
59 private Long eventCount
= 0L;
61 private HashMap
<Long
, LttngTraceState
> stateCheckpointsList
= new HashMap
<Long
, LttngTraceState
>();
62 private Vector
<TmfCheckpoint
> timestampCheckpointsList
= new Vector
<TmfCheckpoint
>();
64 // ========================================================================
66 // =======================================================================
69 // * Default constructor
71 // * Instanciate its own StateStacksHandler.
74 // public StateManager() {
75 // this.stateIn = new StateStacksHandler();
79 * Constructor with parameter
82 * @param stateInputHandler
83 * A valid StateStacksHandler
86 public StateManager(StateStacksHandler stateInputHandler
) {
87 this.stateIn
= stateInputHandler
;
94 // * @param oldStateManager
95 // * the StateManager we want to copy
98 // public StateManager(StateManager oldStateManager) {
99 // fEventLog = oldStateManager.fEventLog;
100 // stateIn = oldStateManager.stateIn;
101 // trace = oldStateManager.trace;
102 // eventCount = oldStateManager.eventCount;
104 // stateCheckpointsList = oldStateManager.stateCheckpointsList;
105 // timestampCheckpointsList = oldStateManager.timestampCheckpointsList;
108 // ========================================================================
110 // =======================================================================
112 * A new Experiment or trace selected
114 * @param clearPreviousData
116 @SuppressWarnings("unchecked")
117 public void setTraceSelection(TmfExperiment
<LttngEvent
> experiment
,
118 boolean clearPreviousData
) {
119 // New log in use, read all events and build state transition stack
120 if (experiment
!= null) {
121 if (fExperiment
!= null && fExperiment
!= experiment
) {
122 this.fExperiment
.deregister();
125 this.fExperiment
= experiment
;
127 // if (fEventLog != null) {
128 // this.fEventLog.dispose();
131 this.fEventLog
= (TmfTrace
<LttngEvent
>) experiment
.getTraces()[0];
133 stateIn
.init(fEventLog
);
134 } catch (LttngStateException e
) {
138 // Restart count and collections
140 stateCheckpointsList
.clear();
141 timestampCheckpointsList
.clear();
143 // Obtain a dataRequest to pass to the processRequest function
144 TmfTimeRange allTraceWindow
= fEventLog
.getTimeRange();
145 StateDataRequest request
= getDataRequestStateSave(allTraceWindow
,
147 request
.setclearDataInd(clearPreviousData
);
149 // Wait for completion
150 request
.startRequestInd(fExperiment
, true, true);
152 if (TraceDebug
.isDEBUG()) {
153 StringBuilder sb
= new StringBuilder(
154 "Total number of processes in the State provider: "
155 + stateIn
.getTraceStateModel().getProcesses().length
);
157 TmfTimeRange logTimes
= fEventLog
.getTimeRange();
158 sb
.append("\n\tLog file times "
159 + new LttngTimestamp(logTimes
.getStartTime()));
160 sb
.append(" - " + new LttngTimestamp(logTimes
.getEndTime()));
162 sb
.append("\n\tCheckPoints available at: ");
163 for (TmfCheckpoint cpoint
: timestampCheckpointsList
) {
164 sb
.append("\n\t" + cpoint
.getTimestamp());
166 TraceDebug
.debug(sb
.toString());
173 * TODO: Not ready for threading
175 * Read events within specific time window
180 * @param transactionID
182 public void executeDataRequest(TmfTimeRange trange
, String transactionID
,
183 IStateDataRequestListener listener
) {
184 TmfTimestamp restoredStartTime
= restoreCheckPointByTimestamp(trange
186 // Adjust the time range to consider rewinding to the start time
187 trange
= new TmfTimeRange(restoredStartTime
, trange
.getEndTime());
188 // Get a data request for the time range we want (nearest checkpoint
189 // to timestamp wanted)
192 // Process request to that point
193 StateDataRequest request
= getDataRequestByTimeRange(trange
, listener
);
194 // don't wait for completion i.e. allow cancellations
195 request
.startRequestInd(fExperiment
, false, false);
197 if (TraceDebug
.isDEBUG()) {
199 .debug(" Time Window requested, (start adjusted to checkpoint): "
200 + trange
.getStartTime()
201 + "-" + trange
.getEndTime()
202 + " Total number of processes in the State provider: "
203 + stateIn
.getTraceStateModel().getProcesses().length
+ " Completed");
208 * Current value of event counter
210 * @return Long The number of events, if it is known
212 public Long
getEventCount() {
217 * used to obtain details on the log associated with this manager e.g.
222 public TmfTrace
<LttngEvent
> getEventLog() {
227 * Used for troubleshooting when debug mode is on
229 * @return Set<String> Set of event that were not handled
231 public Set
<String
> getEventsNotHandled() {
232 return stateIn
.getEventsNotHandled();
236 * Needed for verification purposes
239 * The IEventProcessing we want to register
241 void registerListener(IEventProcessing listener
) {
242 stateIn
.registerListener(listener
);
246 * Needed for verification purposes
249 * The IEventProcessing we want to unregister
251 void deregisterListener(IEventProcessing listener
) {
252 stateIn
.deregisterListener(listener
);
256 * Save a checkpoint if it is needed at that point
258 * The function will use "eventCount" internally to determine if a save was
261 * @param eventCounter
262 * The event "count" or event "id" so far
264 * The timestamp of this event
266 * @return boolean True if a checkpoint was saved, false otherwise
268 private boolean saveCheckPointIfNeeded(Long eventCounter
, TmfTimestamp eventTime
) {
269 boolean saveHappened
= false;
270 // Save a checkpoint every LTTNG_STATE_SAVE_INTERVAL event
271 if ((eventCounter
.longValue() % LTTNG_STATE_SAVE_INTERVAL
) == 0) {
272 // Save the checkpoint
273 stateCheckpointsList
.put(eventCounter
, stateIn
.traceStateModel
.clone());
274 // Save correlation between timestamp and checkpoint index
276 timestampCheckpointsList
.add(new TmfCheckpoint(eventTime
, new TmfLocation
<Long
>(eventCounter
)));
285 * Restore to the closest checkpoint from TmfTimestamp
287 * Note : it is heavier to restore by timestamp than by event position,
288 * restore by event position whichever possible.
291 * The timestamp of the event to restore to
293 * @return TmfTimestamp indicates the nearest time used to restore the
294 * state, null sent if input is invalid
296 @SuppressWarnings("unchecked")
297 public TmfTimestamp
restoreCheckPointByTimestamp(TmfTimestamp eventTime
) {
298 TmfTimeRange logRange
= fExperiment
.getTimeRange();
299 TmfTimestamp nearestTimeStamp
= logRange
.getStartTime();
301 // The GUI can have time limits higher than this log, since GUI can
302 // handle multiple logs
303 if ((eventTime
.getValue() < 0)
304 || (eventTime
.getValue() > logRange
.getEndTime().getValue())) {
308 // The GUI can have time limits lower than this log, since GUI can
309 // handle multiple logs
310 if ((eventTime
.getValue() < logRange
.getStartTime().getValue())) {
311 eventTime
= logRange
.getStartTime();
314 // Sort the checkpoints, required before the binary search
315 Collections
.sort(timestampCheckpointsList
);
316 // Initiate the compare with a checkpoint containing the target time
318 int index
= Collections
.binarySearch(timestampCheckpointsList
,
319 new TmfCheckpoint(eventTime
, new TmfLocation
<Long
>(0L)));
320 // adjust index to round down to earlier checkpoint when exact match not
322 index
= getPrevIndex(index
);
324 LttngTraceState traceState
;
325 TmfLocation
<Long
> location
= new TmfLocation
<Long
>(0L);
327 // No checkpoint restore is needed, start with a brand new
329 ILttngStateInputRef inputDataRef
= new LttngStateInputRef(fEventLog
);
330 traceState
= StateModelFactory
.getStateEntryInstance(inputDataRef
);
332 // Useful CheckPoint found
333 TmfCheckpoint checkpoint
= timestampCheckpointsList
.get(index
);
334 nearestTimeStamp
= checkpoint
.getTimestamp();
335 // get the location associated with the checkpoint
336 location
= (TmfLocation
<Long
>) checkpoint
.getLocation();
337 // reference a new copy of the checkpoint template
338 traceState
= stateCheckpointsList
.get(location
).clone();
341 // Make sure eventCount stay consistent!
342 eventCount
= location
.getValue();
344 // Restore the stored traceState
345 stateIn
.setTraceStateModel(traceState
);
347 return nearestTimeStamp
;
351 * Adjust the result from a binary search to the round down position
354 * if Negative is: (-(insertion point) -1)
355 * @return position or if no match found, earlier than insertion point
357 private int getPrevIndex(int position
) {
358 int roundDownPosition
= position
;
360 roundDownPosition
= -(position
+ 2);
363 roundDownPosition
= roundDownPosition
< 0 ?
0 : roundDownPosition
;
364 return roundDownPosition
;
368 // * Restore to the closest checkpoint from position
372 // * The position of the event to restore to
374 // * @return boolean True if a checkpoint was restored, false otherwise
376 // private boolean restoreCheckPointByPosition(long position) {
377 // long nearestCheckPoint = (position - (position %
378 // LTTNG_STATE_SAVE_INTERVAL));
380 // // Some sanity check :
382 // // Not over eventCount
383 // // A checkpoint exist
384 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
385 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
388 // // Restore the stored traceState
389 // stateIn.setTraceStateModel(stateCheckpointsList
390 // .get(nearestCheckPoint));
392 // // Make sure eventCount stay consistent!
393 // eventCount = new Long(nearestCheckPoint);
395 // // * Rewind to the correct position
396 // // To do so, we need a request to the correct window
397 // // We will seek to nearestCheckPoint and read next events until
399 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
400 // (int) nearestCheckPoint, (int) position);
402 // // Process request to that point
403 // fExperiment.processRequest(request, true);
410 * Get a Tmf data request for the current eventlog
413 * @param TmfTimeRange
414 * The time range we want events from.
416 * @return TmfDataRequest<TmfEvent> The request made
418 StateDataRequest
getDataRequestByTimeRange(TmfTimeRange timeWindow
,
419 IStateDataRequestListener listener
) {
421 final TmfEvent
[] evt
= new TmfEvent
[1];
424 // The override of handlePartialResult is similar to the one in
425 // getDataRequestByPosition()
428 // Create the new request and override the handlePartialResult function
429 StateDataRequest request
= new StateDataRequest(timeWindow
,
430 DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
, DEFAULT_CHUNK
,
433 public void handleData() {
434 TmfEvent
[] result
= getData();
436 evt
[0] = (result
.length
> 0) ? result
[0] : null;
437 // Dispatch information for Event processing
438 stateIn
.processEvent(evt
[0]);
440 // increment internal and external number of events
441 setNumOfEvents(getNumOfEvents() + 1);
446 public void handleCompleted() {
447 if (isCancelled() || isFailed()) {
448 // No notification to end request handlers
450 // notify the associated end request handlers
462 private StateDataRequest
getDataRequestStateSave(TmfTimeRange timeWindow
,
463 IStateDataRequestListener requestListener
) {
465 final TmfEvent
[] evt
= new TmfEvent
[1];
468 // The override of handlePartialResult is similar to the one in
469 // getDataRequestByPosition()
472 // Create the new request and override the handlePartialResult function
473 StateDataRequest request
= new StateDataRequest(timeWindow
,
474 DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
, DEFAULT_CHUNK
,
475 requestListener
, this) {
478 public void handleData() {
479 TmfEvent
[] result
= getData();
481 evt
[0] = (result
.length
> 0) ? result
[0] : null;
482 // Dispatch information for Event processing
483 stateIn
.processEvent(evt
[0]);
485 // Call the function that will save a checkpoint if needed at
487 // Note : We call this function before incrementing eventCount
488 // to avoid skipping the "0th" event
489 if (evt
[0] != null) {
490 saveCheckPointIfNeeded(getNumOfEvents(), evt
[0]
494 // increment internal and external counters
495 setNumOfEvents(getNumOfEvents() + 1);
500 public void handleCompleted() {
501 if (isCancelled() || isFailed()) {
502 // No notification to end request handlers
504 // notify the associated end request handlers
510 TraceDebug
.debug("number of events processed on file opening"
519 // * Get a Tmf data request for the current eventlog
522 // * @param startPosition
523 // * The position to start the get request from
524 // * @param endPosition
525 // * The position to ed the get request at
527 // * @return TmfDataRequest<TmfEvent> The request made
529 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
530 // long startPosition, long endPosition) {
531 // final TmfEvent[] evt = new TmfEvent[1];
534 // // The override of handlePartialResult is exactly the same as the one in
535 // // getDataRequestByPosition()
536 // // However, there is no way to override it in only one place to avoid
537 // // code duplication!
540 // // Create the new request and override the handlePartialResult function
541 // TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(
542 // (int) startPosition, DEFAULT_OFFSET,
543 // (int) (endPosition - startPosition), DEFAULT_CHUNK) {
545 // public void handlePartialResult() {
546 // TmfEvent[] result = getData();
548 // evt[0] = (result.length > 0) ? result[0] : null;
549 // // Dispatch information for Event processing
550 // stateIn.processEvent(evt[0]);
560 public TmfTimeRange
getExperimentTimeWindow() {
561 if (fExperiment
!= null) {
562 return fExperiment
.getTimeRange();
568 * This method has to be called once all events of the associated Trace have
569 * been processed, this method then triggers the drawing of the final state
570 * which is necessary e.g when zooming.
572 public synchronized void requestCompleted() {
573 Set
<AbsEventProcessorFactory
> handlerRegister
= EventProcessorProxy
574 .getInstance().getProcessingFactories();
575 // Notify the FINISH handlers
576 for (Iterator
<AbsEventProcessorFactory
> iterator
= handlerRegister
577 .iterator(); iterator
.hasNext();) {
578 AbsEventProcessorFactory handlerRegistry
= (AbsEventProcessorFactory
) iterator
580 IEventProcessing handler
= handlerRegistry
.getfinishProcessor();
581 if (handler
!= null) {
582 // process State Update
583 handler
.process(null, stateIn
.traceStateModel
);