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
.List
;
19 import java
.util
.Observable
;
21 import java
.util
.Vector
;
23 import org
.eclipse
.linuxtools
.lttng
.TraceDebug
;
24 import org
.eclipse
.linuxtools
.lttng
.event
.LttngTimestamp
;
25 import org
.eclipse
.linuxtools
.lttng
.jni
.JniTrace
;
26 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.AbsEventProcessorFactory
;
27 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.EventProcessorProxy
;
28 import org
.eclipse
.linuxtools
.lttng
.state
.evProcessor
.IEventProcessing
;
29 import org
.eclipse
.linuxtools
.lttng
.state
.experiment
.StateManagerFactory
;
30 import org
.eclipse
.linuxtools
.lttng
.state
.model
.ILttngStateInputRef
;
31 import org
.eclipse
.linuxtools
.lttng
.state
.model
.LttngProcessState
;
32 import org
.eclipse
.linuxtools
.lttng
.state
.model
.LttngTraceState
;
33 import org
.eclipse
.linuxtools
.lttng
.state
.model
.StateModelFactory
;
34 import org
.eclipse
.linuxtools
.lttng
.trace
.LTTngTrace
;
35 import org
.eclipse
.linuxtools
.tmf
.event
.TmfEvent
;
36 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimeRange
;
37 import org
.eclipse
.linuxtools
.tmf
.event
.TmfTimestamp
;
38 import org
.eclipse
.linuxtools
.tmf
.request
.TmfDataRequest
;
39 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfExperiment
;
40 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTrace
;
41 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTraceCheckpoint
;
48 public class StateManager
extends Observable
{
50 private static final long LTTNG_STATE_SAVE_INTERVAL
= 50000L;
52 // These are used in the building of the data request.
53 private static final long DEFAULT_OFFSET
= 0L;
54 private static final int DEFAULT_CHUNK
= 1;
56 // ========================================================================
58 // =======================================================================
59 private TmfExperiment fExperiment
= null;
60 private LTTngTrace fEventLog
= null;
61 private StateStacksHandler stateIn
= null;
62 private JniTrace trace
= null;
63 private Long eventCount
= 0L;
65 private HashMap
<Long
, LttngTraceState
> stateCheckpointsList
= new HashMap
<Long
, LttngTraceState
>();
66 private Vector
<TmfTraceCheckpoint
> timestampCheckpointsList
= new Vector
<TmfTraceCheckpoint
>();
68 // ========================================================================
70 // =======================================================================
73 // * Default constructor
75 // * Instanciate its own StateStacksHandler.
78 // public StateManager() {
79 // this.stateIn = new StateStacksHandler();
83 * Constructor with parameter
86 * @param stateInputHandler
87 * A valid StateStacksHandler
90 public StateManager(StateStacksHandler stateInputHandler
) {
91 this.stateIn
= stateInputHandler
;
98 // * @param oldStateManager
99 // * the StateManager we want to copy
102 // public StateManager(StateManager oldStateManager) {
103 // fEventLog = oldStateManager.fEventLog;
104 // stateIn = oldStateManager.stateIn;
105 // trace = oldStateManager.trace;
106 // eventCount = oldStateManager.eventCount;
108 // stateCheckpointsList = oldStateManager.stateCheckpointsList;
109 // timestampCheckpointsList = oldStateManager.timestampCheckpointsList;
112 // ========================================================================
114 // =======================================================================
115 public void setTraceSelection(TmfExperiment experiment
) {
116 // New log in use, read all events and build state transition stack
117 if (experiment
!= null) {
118 if (fExperiment
!= null && fExperiment
!= experiment
) {
119 this.fExperiment
.dispose();
122 this.fExperiment
= experiment
;
124 // if (fEventLog != null) {
125 // this.fEventLog.dispose();
128 this.fEventLog
= (LTTngTrace
) experiment
.getTraces()[0];
129 trace
= fEventLog
.getCurrentJniTrace();
131 stateIn
.init(trace
, fEventLog
);
132 } catch (LttngStateException e
) {
136 // Restart count and collections
138 stateCheckpointsList
.clear();
139 timestampCheckpointsList
.clear();
141 // Obtain a dataRequest to pass to the processRequest function
142 TmfTimeRange allTraceWindow
= fEventLog
.getTimeRange();
143 StateDataRequest request
= getDataRequestStateSave(allTraceWindow
,
146 // Wait for completion
147 request
.startRequestInd(fExperiment
, true, true);
149 if (TraceDebug
.isDEBUG()) {
150 List
<LttngProcessState
> processes
= stateIn
151 .getTraceStateModel().getProcesses();
152 StringBuilder sb
= new StringBuilder(
153 "Total number of processes in the State provider: "
156 TmfTimeRange logTimes
= fEventLog
.getTimeRange();
157 sb
.append("\n\tLog file times "
158 + new LttngTimestamp(logTimes
.getStartTime()));
159 sb
.append(" - " + new LttngTimestamp(logTimes
.getEndTime()));
161 sb
.append("\n\tCheckPoints available at: ");
162 for (TmfTraceCheckpoint cpoint
: timestampCheckpointsList
) {
163 sb
.append("\n\t" + cpoint
.getTimestamp());
165 TraceDebug
.debug(sb
.toString());
172 * TODO: Not ready for threading
174 * Read events within specific time window
179 * @param transactionID
181 public void executeDataRequest(TmfTimeRange trange
, String transactionID
,
182 IStateDataRequestListener listener
) {
183 TmfTimestamp restoredStartTime
= restoreCheckPointByTimestamp(trange
185 // Adjust the time range to consider rewinding to the start time
186 trange
= new TmfTimeRange(restoredStartTime
, trange
.getEndTime());
187 // Get a data request for the time range we want (nearest checkpoint
188 // to timestamp wanted)
191 // Process request to that point
192 StateDataRequest request
= getDataRequestByTimeRange(trange
, listener
);
193 // don't wait for completion i.e. allow cancellations
194 request
.startRequestInd(fExperiment
, false, true);
196 if (TraceDebug
.isDEBUG()) {
197 List
<LttngProcessState
> processes
= stateIn
.getTraceStateModel()
199 TraceDebug
.debug(" Time Window requested: "
200 + trange
.getStartTime().getValue() + "-"
201 + trange
.getEndTime().getValue()
202 + " Total number of processes in the State provider: "
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
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
,
269 TmfTimestamp eventTime
) {
270 boolean saveHappened
= false;
271 // Crate new location to store checkpoint reference
272 Long location
= new Long(eventCounter
.longValue());
273 // Save a checkpoint every LTTNG_STATE_SAVE_INTERVAL event
274 if ((location
% LTTNG_STATE_SAVE_INTERVAL
) == 0) {
275 // Save the checkpoint
276 stateCheckpointsList
.put(location
, stateIn
.traceStateModel
.clone());
277 // Save correlation between timestamp and checkpoint index
279 timestampCheckpointsList
.add(new TmfTraceCheckpoint(eventTime
,
289 * Restore to the closest checkpoint from TmfTimestamp
291 * Note : it is heavier to restore by timestamp than by event position,
292 * restore by event position whichever possible.
295 * The timestamp of the event to restore to
297 * @return TmfTimestamp indicates the nearest time used to restore the
298 * state, null sent if input is invalid
300 public TmfTimestamp
restoreCheckPointByTimestamp(TmfTimestamp eventTime
) {
301 TmfTimeRange logRange
= fExperiment
.getTimeRange();
302 TmfTimestamp nearestTimeStamp
= logRange
.getStartTime();
304 // The GUI can have time limits higher than this log, since GUI can
305 // handle multiple logs
306 if ((eventTime
.getValue() < 0)
307 || (eventTime
.getValue() > logRange
.getEndTime().getValue())) {
311 // The GUI can have time limits lower than this log, since GUI can
312 // handle multiple logs
313 if ((eventTime
.getValue() < logRange
.getStartTime().getValue())) {
314 eventTime
= logRange
.getStartTime();
317 // Sort the checkpoints, required before the binary search
318 Collections
.sort(timestampCheckpointsList
);
319 // Initiate the compare with a checkpoint containing the target time
321 int index
= Collections
.binarySearch(timestampCheckpointsList
,
322 new TmfTraceCheckpoint(eventTime
, 0));
323 // adjust index to round down to earlier checkpoint when exact match not
325 index
= getPrevIndex(index
);
327 LttngTraceState traceState
;
330 // No checkpoint restore is needed, start with a brand new
332 ILttngStateInputRef inputDataRef
= new LttngStateInputRef(trace
,
334 traceState
= StateModelFactory
.getStateEntryInstance(inputDataRef
);
336 // Useful CheckPoint found
337 TmfTraceCheckpoint checkpoint
= timestampCheckpointsList
.get(index
);
338 nearestTimeStamp
= checkpoint
.getTimestamp();
339 // get the location associated with the checkpoint
340 location
= (Long
) (checkpoint
.getLocation());
341 // reference a new copy of the checkpoint template
342 traceState
= stateCheckpointsList
.get(location
).clone();
345 // Make sure eventCount stay consistent!
346 eventCount
= new Long(location
);
348 // Restore the stored traceState
349 stateIn
.setTraceStateModel(traceState
);
351 return nearestTimeStamp
;
355 * Adjust the result from a binary search to the round down position
358 * if Negative is: (-(insertion point) -1)
359 * @return position or if no match found, earlier than insertion point
361 private int getPrevIndex(int position
) {
362 int roundDownPosition
= position
;
364 roundDownPosition
= -(position
+ 2);
367 roundDownPosition
= roundDownPosition
< 0 ?
0 : roundDownPosition
;
368 return roundDownPosition
;
372 // * Restore to the closest checkpoint from position
376 // * The position of the event to restore to
378 // * @return boolean True if a checkpoint was restored, false otherwise
380 // private boolean restoreCheckPointByPosition(long position) {
381 // long nearestCheckPoint = (position - (position %
382 // LTTNG_STATE_SAVE_INTERVAL));
384 // // Some sanity check :
386 // // Not over eventCount
387 // // A checkpoint exist
388 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
389 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
392 // // Restore the stored traceState
393 // stateIn.setTraceStateModel(stateCheckpointsList
394 // .get(nearestCheckPoint));
396 // // Make sure eventCount stay consistent!
397 // eventCount = new Long(nearestCheckPoint);
399 // // * Rewind to the correct position
400 // // To do so, we need a request to the correct window
401 // // We will seek to nearestCheckPoint and read next events until
403 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
404 // (int) nearestCheckPoint, (int) position);
406 // // Process request to that point
407 // fExperiment.processRequest(request, true);
414 * Get a Tmf data request for the current eventlog
417 * @param TmfTimeRange
418 * The time range we want events from.
420 * @return TmfDataRequest<TmfEvent> The request made
422 StateDataRequest
getDataRequestByTimeRange(TmfTimeRange timeWindow
,
423 IStateDataRequestListener listener
) {
425 final TmfEvent
[] evt
= new TmfEvent
[1];
428 // The override of handlePartialResult is similar to the one in
429 // getDataRequestByPosition()
432 // Create the new request and override the handlePartialResult function
433 StateDataRequest request
= new StateDataRequest(timeWindow
,
434 DEFAULT_OFFSET
, TmfDataRequest
.ALL_EVENTS
, DEFAULT_CHUNK
,
437 public void handleData() {
438 TmfEvent
[] result
= getData();
440 evt
[0] = (result
.length
> 0) ? result
[0] : null;
441 // Dispatch information for Event processing
442 stateIn
.processEvent(evt
[0]);
444 // increment internal and external number of events
445 setNumOfEvents(getNumOfEvents() + 1);
450 public void handleCompleted() {
451 if (isCancelled() || isFailed()) {
452 // No notification to end request handlers
454 // notify the associated end request handlers
466 private StateDataRequest
getDataRequestStateSave(TmfTimeRange timeWindow
,
467 IStateDataRequestListener requestListener
) {
469 final TmfEvent
[] evt
= new TmfEvent
[1];
472 // The override of handlePartialResult is similar to the one in
473 // getDataRequestByPosition()
476 // Create the new request and override the handlePartialResult function
477 StateDataRequest request
= new StateDataRequest(timeWindow
,
478 DEFAULT_OFFSET
, TmfDataRequest
.ALL_EVENTS
, DEFAULT_CHUNK
,
479 requestListener
, this) {
482 public void handleData() {
483 TmfEvent
[] result
= getData();
485 evt
[0] = (result
.length
> 0) ? result
[0] : null;
486 // Dispatch information for Event processing
487 stateIn
.processEvent(evt
[0]);
489 // Call the function that will save a checkpoint if needed at
491 // Note : We call this function before incrementing eventCount
492 // to avoid skipping the "0th" event
493 if (evt
[0] != null) {
494 saveCheckPointIfNeeded(getNumOfEvents(), evt
[0]
498 // increment internal and external counters
499 setNumOfEvents(getNumOfEvents() + 1);
504 public void handleCompleted() {
505 if (isCancelled() || isFailed()) {
506 // No notification to end request handlers
508 // notify the associated end request handlers
514 TraceDebug
.debug("number of events processed on file opening"
523 // * Get a Tmf data request for the current eventlog
526 // * @param startPosition
527 // * The position to start the get request from
528 // * @param endPosition
529 // * The position to ed the get request at
531 // * @return TmfDataRequest<TmfEvent> The request made
533 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
534 // long startPosition, long endPosition) {
535 // final TmfEvent[] evt = new TmfEvent[1];
538 // // The override of handlePartialResult is exactly the same as the one in
539 // // getDataRequestByPosition()
540 // // However, there is no way to override it in only one place to avoid
541 // // code duplication!
544 // // Create the new request and override the handlePartialResult function
545 // TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(
546 // (int) startPosition, DEFAULT_OFFSET,
547 // (int) (endPosition - startPosition), DEFAULT_CHUNK) {
549 // public void handlePartialResult() {
550 // TmfEvent[] result = getData();
552 // evt[0] = (result.length > 0) ? result[0] : null;
553 // // Dispatch information for Event processing
554 // stateIn.processEvent(evt[0]);
564 public TmfTimeRange
getExperimentTimeWindow() {
565 if (fExperiment
!= null) {
566 return fExperiment
.getTimeRange();
572 * This method has to be called once all events of the associated Trace have
573 * been processed, this method then triggers the drawing of the final state
574 * which is necessary e.g when zooming.
576 public synchronized void requestCompleted() {
577 Set
<AbsEventProcessorFactory
> handlerRegister
= EventProcessorProxy
578 .getInstance().getProcessingFactories();
579 // Notify the FINISH handlers
580 for (Iterator
<AbsEventProcessorFactory
> iterator
= handlerRegister
581 .iterator(); iterator
.hasNext();) {
582 AbsEventProcessorFactory handlerRegistry
= (AbsEventProcessorFactory
) iterator
584 IEventProcessing handler
= handlerRegistry
.getfinishProcessor();
585 if (handler
!= null) {
586 // process State Update
587 handler
.process(null, stateIn
.traceStateModel
);
592 // *** MAIN : For testing only ***
593 public static void main(String
[] args
) {
595 // Timestamp for the "197500th" events
596 long timefor197500
= 953098902827L;
598 // A new StateManager
599 StateManager stateManagerTest
= StateManagerFactory
.getManager("test");
601 LTTngTrace
[] testStream
= new LTTngTrace
[1];
603 // The stream is needed by the eventLog, which is needed by the
605 // testStream[0] = new LttngEventStream("/home/william/trace1",
607 testStream
[0] = new LTTngTrace(
608 "/home/william/runtime-EclipseApplication/TEST_JOIE/Traces/trace3",
611 TmfExperiment newExpt
= new TmfExperiment("trace1", testStream
);
613 // This will create all the checkpoint
614 stateManagerTest
.setTraceSelection(newExpt
);
615 System
.out
.println("JOIE JOIE FIN DE LA CREATION DES CHECKPOINTS");
617 // *** Restore some checkpoint to test
619 // Test the restoration from position
620 // stateManagerTest.restoreCheckPointByPosition(197500);
622 if (testStream
[0].getCurrentEvent().getTimestamp().getValue() == timefor197500
) {
623 System
.out
.println("Successfully restored by Position!");
625 System
.out
.println("FAILED : "
626 + testStream
[0].getCurrentEvent().getTimestamp()
627 .getValue() + " != " + timefor197500
);
630 // Test the restoration from Timestamp
631 TmfTimestamp newTimestamp
= new TmfTimestamp(timefor197500
,
633 stateManagerTest
.restoreCheckPointByTimestamp(newTimestamp
);
634 // test the timestamp
635 if (testStream
[0].getCurrentEvent().getTimestamp().getValue() == timefor197500
) {
636 System
.out
.println("Successfully restored by Timestamp!");
638 System
.out
.println("FAILED : "
639 + testStream
[0].getCurrentEvent().getTimestamp()
640 .getValue() + " != " + timefor197500
);
643 } catch (Exception e
) {