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
.TmfTrace
;
37 import org
.eclipse
.linuxtools
.tmf
.trace
.TmfTraceCheckpoint
;
44 public class StateManager
extends Observable
{
46 private static final long LTTNG_STATE_SAVE_INTERVAL
= 5000000L;
48 // These are used in the building of the data request.
49 private static final long DEFAULT_OFFSET
= 0L;
50 private static final int DEFAULT_CHUNK
= 1;
52 // ========================================================================
54 // =======================================================================
55 private TmfExperiment
<LttngEvent
> fExperiment
= null;
56 private TmfTrace
<LttngEvent
> fEventLog
= null;
57 private StateStacksHandler stateIn
= null;
58 private Long eventCount
= 0L;
60 private HashMap
<Long
, LttngTraceState
> stateCheckpointsList
= new HashMap
<Long
, LttngTraceState
>();
61 private Vector
<TmfTraceCheckpoint
> timestampCheckpointsList
= new Vector
<TmfTraceCheckpoint
>();
63 // ========================================================================
65 // =======================================================================
68 // * Default constructor
70 // * Instanciate its own StateStacksHandler.
73 // public StateManager() {
74 // this.stateIn = new StateStacksHandler();
78 * Constructor with parameter
81 * @param stateInputHandler
82 * A valid StateStacksHandler
85 public StateManager(StateStacksHandler stateInputHandler
) {
86 this.stateIn
= stateInputHandler
;
93 // * @param oldStateManager
94 // * the StateManager we want to copy
97 // public StateManager(StateManager oldStateManager) {
98 // fEventLog = oldStateManager.fEventLog;
99 // stateIn = oldStateManager.stateIn;
100 // trace = oldStateManager.trace;
101 // eventCount = oldStateManager.eventCount;
103 // stateCheckpointsList = oldStateManager.stateCheckpointsList;
104 // timestampCheckpointsList = oldStateManager.timestampCheckpointsList;
107 // ========================================================================
109 // =======================================================================
111 * A new Experiment or trace selected
113 * @param clearPreviousData
115 @SuppressWarnings("unchecked")
116 public void setTraceSelection(TmfExperiment
<LttngEvent
> experiment
,
117 boolean clearPreviousData
) {
118 // New log in use, read all events and build state transition stack
119 if (experiment
!= null) {
120 if (fExperiment
!= null && fExperiment
!= experiment
) {
121 this.fExperiment
.deregister();
124 this.fExperiment
= experiment
;
126 // if (fEventLog != null) {
127 // this.fEventLog.dispose();
130 this.fEventLog
= (TmfTrace
<LttngEvent
>) experiment
.getTraces()[0];
132 stateIn
.init(fEventLog
);
133 } catch (LttngStateException e
) {
137 // Restart count and collections
139 stateCheckpointsList
.clear();
140 timestampCheckpointsList
.clear();
142 // Obtain a dataRequest to pass to the processRequest function
143 TmfTimeRange allTraceWindow
= fEventLog
.getTimeRange();
144 StateDataRequest request
= getDataRequestStateSave(allTraceWindow
,
146 request
.setclearDataInd(clearPreviousData
);
148 // Wait for completion
149 request
.startRequestInd(fExperiment
, true, true);
151 if (TraceDebug
.isDEBUG()) {
152 StringBuilder sb
= new StringBuilder(
153 "Total number of processes in the State provider: "
154 + stateIn
.getTraceStateModel().getProcesses().length
);
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, false);
196 if (TraceDebug
.isDEBUG()) {
198 .debug(" Time Window requested, (start adjusted to checkpoint): "
199 + trange
.getStartTime()
200 + "-" + trange
.getEndTime()
201 + " Total number of processes in the State provider: "
202 + stateIn
.getTraceStateModel().getProcesses().length
+ " Completed");
207 * Current value of event counter
209 * @return Long The number of events, if it is known
211 public Long
getEventCount() {
216 * used to obtain details on the log associated with this manager e.g.
221 public TmfTrace
<LttngEvent
> getEventLog() {
226 * Used for troubleshooting when debug mode is on
228 * @return Set<String> Set of event that were not handled
230 public Set
<String
> getEventsNotHandled() {
231 return stateIn
.getEventsNotHandled();
235 * Needed for verification purposes
238 * The IEventProcessing we want to register
240 void registerListener(IEventProcessing listener
) {
241 stateIn
.registerListener(listener
);
245 * Needed for verification purposes
248 * The IEventProcessing we want to unregister
250 void deregisterListener(IEventProcessing listener
) {
251 stateIn
.deregisterListener(listener
);
255 * Save a checkpoint if it is needed at that point
257 * The function will use "eventCount" internally to determine if a save was
260 * @param eventCounter
261 * The event "count" or event "id" so far
263 * The timestamp of this event
265 * @return boolean True if a checkpoint was saved, false otherwise
267 private boolean saveCheckPointIfNeeded(Long eventCounter
,
268 TmfTimestamp eventTime
) {
269 boolean saveHappened
= false;
270 // Crate new location to store checkpoint reference
271 Long location
= new Long(eventCounter
.longValue());
272 // Save a checkpoint every LTTNG_STATE_SAVE_INTERVAL event
273 if ((location
% LTTNG_STATE_SAVE_INTERVAL
) == 0) {
274 // Save the checkpoint
275 stateCheckpointsList
.put(location
, stateIn
.traceStateModel
.clone());
276 // Save correlation between timestamp and checkpoint index
278 timestampCheckpointsList
.add(new TmfTraceCheckpoint(eventTime
,
288 * Restore to the closest checkpoint from TmfTimestamp
290 * Note : it is heavier to restore by timestamp than by event position,
291 * restore by event position whichever possible.
294 * The timestamp of the event to restore to
296 * @return TmfTimestamp indicates the nearest time used to restore the
297 * state, null sent if input is invalid
299 public TmfTimestamp
restoreCheckPointByTimestamp(TmfTimestamp eventTime
) {
300 TmfTimeRange logRange
= fExperiment
.getTimeRange();
301 TmfTimestamp nearestTimeStamp
= logRange
.getStartTime();
303 // The GUI can have time limits higher than this log, since GUI can
304 // handle multiple logs
305 if ((eventTime
.getValue() < 0)
306 || (eventTime
.getValue() > logRange
.getEndTime().getValue())) {
310 // The GUI can have time limits lower than this log, since GUI can
311 // handle multiple logs
312 if ((eventTime
.getValue() < logRange
.getStartTime().getValue())) {
313 eventTime
= logRange
.getStartTime();
316 // Sort the checkpoints, required before the binary search
317 Collections
.sort(timestampCheckpointsList
);
318 // Initiate the compare with a checkpoint containing the target time
320 int index
= Collections
.binarySearch(timestampCheckpointsList
,
321 new TmfTraceCheckpoint(eventTime
, 0));
322 // adjust index to round down to earlier checkpoint when exact match not
324 index
= getPrevIndex(index
);
326 LttngTraceState traceState
;
329 // No checkpoint restore is needed, start with a brand new
331 ILttngStateInputRef inputDataRef
= new LttngStateInputRef(fEventLog
);
332 traceState
= StateModelFactory
.getStateEntryInstance(inputDataRef
);
334 // Useful CheckPoint found
335 TmfTraceCheckpoint checkpoint
= timestampCheckpointsList
.get(index
);
336 nearestTimeStamp
= checkpoint
.getTimestamp();
337 // get the location associated with the checkpoint
338 location
= (Long
) (checkpoint
.getLocation());
339 // reference a new copy of the checkpoint template
340 traceState
= stateCheckpointsList
.get(location
).clone();
343 // Make sure eventCount stay consistent!
344 eventCount
= new Long(location
);
346 // Restore the stored traceState
347 stateIn
.setTraceStateModel(traceState
);
349 return nearestTimeStamp
;
353 * Adjust the result from a binary search to the round down position
356 * if Negative is: (-(insertion point) -1)
357 * @return position or if no match found, earlier than insertion point
359 private int getPrevIndex(int position
) {
360 int roundDownPosition
= position
;
362 roundDownPosition
= -(position
+ 2);
365 roundDownPosition
= roundDownPosition
< 0 ?
0 : roundDownPosition
;
366 return roundDownPosition
;
370 // * Restore to the closest checkpoint from position
374 // * The position of the event to restore to
376 // * @return boolean True if a checkpoint was restored, false otherwise
378 // private boolean restoreCheckPointByPosition(long position) {
379 // long nearestCheckPoint = (position - (position %
380 // LTTNG_STATE_SAVE_INTERVAL));
382 // // Some sanity check :
384 // // Not over eventCount
385 // // A checkpoint exist
386 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
387 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
390 // // Restore the stored traceState
391 // stateIn.setTraceStateModel(stateCheckpointsList
392 // .get(nearestCheckPoint));
394 // // Make sure eventCount stay consistent!
395 // eventCount = new Long(nearestCheckPoint);
397 // // * Rewind to the correct position
398 // // To do so, we need a request to the correct window
399 // // We will seek to nearestCheckPoint and read next events until
401 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
402 // (int) nearestCheckPoint, (int) position);
404 // // Process request to that point
405 // fExperiment.processRequest(request, true);
412 * Get a Tmf data request for the current eventlog
415 * @param TmfTimeRange
416 * The time range we want events from.
418 * @return TmfDataRequest<TmfEvent> The request made
420 StateDataRequest
getDataRequestByTimeRange(TmfTimeRange timeWindow
,
421 IStateDataRequestListener listener
) {
423 final TmfEvent
[] evt
= new TmfEvent
[1];
426 // The override of handlePartialResult is similar to the one in
427 // getDataRequestByPosition()
430 // Create the new request and override the handlePartialResult function
431 StateDataRequest request
= new StateDataRequest(timeWindow
,
432 DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
, DEFAULT_CHUNK
,
435 public void handleData() {
436 TmfEvent
[] result
= getData();
438 evt
[0] = (result
.length
> 0) ? result
[0] : null;
439 // Dispatch information for Event processing
440 stateIn
.processEvent(evt
[0]);
442 // increment internal and external number of events
443 setNumOfEvents(getNumOfEvents() + 1);
448 public void handleCompleted() {
449 if (isCancelled() || isFailed()) {
450 // No notification to end request handlers
452 // notify the associated end request handlers
464 private StateDataRequest
getDataRequestStateSave(TmfTimeRange timeWindow
,
465 IStateDataRequestListener requestListener
) {
467 final TmfEvent
[] evt
= new TmfEvent
[1];
470 // The override of handlePartialResult is similar to the one in
471 // getDataRequestByPosition()
474 // Create the new request and override the handlePartialResult function
475 StateDataRequest request
= new StateDataRequest(timeWindow
,
476 DEFAULT_OFFSET
, TmfDataRequest
.ALL_DATA
, DEFAULT_CHUNK
,
477 requestListener
, this) {
480 public void handleData() {
481 TmfEvent
[] result
= getData();
483 evt
[0] = (result
.length
> 0) ? result
[0] : null;
484 // Dispatch information for Event processing
485 stateIn
.processEvent(evt
[0]);
487 // Call the function that will save a checkpoint if needed at
489 // Note : We call this function before incrementing eventCount
490 // to avoid skipping the "0th" event
491 if (evt
[0] != null) {
492 saveCheckPointIfNeeded(getNumOfEvents(), evt
[0]
496 // increment internal and external counters
497 setNumOfEvents(getNumOfEvents() + 1);
502 public void handleCompleted() {
503 if (isCancelled() || isFailed()) {
504 // No notification to end request handlers
506 // notify the associated end request handlers
512 TraceDebug
.debug("number of events processed on file opening"
521 // * Get a Tmf data request for the current eventlog
524 // * @param startPosition
525 // * The position to start the get request from
526 // * @param endPosition
527 // * The position to ed the get request at
529 // * @return TmfDataRequest<TmfEvent> The request made
531 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
532 // long startPosition, long endPosition) {
533 // final TmfEvent[] evt = new TmfEvent[1];
536 // // The override of handlePartialResult is exactly the same as the one in
537 // // getDataRequestByPosition()
538 // // However, there is no way to override it in only one place to avoid
539 // // code duplication!
542 // // Create the new request and override the handlePartialResult function
543 // TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(
544 // (int) startPosition, DEFAULT_OFFSET,
545 // (int) (endPosition - startPosition), DEFAULT_CHUNK) {
547 // public void handlePartialResult() {
548 // TmfEvent[] result = getData();
550 // evt[0] = (result.length > 0) ? result[0] : null;
551 // // Dispatch information for Event processing
552 // stateIn.processEvent(evt[0]);
562 public TmfTimeRange
getExperimentTimeWindow() {
563 if (fExperiment
!= null) {
564 return fExperiment
.getTimeRange();
570 * This method has to be called once all events of the associated Trace have
571 * been processed, this method then triggers the drawing of the final state
572 * which is necessary e.g when zooming.
574 public synchronized void requestCompleted() {
575 Set
<AbsEventProcessorFactory
> handlerRegister
= EventProcessorProxy
576 .getInstance().getProcessingFactories();
577 // Notify the FINISH handlers
578 for (Iterator
<AbsEventProcessorFactory
> iterator
= handlerRegister
579 .iterator(); iterator
.hasNext();) {
580 AbsEventProcessorFactory handlerRegistry
= (AbsEventProcessorFactory
) iterator
582 IEventProcessing handler
= handlerRegistry
.getfinishProcessor();
583 if (handler
!= null) {
584 // process State Update
585 handler
.process(null, stateIn
.traceStateModel
);