[Bug304438] Introduced TmfLocation
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng / src / org / eclipse / linuxtools / lttng / state / StateManager.java
1 /*******************************************************************************
2 * Copyright (c) 2009 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Alvaro Sanchez-Leon (alvsan09@gmail.com) - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.lttng.state;
14
15 import java.util.Collections;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.Observable;
19 import java.util.Set;
20 import java.util.Vector;
21
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;
39
40 /**
41 *
42 * @author alvaro
43 *
44 */
45 public class StateManager extends Observable {
46
47 private static final long LTTNG_STATE_SAVE_INTERVAL = 5000000L;
48
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;
52
53 // ========================================================================
54 // Data
55 // =======================================================================
56 private TmfExperiment<LttngEvent> fExperiment = null;
57 private TmfTrace<LttngEvent> fEventLog = null;
58 private StateStacksHandler stateIn = null;
59 private Long eventCount = 0L;
60
61 private HashMap<Long, LttngTraceState> stateCheckpointsList = new HashMap<Long, LttngTraceState>();
62 private Vector<TmfCheckpoint> timestampCheckpointsList = new Vector<TmfCheckpoint>();
63
64 // ========================================================================
65 // Constructor
66 // =======================================================================
67
68 // /**
69 // * Default constructor
70 // * <p>
71 // * Instanciate its own StateStacksHandler.
72 // *
73 // */
74 // public StateManager() {
75 // this.stateIn = new StateStacksHandler();
76 // }
77
78 /**
79 * Constructor with parameter
80 * <p>
81 *
82 * @param stateInputHandler
83 * A valid StateStacksHandler
84 *
85 */
86 public StateManager(StateStacksHandler stateInputHandler) {
87 this.stateIn = stateInputHandler;
88 }
89
90 // /**
91 // * Copy constructor
92 // * <p>
93 // *
94 // * @param oldStateManager
95 // * the StateManager we want to copy
96 // *
97 // */
98 // public StateManager(StateManager oldStateManager) {
99 // fEventLog = oldStateManager.fEventLog;
100 // stateIn = oldStateManager.stateIn;
101 // trace = oldStateManager.trace;
102 // eventCount = oldStateManager.eventCount;
103 //
104 // stateCheckpointsList = oldStateManager.stateCheckpointsList;
105 // timestampCheckpointsList = oldStateManager.timestampCheckpointsList;
106 // }
107
108 // ========================================================================
109 // Methods
110 // =======================================================================
111 /**
112 * A new Experiment or trace selected
113 * @param experiment
114 * @param clearPreviousData
115 */
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();
123 }
124
125 this.fExperiment = experiment;
126
127 // if (fEventLog != null) {
128 // this.fEventLog.dispose();
129 // }
130
131 this.fEventLog = (TmfTrace<LttngEvent>) experiment.getTraces()[0];
132 try {
133 stateIn.init(fEventLog);
134 } catch (LttngStateException e) {
135 e.printStackTrace();
136 }
137
138 // Restart count and collections
139 eventCount = 0L;
140 stateCheckpointsList.clear();
141 timestampCheckpointsList.clear();
142
143 // Obtain a dataRequest to pass to the processRequest function
144 TmfTimeRange allTraceWindow = fEventLog.getTimeRange();
145 StateDataRequest request = getDataRequestStateSave(allTraceWindow,
146 null);
147 request.setclearDataInd(clearPreviousData);
148
149 // Wait for completion
150 request.startRequestInd(fExperiment, true, true);
151
152 if (TraceDebug.isDEBUG()) {
153 StringBuilder sb = new StringBuilder(
154 "Total number of processes in the State provider: "
155 + stateIn.getTraceStateModel().getProcesses().length);
156
157 TmfTimeRange logTimes = fEventLog.getTimeRange();
158 sb.append("\n\tLog file times "
159 + new LttngTimestamp(logTimes.getStartTime()));
160 sb.append(" - " + new LttngTimestamp(logTimes.getEndTime()));
161
162 sb.append("\n\tCheckPoints available at: ");
163 for (TmfCheckpoint cpoint : timestampCheckpointsList) {
164 sb.append("\n\t" + cpoint.getTimestamp());
165 }
166 TraceDebug.debug(sb.toString());
167 }
168 }
169
170 }
171
172 /**
173 * TODO: Not ready for threading
174 * <p>
175 * Read events within specific time window
176 * </p>
177 *
178 * @param trange
179 * @param obs
180 * @param transactionID
181 */
182 public void executeDataRequest(TmfTimeRange trange, String transactionID,
183 IStateDataRequestListener listener) {
184 TmfTimestamp restoredStartTime = restoreCheckPointByTimestamp(trange
185 .getStartTime());
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)
190 eventCount = 0L;
191
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);
196
197 if (TraceDebug.isDEBUG()) {
198 TraceDebug
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");
204 }
205 }
206
207 /**
208 * Current value of event counter
209 *
210 * @return Long The number of events, if it is known
211 */
212 public Long getEventCount() {
213 return eventCount;
214 }
215
216 /**
217 * used to obtain details on the log associated with this manager e.g.
218 * logid.
219 *
220 * @return
221 */
222 public TmfTrace<LttngEvent> getEventLog() {
223 return fEventLog;
224 }
225
226 /**
227 * Used for troubleshooting when debug mode is on
228 *
229 * @return Set<String> Set of event that were not handled
230 */
231 public Set<String> getEventsNotHandled() {
232 return stateIn.getEventsNotHandled();
233 }
234
235 /**
236 * Needed for verification purposes
237 *
238 * @param listener
239 * The IEventProcessing we want to register
240 */
241 void registerListener(IEventProcessing listener) {
242 stateIn.registerListener(listener);
243 }
244
245 /**
246 * Needed for verification purposes
247 *
248 * @param listener
249 * The IEventProcessing we want to unregister
250 */
251 void deregisterListener(IEventProcessing listener) {
252 stateIn.deregisterListener(listener);
253 }
254
255 /**
256 * Save a checkpoint if it is needed at that point
257 * <p>
258 * The function will use "eventCount" internally to determine if a save was
259 * needed
260 *
261 * @param eventCounter
262 * The event "count" or event "id" so far
263 * @param eventTime
264 * The timestamp of this event
265 *
266 * @return boolean True if a checkpoint was saved, false otherwise
267 */
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
275
276 timestampCheckpointsList.add(new TmfCheckpoint(eventTime, new TmfLocation<Long>(eventCounter)));
277
278 saveHappened = true;
279 }
280
281 return saveHappened;
282 }
283
284 /**
285 * Restore to the closest checkpoint from TmfTimestamp
286 * <p>
287 * Note : it is heavier to restore by timestamp than by event position,
288 * restore by event position whichever possible.
289 *
290 * @param eventTime
291 * The timestamp of the event to restore to
292 *
293 * @return TmfTimestamp indicates the nearest time used to restore the
294 * state, null sent if input is invalid
295 */
296 @SuppressWarnings("unchecked")
297 public TmfTimestamp restoreCheckPointByTimestamp(TmfTimestamp eventTime) {
298 TmfTimeRange logRange = fExperiment.getTimeRange();
299 TmfTimestamp nearestTimeStamp = logRange.getStartTime();
300
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())) {
305 return null;
306 }
307
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();
312 }
313
314 // Sort the checkpoints, required before the binary search
315 Collections.sort(timestampCheckpointsList);
316 // Initiate the compare with a checkpoint containing the target time
317 // stamp to find
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
321 // found
322 index = getPrevIndex(index);
323
324 LttngTraceState traceState;
325 TmfLocation<Long> location = new TmfLocation<Long>(0L);
326 if (index == 0) {
327 // No checkpoint restore is needed, start with a brand new
328 // TraceState
329 ILttngStateInputRef inputDataRef = new LttngStateInputRef(fEventLog);
330 traceState = StateModelFactory.getStateEntryInstance(inputDataRef);
331 } else {
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();
339 }
340
341 // Make sure eventCount stay consistent!
342 eventCount = location.getValue();
343
344 // Restore the stored traceState
345 stateIn.setTraceStateModel(traceState);
346
347 return nearestTimeStamp;
348 }
349
350 /**
351 * Adjust the result from a binary search to the round down position
352 *
353 * @param position
354 * if Negative is: (-(insertion point) -1)
355 * @return position or if no match found, earlier than insertion point
356 */
357 private int getPrevIndex(int position) {
358 int roundDownPosition = position;
359 if (position < 0) {
360 roundDownPosition = -(position + 2);
361 }
362
363 roundDownPosition = roundDownPosition < 0 ? 0 : roundDownPosition;
364 return roundDownPosition;
365 }
366
367 // /**
368 // * Restore to the closest checkpoint from position
369 // * <p>
370 // *
371 // * @param position
372 // * The position of the event to restore to
373 // *
374 // * @return boolean True if a checkpoint was restored, false otherwise
375 // */
376 // private boolean restoreCheckPointByPosition(long position) {
377 // long nearestCheckPoint = (position - (position %
378 // LTTNG_STATE_SAVE_INTERVAL));
379 //
380 // // Some sanity check :
381 // // Not under 0
382 // // Not over eventCount
383 // // A checkpoint exist
384 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
385 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
386 // return false;
387 // } else {
388 // // Restore the stored traceState
389 // stateIn.setTraceStateModel(stateCheckpointsList
390 // .get(nearestCheckPoint));
391 //
392 // // Make sure eventCount stay consistent!
393 // eventCount = new Long(nearestCheckPoint);
394 //
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
398 // // position
399 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
400 // (int) nearestCheckPoint, (int) position);
401 //
402 // // Process request to that point
403 // fExperiment.processRequest(request, true);
404 //
405 // return true;
406 // }
407 // }
408
409 /**
410 * Get a Tmf data request for the current eventlog
411 * <p>
412 *
413 * @param TmfTimeRange
414 * The time range we want events from.
415 *
416 * @return TmfDataRequest<TmfEvent> The request made
417 */
418 StateDataRequest getDataRequestByTimeRange(TmfTimeRange timeWindow,
419 IStateDataRequestListener listener) {
420
421 final TmfEvent[] evt = new TmfEvent[1];
422
423 // ***TODO***
424 // The override of handlePartialResult is similar to the one in
425 // getDataRequestByPosition()
426 // ***
427
428 // Create the new request and override the handlePartialResult function
429 StateDataRequest request = new StateDataRequest(timeWindow,
430 DEFAULT_OFFSET, TmfDataRequest.ALL_DATA, DEFAULT_CHUNK,
431 listener, this) {
432 @Override
433 public void handleData() {
434 TmfEvent[] result = getData();
435
436 evt[0] = (result.length > 0) ? result[0] : null;
437 // Dispatch information for Event processing
438 stateIn.processEvent(evt[0]);
439
440 // increment internal and external number of events
441 setNumOfEvents(getNumOfEvents() + 1);
442 eventCount++;
443 }
444
445 @Override
446 public void handleCompleted() {
447 if (isCancelled() || isFailed()) {
448 // No notification to end request handlers
449 } else {
450 // notify the associated end request handlers
451 requestCompleted();
452 }
453
454 // notify listeners
455 notifyCompletion();
456 }
457 };
458
459 return request;
460 }
461
462 private StateDataRequest getDataRequestStateSave(TmfTimeRange timeWindow,
463 IStateDataRequestListener requestListener) {
464
465 final TmfEvent[] evt = new TmfEvent[1];
466
467 // ***TODO***
468 // The override of handlePartialResult is similar to the one in
469 // getDataRequestByPosition()
470 // ***
471
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) {
476
477 @Override
478 public void handleData() {
479 TmfEvent[] result = getData();
480
481 evt[0] = (result.length > 0) ? result[0] : null;
482 // Dispatch information for Event processing
483 stateIn.processEvent(evt[0]);
484
485 // Call the function that will save a checkpoint if needed at
486 // that point
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]
491 .getTimestamp());
492 }
493
494 // increment internal and external counters
495 setNumOfEvents(getNumOfEvents() + 1);
496 eventCount++;
497 }
498
499 @Override
500 public void handleCompleted() {
501 if (isCancelled() || isFailed()) {
502 // No notification to end request handlers
503 } else {
504 // notify the associated end request handlers
505 requestCompleted();
506 }
507
508 // notify listeners
509 notifyCompletion();
510 TraceDebug.debug("number of events processed on file opening"
511 + getNumOfEvents());
512 }
513 };
514
515 return request;
516 }
517
518 // /**
519 // * Get a Tmf data request for the current eventlog
520 // * <p>
521 // *
522 // * @param startPosition
523 // * The position to start the get request from
524 // * @param endPosition
525 // * The position to ed the get request at
526 // *
527 // * @return TmfDataRequest<TmfEvent> The request made
528 // */
529 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
530 // long startPosition, long endPosition) {
531 // final TmfEvent[] evt = new TmfEvent[1];
532 //
533 // // ***FIXME***
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!
538 // // ***
539 //
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) {
544 // //@Override
545 // public void handlePartialResult() {
546 // TmfEvent[] result = getData();
547 //
548 // evt[0] = (result.length > 0) ? result[0] : null;
549 // // Dispatch information for Event processing
550 // stateIn.processEvent(evt[0]);
551 // }
552 // };
553 //
554 // return request;
555 // }
556
557 /**
558 * @return
559 */
560 public TmfTimeRange getExperimentTimeWindow() {
561 if (fExperiment != null) {
562 return fExperiment.getTimeRange();
563 }
564 return null;
565 }
566
567 /**
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.
571 */
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
579 .next();
580 IEventProcessing handler = handlerRegistry.getfinishProcessor();
581 if (handler != null) {
582 // process State Update
583 handler.process(null, stateIn.traceStateModel);
584 }
585 }
586 }
587 }
This page took 0.04461 seconds and 5 git commands to generate.