[Bug292967] Second part of request coalescing + unit tests + minor fixes.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.lttng / src / org / eclipse / linuxtools / lttng / state / StateManager.java
CommitLineData
88144d4a
ASL
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
13package org.eclipse.linuxtools.lttng.state;
14
15import java.util.Collections;
16import java.util.HashMap;
17import java.util.Iterator;
18import java.util.Observable;
19import java.util.Set;
20import java.util.Vector;
21
22import org.eclipse.linuxtools.lttng.TraceDebug;
e31e01e8 23import org.eclipse.linuxtools.lttng.event.LttngEvent;
88144d4a
ASL
24import org.eclipse.linuxtools.lttng.event.LttngTimestamp;
25import org.eclipse.linuxtools.lttng.state.evProcessor.AbsEventProcessorFactory;
26import org.eclipse.linuxtools.lttng.state.evProcessor.EventProcessorProxy;
27import org.eclipse.linuxtools.lttng.state.evProcessor.IEventProcessing;
28import org.eclipse.linuxtools.lttng.state.model.ILttngStateInputRef;
29import org.eclipse.linuxtools.lttng.state.model.LttngTraceState;
30import org.eclipse.linuxtools.lttng.state.model.StateModelFactory;
31import org.eclipse.linuxtools.tmf.event.TmfEvent;
32import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
33import org.eclipse.linuxtools.tmf.event.TmfTimestamp;
e31e01e8 34import org.eclipse.linuxtools.tmf.experiment.TmfExperiment;
88144d4a 35import org.eclipse.linuxtools.tmf.request.TmfDataRequest;
9f584e4c
FC
36import org.eclipse.linuxtools.tmf.trace.TmfCheckpoint;
37import org.eclipse.linuxtools.tmf.trace.TmfLocation;
88144d4a 38import org.eclipse.linuxtools.tmf.trace.TmfTrace;
88144d4a
ASL
39
40/**
41 *
42 * @author alvaro
43 *
44 */
45public class StateManager extends Observable {
46
28b94d61 47 private static final long LTTNG_STATE_SAVE_INTERVAL = 5000000L;
88144d4a
ASL
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 // =======================================================================
e31e01e8
FC
56 private TmfExperiment<LttngEvent> fExperiment = null;
57 private TmfTrace<LttngEvent> fEventLog = null;
88144d4a
ASL
58 private StateStacksHandler stateIn = null;
59 private Long eventCount = 0L;
60
61 private HashMap<Long, LttngTraceState> stateCheckpointsList = new HashMap<Long, LttngTraceState>();
9f584e4c 62 private Vector<TmfCheckpoint> timestampCheckpointsList = new Vector<TmfCheckpoint>();
88144d4a
ASL
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 // =======================================================================
d712a5f3
FC
111 /**
112 * A new Experiment or trace selected
113 * @param experiment
114 * @param clearPreviousData
115 */
e31e01e8
FC
116 @SuppressWarnings("unchecked")
117 public void setTraceSelection(TmfExperiment<LttngEvent> experiment,
d712a5f3 118 boolean clearPreviousData) {
88144d4a
ASL
119 // New log in use, read all events and build state transition stack
120 if (experiment != null) {
951d134a
FC
121// if (fExperiment != null && fExperiment != experiment) {
122// this.fExperiment.deregister();
123// }
88144d4a 124
dfaf8391
FC
125 this.fExperiment = experiment;
126
127 // if (fEventLog != null) {
128 // this.fEventLog.dispose();
129 // }
a3fe52fc 130
e31e01e8 131 this.fEventLog = (TmfTrace<LttngEvent>) experiment.getTraces()[0];
dfaf8391 132 try {
a3fe52fc 133 stateIn.init(fEventLog);
dfaf8391
FC
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);
d712a5f3 147 request.setclearDataInd(clearPreviousData);
41dc35d0 148
951d134a 149 request.startRequestInd(fExperiment, true);
dfaf8391
FC
150
151 if (TraceDebug.isDEBUG()) {
dfaf8391
FC
152 StringBuilder sb = new StringBuilder(
153 "Total number of processes in the State provider: "
2211df66 154 + stateIn.getTraceStateModel().getProcesses().length);
dfaf8391
FC
155
156 TmfTimeRange logTimes = fEventLog.getTimeRange();
157 sb.append("\n\tLog file times "
158 + new LttngTimestamp(logTimes.getStartTime()));
159 sb.append(" - " + new LttngTimestamp(logTimes.getEndTime()));
160
161 sb.append("\n\tCheckPoints available at: ");
9f584e4c 162 for (TmfCheckpoint cpoint : timestampCheckpointsList) {
dfaf8391
FC
163 sb.append("\n\t" + cpoint.getTimestamp());
164 }
165 TraceDebug.debug(sb.toString());
88144d4a
ASL
166 }
167 }
168
169 }
170
171 /**
172 * TODO: Not ready for threading
173 * <p>
174 * Read events within specific time window
175 * </p>
176 *
177 * @param trange
178 * @param obs
179 * @param transactionID
180 */
58c60db3 181 public void executeDataRequest(TmfTimeRange trange, String transactionID,
88144d4a
ASL
182 IStateDataRequestListener listener) {
183 TmfTimestamp restoredStartTime = restoreCheckPointByTimestamp(trange
184 .getStartTime());
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)
189 eventCount = 0L;
190
191 // Process request to that point
192 StateDataRequest request = getDataRequestByTimeRange(trange, listener);
41dc35d0 193 // don't wait for completion i.e. allow cancellations
951d134a 194 request.startRequestInd(fExperiment, false);
88144d4a
ASL
195
196 if (TraceDebug.isDEBUG()) {
63eecb47
FC
197 TraceDebug
198 .debug(" Time Window requested, (start adjusted to checkpoint): "
199 + trange.getStartTime()
200 + "-" + trange.getEndTime()
88144d4a 201 + " Total number of processes in the State provider: "
2211df66 202 + stateIn.getTraceStateModel().getProcesses().length + " Completed");
88144d4a
ASL
203 }
204 }
205
206 /**
207 * Current value of event counter
208 *
209 * @return Long The number of events, if it is known
210 */
211 public Long getEventCount() {
212 return eventCount;
213 }
214
215 /**
216 * used to obtain details on the log associated with this manager e.g.
217 * logid.
218 *
219 * @return
220 */
e31e01e8 221 public TmfTrace<LttngEvent> getEventLog() {
88144d4a
ASL
222 return fEventLog;
223 }
224
225 /**
226 * Used for troubleshooting when debug mode is on
227 *
228 * @return Set<String> Set of event that were not handled
229 */
230 public Set<String> getEventsNotHandled() {
231 return stateIn.getEventsNotHandled();
232 }
233
234 /**
235 * Needed for verification purposes
236 *
237 * @param listener
238 * The IEventProcessing we want to register
239 */
240 void registerListener(IEventProcessing listener) {
241 stateIn.registerListener(listener);
242 }
243
244 /**
245 * Needed for verification purposes
246 *
247 * @param listener
248 * The IEventProcessing we want to unregister
249 */
250 void deregisterListener(IEventProcessing listener) {
251 stateIn.deregisterListener(listener);
252 }
253
254 /**
255 * Save a checkpoint if it is needed at that point
256 * <p>
257 * The function will use "eventCount" internally to determine if a save was
258 * needed
259 *
260 * @param eventCounter
261 * The event "count" or event "id" so far
262 * @param eventTime
263 * The timestamp of this event
264 *
265 * @return boolean True if a checkpoint was saved, false otherwise
266 */
9f584e4c 267 private boolean saveCheckPointIfNeeded(Long eventCounter, TmfTimestamp eventTime) {
88144d4a 268 boolean saveHappened = false;
88144d4a 269 // Save a checkpoint every LTTNG_STATE_SAVE_INTERVAL event
9f584e4c 270 if ((eventCounter.longValue() % LTTNG_STATE_SAVE_INTERVAL) == 0) {
88144d4a 271 // Save the checkpoint
9f584e4c 272 stateCheckpointsList.put(eventCounter, stateIn.traceStateModel.clone());
88144d4a
ASL
273 // Save correlation between timestamp and checkpoint index
274
9f584e4c 275 timestampCheckpointsList.add(new TmfCheckpoint(eventTime, new TmfLocation<Long>(eventCounter)));
88144d4a
ASL
276
277 saveHappened = true;
278 }
279
280 return saveHappened;
281 }
282
283 /**
284 * Restore to the closest checkpoint from TmfTimestamp
285 * <p>
286 * Note : it is heavier to restore by timestamp than by event position,
287 * restore by event position whichever possible.
288 *
289 * @param eventTime
290 * The timestamp of the event to restore to
291 *
292 * @return TmfTimestamp indicates the nearest time used to restore the
293 * state, null sent if input is invalid
294 */
9f584e4c 295 @SuppressWarnings("unchecked")
88144d4a
ASL
296 public TmfTimestamp restoreCheckPointByTimestamp(TmfTimestamp eventTime) {
297 TmfTimeRange logRange = fExperiment.getTimeRange();
298 TmfTimestamp nearestTimeStamp = logRange.getStartTime();
299
300 // The GUI can have time limits higher than this log, since GUI can
301 // handle multiple logs
302 if ((eventTime.getValue() < 0)
303 || (eventTime.getValue() > logRange.getEndTime().getValue())) {
304 return null;
305 }
28b94d61 306
88144d4a
ASL
307 // The GUI can have time limits lower than this log, since GUI can
308 // handle multiple logs
309 if ((eventTime.getValue() < logRange.getStartTime().getValue())) {
310 eventTime = logRange.getStartTime();
311 }
28b94d61 312
88144d4a
ASL
313 // Sort the checkpoints, required before the binary search
314 Collections.sort(timestampCheckpointsList);
315 // Initiate the compare with a checkpoint containing the target time
316 // stamp to find
317 int index = Collections.binarySearch(timestampCheckpointsList,
9f584e4c 318 new TmfCheckpoint(eventTime, new TmfLocation<Long>(0L)));
88144d4a
ASL
319 // adjust index to round down to earlier checkpoint when exact match not
320 // found
321 index = getPrevIndex(index);
322
323 LttngTraceState traceState;
9f584e4c 324 TmfLocation<Long> location = new TmfLocation<Long>(0L);
88144d4a
ASL
325 if (index == 0) {
326 // No checkpoint restore is needed, start with a brand new
327 // TraceState
a3fe52fc 328 ILttngStateInputRef inputDataRef = new LttngStateInputRef(fEventLog);
88144d4a
ASL
329 traceState = StateModelFactory.getStateEntryInstance(inputDataRef);
330 } else {
331 // Useful CheckPoint found
9f584e4c 332 TmfCheckpoint checkpoint = timestampCheckpointsList.get(index);
88144d4a
ASL
333 nearestTimeStamp = checkpoint.getTimestamp();
334 // get the location associated with the checkpoint
9f584e4c 335 location = (TmfLocation<Long>) checkpoint.getLocation();
88144d4a
ASL
336 // reference a new copy of the checkpoint template
337 traceState = stateCheckpointsList.get(location).clone();
338 }
339
340 // Make sure eventCount stay consistent!
452ad365 341 eventCount = location.getLocation();
88144d4a
ASL
342
343 // Restore the stored traceState
344 stateIn.setTraceStateModel(traceState);
345
346 return nearestTimeStamp;
347 }
348
349 /**
350 * Adjust the result from a binary search to the round down position
351 *
352 * @param position
353 * if Negative is: (-(insertion point) -1)
354 * @return position or if no match found, earlier than insertion point
355 */
356 private int getPrevIndex(int position) {
357 int roundDownPosition = position;
358 if (position < 0) {
359 roundDownPosition = -(position + 2);
360 }
361
362 roundDownPosition = roundDownPosition < 0 ? 0 : roundDownPosition;
363 return roundDownPosition;
364 }
365
366 // /**
367 // * Restore to the closest checkpoint from position
368 // * <p>
369 // *
370 // * @param position
371 // * The position of the event to restore to
372 // *
373 // * @return boolean True if a checkpoint was restored, false otherwise
374 // */
375 // private boolean restoreCheckPointByPosition(long position) {
376 // long nearestCheckPoint = (position - (position %
377 // LTTNG_STATE_SAVE_INTERVAL));
378 //
379 // // Some sanity check :
380 // // Not under 0
381 // // Not over eventCount
382 // // A checkpoint exist
383 // if ((nearestCheckPoint < 0) || (nearestCheckPoint > eventCount)
384 // || (stateCheckpointsList.get(nearestCheckPoint) == null)) {
385 // return false;
386 // } else {
387 // // Restore the stored traceState
388 // stateIn.setTraceStateModel(stateCheckpointsList
389 // .get(nearestCheckPoint));
390 //
391 // // Make sure eventCount stay consistent!
392 // eventCount = new Long(nearestCheckPoint);
393 //
394 // // * Rewind to the correct position
395 // // To do so, we need a request to the correct window
396 // // We will seek to nearestCheckPoint and read next events until
397 // // position
398 // TmfDataRequest<TmfEvent> request = getDataRequestByPosition(
399 // (int) nearestCheckPoint, (int) position);
400 //
401 // // Process request to that point
402 // fExperiment.processRequest(request, true);
403 //
404 // return true;
405 // }
406 // }
407
408 /**
409 * Get a Tmf data request for the current eventlog
410 * <p>
411 *
412 * @param TmfTimeRange
413 * The time range we want events from.
414 *
415 * @return TmfDataRequest<TmfEvent> The request made
416 */
417 StateDataRequest getDataRequestByTimeRange(TmfTimeRange timeWindow,
418 IStateDataRequestListener listener) {
419
420 final TmfEvent[] evt = new TmfEvent[1];
421
41dc35d0
FC
422 // ***TODO***
423 // The override of handlePartialResult is similar to the one in
88144d4a
ASL
424 // getDataRequestByPosition()
425 // ***
426
427 // Create the new request and override the handlePartialResult function
428 StateDataRequest request = new StateDataRequest(timeWindow,
e31e01e8 429 DEFAULT_OFFSET, TmfDataRequest.ALL_DATA, DEFAULT_CHUNK,
88144d4a
ASL
430 listener, this) {
431 @Override
432 public void handleData() {
433 TmfEvent[] result = getData();
434
435 evt[0] = (result.length > 0) ? result[0] : null;
436 // Dispatch information for Event processing
437 stateIn.processEvent(evt[0]);
438
41dc35d0
FC
439 // increment internal and external number of events
440 setNumOfEvents(getNumOfEvents() + 1);
88144d4a
ASL
441 eventCount++;
442 }
443
cc6eec3e 444 @Override
88144d4a 445 public void handleCompleted() {
41dc35d0
FC
446 if (isCancelled() || isFailed()) {
447 // No notification to end request handlers
448 } else {
449 // notify the associated end request handlers
450 requestCompleted();
451 }
452
453 // notify listeners
88144d4a
ASL
454 notifyCompletion();
455 }
456 };
457
458 return request;
459 }
460
461 private StateDataRequest getDataRequestStateSave(TmfTimeRange timeWindow,
462 IStateDataRequestListener requestListener) {
463
464 final TmfEvent[] evt = new TmfEvent[1];
465
41dc35d0
FC
466 // ***TODO***
467 // The override of handlePartialResult is similar to the one in
88144d4a
ASL
468 // getDataRequestByPosition()
469 // ***
470
471 // Create the new request and override the handlePartialResult function
472 StateDataRequest request = new StateDataRequest(timeWindow,
e31e01e8 473 DEFAULT_OFFSET, TmfDataRequest.ALL_DATA, DEFAULT_CHUNK,
88144d4a
ASL
474 requestListener, this) {
475
476 @Override
477 public void handleData() {
478 TmfEvent[] result = getData();
28b94d61 479
88144d4a
ASL
480 evt[0] = (result.length > 0) ? result[0] : null;
481 // Dispatch information for Event processing
482 stateIn.processEvent(evt[0]);
483
484 // Call the function that will save a checkpoint if needed at
485 // that point
dfaf8391 486 // Note : We call this function before incrementing eventCount
88144d4a
ASL
487 // to avoid skipping the "0th" event
488 if (evt[0] != null) {
489 saveCheckPointIfNeeded(getNumOfEvents(), evt[0]
490 .getTimestamp());
491 }
492
493 // increment internal and external counters
494 setNumOfEvents(getNumOfEvents() + 1);
495 eventCount++;
496 }
497
cc6eec3e 498 @Override
88144d4a 499 public void handleCompleted() {
41dc35d0
FC
500 if (isCancelled() || isFailed()) {
501 // No notification to end request handlers
502 } else {
503 // notify the associated end request handlers
504 requestCompleted();
505 }
88144d4a 506
41dc35d0 507 // notify listeners
88144d4a
ASL
508 notifyCompletion();
509 TraceDebug.debug("number of events processed on file opening"
510 + getNumOfEvents());
511 }
512 };
513
514 return request;
515 }
516
517 // /**
518 // * Get a Tmf data request for the current eventlog
519 // * <p>
520 // *
521 // * @param startPosition
522 // * The position to start the get request from
523 // * @param endPosition
524 // * The position to ed the get request at
525 // *
526 // * @return TmfDataRequest<TmfEvent> The request made
527 // */
528 // private TmfDataRequest<TmfEvent> getDataRequestByPosition(
529 // long startPosition, long endPosition) {
530 // final TmfEvent[] evt = new TmfEvent[1];
531 //
532 // // ***FIXME***
533 // // The override of handlePartialResult is exactly the same as the one in
534 // // getDataRequestByPosition()
535 // // However, there is no way to override it in only one place to avoid
536 // // code duplication!
537 // // ***
538 //
539 // // Create the new request and override the handlePartialResult function
540 // TmfDataRequest<TmfEvent> request = new TmfDataRequest<TmfEvent>(
541 // (int) startPosition, DEFAULT_OFFSET,
542 // (int) (endPosition - startPosition), DEFAULT_CHUNK) {
543 // //@Override
544 // public void handlePartialResult() {
545 // TmfEvent[] result = getData();
546 //
547 // evt[0] = (result.length > 0) ? result[0] : null;
548 // // Dispatch information for Event processing
549 // stateIn.processEvent(evt[0]);
550 // }
551 // };
552 //
553 // return request;
554 // }
555
556 /**
557 * @return
558 */
559 public TmfTimeRange getExperimentTimeWindow() {
560 if (fExperiment != null) {
561 return fExperiment.getTimeRange();
562 }
563 return null;
564 }
565
566 /**
567 * This method has to be called once all events of the associated Trace have
568 * been processed, this method then triggers the drawing of the final state
569 * which is necessary e.g when zooming.
570 */
571 public synchronized void requestCompleted() {
572 Set<AbsEventProcessorFactory> handlerRegister = EventProcessorProxy
573 .getInstance().getProcessingFactories();
574 // Notify the FINISH handlers
575 for (Iterator<AbsEventProcessorFactory> iterator = handlerRegister
576 .iterator(); iterator.hasNext();) {
577 AbsEventProcessorFactory handlerRegistry = (AbsEventProcessorFactory) iterator
578 .next();
579 IEventProcessing handler = handlerRegistry.getfinishProcessor();
580 if (handler != null) {
581 // process State Update
582 handler.process(null, stateIn.traceStateModel);
583 }
584 }
585 }
e31e01e8 586}
This page took 0.052872 seconds and 5 git commands to generate.