tmf: Fix the actual end time of state system modules
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.core / src / org / eclipse / tracecompass / tmf / core / component / TmfEventProvider.java
CommitLineData
8c8bf09f 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2009, 2015 Ericsson
0283f7ff 3 *
8c8bf09f
ASL
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
0283f7ff 8 *
8c8bf09f 9 * Contributors:
fd3f1eff
AM
10 * Francois Chouinard - Initial API and implementation, replace background
11 * requests by preemptable requests
12 * Alexandre Montplaisir - Merge with TmfDataProvider
8967c8c0 13 * Bernd Hufmann - Add timer based coalescing for background requests
8c8bf09f
ASL
14 *******************************************************************************/
15
2bdf0193 16package org.eclipse.tracecompass.tmf.core.component;
8c8bf09f 17
aa353506
AM
18import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
19
d77f31da
BH
20import java.util.ArrayList;
21import java.util.Collections;
8967c8c0 22import java.util.Iterator;
f45257df 23import java.util.LinkedList;
fd3f1eff 24import java.util.List;
8967c8c0
BH
25import java.util.Timer;
26import java.util.TimerTask;
fd3f1eff 27
6ae0ee68 28import org.eclipse.jdt.annotation.NonNull;
5db5a3a4 29import org.eclipse.tracecompass.common.core.NonNullUtils;
2bdf0193
AM
30import org.eclipse.tracecompass.internal.tmf.core.TmfCoreTracer;
31import org.eclipse.tracecompass.internal.tmf.core.component.TmfEventThread;
32import org.eclipse.tracecompass.internal.tmf.core.component.TmfProviderManager;
33import org.eclipse.tracecompass.internal.tmf.core.request.TmfCoalescedEventRequest;
34import org.eclipse.tracecompass.internal.tmf.core.request.TmfRequestExecutor;
35import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
8a580390 36import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
2bdf0193
AM
37import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
38import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType;
39import org.eclipse.tracecompass.tmf.core.signal.TmfEndSynchSignal;
40import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
41import org.eclipse.tracecompass.tmf.core.signal.TmfStartSynchSignal;
42import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
43import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
8c8bf09f
ASL
44
45/**
fd3f1eff
AM
46 * An abstract base class that implements ITmfEventProvider.
47 * <p>
48 * This abstract class implements the housekeeping methods to register/
49 * de-register the event provider and to handle generically the event requests.
50 * </p>
0283f7ff 51 *
8fd82db5 52 * @author Francois Chouinard
8c8bf09f 53 */
8a580390 54public abstract class TmfEventProvider extends TmfComponent implements ITmfEventProvider, ITmfFilter {
fd3f1eff
AM
55
56 // ------------------------------------------------------------------------
57 // Constants
58 // ------------------------------------------------------------------------
59
ae09c4ad 60 /** Default amount of events per request "chunk" */
fd3f1eff
AM
61 public static final int DEFAULT_BLOCK_SIZE = 50000;
62
8967c8c0
BH
63 /** Delay for coalescing background requests (in milli-seconds) */
64 private static final long DELAY = 1000;
65
fd3f1eff
AM
66 // ------------------------------------------------------------------------
67 // Attributes
68 // ------------------------------------------------------------------------
69
f45257df
AM
70 /** List of coalesced requests */
71 private final List<TmfCoalescedEventRequest> fPendingCoalescedRequests = new LinkedList<>();
fd3f1eff 72
f45257df
AM
73 /** The type of event handled by this provider */
74 private Class<? extends ITmfEvent> fType;
fd3f1eff
AM
75
76 private final TmfRequestExecutor fExecutor;
77
78 private final Object fLock = new Object();
79
80 private int fSignalDepth = 0;
81
82 private int fRequestPendingCounter = 0;
8c8bf09f 83
506219d0 84 private Timer fTimer;
8967c8c0 85
6ae0ee68
BH
86 /** Current timer task */
87 @NonNull private TimerTask fCurrentTask = new TimerTask() { @Override public void run() {} };
88
2b5c3b7e 89 private boolean fIsTimerEnabled;
8967c8c0 90
d77f31da
BH
91 /**
92 * The parent event provider.
93 */
94 private TmfEventProvider fParent = null;
95 /**
96 * The list if children event provider.
97 */
98 private final List<TmfEventProvider> fChildren = Collections.synchronizedList(new ArrayList<TmfEventProvider>());
99
00641a97
FC
100 // ------------------------------------------------------------------------
101 // Constructors
102 // ------------------------------------------------------------------------
103
063f0d27
AM
104 /**
105 * Default constructor
106 */
12c155f5 107 public TmfEventProvider() {
00641a97 108 super();
2b5c3b7e 109 setTimerEnabled(true);
fd3f1eff 110 fExecutor = new TmfRequestExecutor();
12c155f5 111 }
8c8bf09f 112
063f0d27 113 /**
f45257df 114 * Standard constructor. Instantiate and initialize at the same time.
063f0d27
AM
115 *
116 * @param name
fd3f1eff 117 * Name of the provider
063f0d27 118 * @param type
fd3f1eff 119 * The type of events that will be handled
063f0d27 120 */
f45257df 121 public TmfEventProvider(String name, Class<? extends ITmfEvent> type) {
fd3f1eff 122 this();
fd3f1eff 123 init(name, type);
12c155f5
FC
124 }
125
063f0d27 126 /**
f45257df 127 * Initialize this data provider
fd3f1eff
AM
128 *
129 * @param name
130 * Name of the provider
131 * @param type
132 * The type of events that will be handled
133 */
f45257df
AM
134 public void init(String name, Class<? extends ITmfEvent> type) {
135 super.init(name);
136 fType = type;
137 fExecutor.init();
138
139 fSignalDepth = 0;
506219d0
BH
140
141 synchronized (fLock) {
142 fTimer = new Timer();
143 }
144
f45257df 145 TmfProviderManager.register(fType, this);
fd3f1eff
AM
146 }
147
148 @Override
149 public void dispose() {
150 TmfProviderManager.deregister(fType, this);
151 fExecutor.stop();
506219d0
BH
152 synchronized (fLock) {
153 if (fTimer != null) {
154 fTimer.cancel();
155 }
156 fTimer = null;
157 }
d77f31da
BH
158
159 synchronized (fChildren) {
160 for (TmfEventProvider child : fChildren) {
161 child.dispose();
162 }
163 fChildren.clear();
164 }
2b5c3b7e 165 clearPendingRequests();
fd3f1eff 166 super.dispose();
12c155f5
FC
167 }
168
00641a97 169 // ------------------------------------------------------------------------
fd3f1eff
AM
170 // Accessors
171 // ------------------------------------------------------------------------
172
fd3f1eff 173 /**
ea652979 174 * @since 2.0
fd3f1eff 175 */
ea652979
AM
176 @Override
177 public Class<? extends ITmfEvent> getEventType() {
fd3f1eff
AM
178 return fType;
179 }
180
181 // ------------------------------------------------------------------------
182 // ITmfRequestHandler
00641a97
FC
183 // ------------------------------------------------------------------------
184
5419a136 185 @Override
fd3f1eff
AM
186 public void sendRequest(final ITmfEventRequest request) {
187 synchronized (fLock) {
5a597798
GB
188
189 if (TmfCoreTracer.isRequestTraced()) {
190 TmfCoreTracer.traceRequest(request.getRequestId(), "SENT to provider " + getName()); //$NON-NLS-1$
191 }
192
8a580390
BH
193 if (request.getProviderFilter() == null) {
194 request.setProviderFilter(this);
6badfac0
BH
195 }
196
6ae0ee68
BH
197 if (sendWithParent(request)) {
198 return;
199 }
200
8967c8c0
BH
201 if (request.getExecType() == ExecutionType.FOREGROUND) {
202 if ((fSignalDepth > 0) || (fRequestPendingCounter > 0)) {
203 coalesceEventRequest(request);
204 } else {
f45257df 205 queueRequest(request);
8967c8c0
BH
206 }
207 return;
208 }
209
506219d0
BH
210 /*
211 * Dispatch request in case timer is not running.
212 */
213 if (fTimer == null) {
214 queueRequest(request);
215 return;
216 }
217
8967c8c0 218 coalesceEventRequest(request);
6ae0ee68 219
2b5c3b7e
BH
220 if (fIsTimerEnabled) {
221 fCurrentTask.cancel();
222 fCurrentTask = new TimerTask() {
223 @Override
224 public void run() {
225 synchronized (fLock) {
226 fireRequest(true);
227 }
8967c8c0 228 }
2b5c3b7e
BH
229 };
230 fTimer.schedule(fCurrentTask, DELAY);
231 }
fd3f1eff
AM
232 }
233 }
234
2b5c3b7e 235 private void fireRequest(boolean isTimeout) {
fd3f1eff
AM
236 synchronized (fLock) {
237 if (fRequestPendingCounter > 0) {
238 return;
239 }
8967c8c0 240
fd3f1eff 241 if (fPendingCoalescedRequests.size() > 0) {
8967c8c0
BH
242 Iterator<TmfCoalescedEventRequest> iter = fPendingCoalescedRequests.iterator();
243 while (iter.hasNext()) {
2b5c3b7e 244 ExecutionType type = (isTimeout ? ExecutionType.BACKGROUND : ExecutionType.FOREGROUND);
8967c8c0
BH
245 ITmfEventRequest request = iter.next();
246 if (type == request.getExecType()) {
f45257df 247 queueRequest(request);
8967c8c0
BH
248 iter.remove();
249 }
fd3f1eff 250 }
fd3f1eff 251 }
5419a136 252 }
5419a136
AM
253 }
254
fd3f1eff
AM
255 /**
256 * Increments/decrements the pending requests counters and fires the request
257 * if necessary (counter == 0). Used for coalescing requests across multiple
258 * TmfDataProvider's.
259 *
260 * @param isIncrement
261 * Should we increment (true) or decrement (false) the pending
262 * counter
263 */
5419a136 264 @Override
fd3f1eff
AM
265 public void notifyPendingRequest(boolean isIncrement) {
266 synchronized (fLock) {
267 if (isIncrement) {
8967c8c0 268 fRequestPendingCounter++;
fd3f1eff
AM
269 } else {
270 if (fRequestPendingCounter > 0) {
271 fRequestPendingCounter--;
272 }
273
274 // fire request if all pending requests are received
275 if (fRequestPendingCounter == 0) {
2b5c3b7e 276 fireRequest(false);
6badfac0 277 fireRequest(true);
fd3f1eff
AM
278 }
279 }
280 }
281 }
282
283 // ------------------------------------------------------------------------
284 // Coalescing
285 // ------------------------------------------------------------------------
286
287 /**
288 * Create a new request from an existing one, and add it to the coalesced
289 * requests
290 *
291 * @param request
292 * The request to copy
293 */
8967c8c0
BH
294 protected void newCoalescedEventRequest(ITmfEventRequest request) {
295 synchronized (fLock) {
672a642a 296 TmfCoalescedEventRequest coalescedRequest = new TmfCoalescedEventRequest(
fd3f1eff
AM
297 request.getDataType(),
298 request.getRange(),
299 request.getIndex(),
300 request.getNbRequested(),
6eaea67d
BH
301 request.getExecType(),
302 request.getDependencyLevel());
fd3f1eff 303 coalescedRequest.addRequest(request);
8a580390 304 coalescedRequest.setProviderFilter(this);
5419a136 305 if (TmfCoreTracer.isRequestTraced()) {
8b56808c
GB
306 TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$
307 TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$
5419a136 308 }
6ae0ee68 309 coalesceChildrenRequests(coalescedRequest);
5419a136 310 fPendingCoalescedRequests.add(coalescedRequest);
8967c8c0 311 }
fd3f1eff
AM
312 }
313
314 /**
315 * Add an existing requests to the list of coalesced ones
316 *
317 * @param request
318 * The request to add to the list
319 */
320 protected void coalesceEventRequest(ITmfEventRequest request) {
321 synchronized (fLock) {
2b5c3b7e 322 for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) {
fd3f1eff
AM
323 if (coalescedRequest.isCompatible(request)) {
324 coalescedRequest.addRequest(request);
325 if (TmfCoreTracer.isRequestTraced()) {
8b56808c
GB
326 TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$
327 TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$
fd3f1eff 328 }
6ae0ee68 329 coalesceChildrenRequests(coalescedRequest);
fd3f1eff
AM
330 return;
331 }
332 }
333 newCoalescedEventRequest(request);
334 }
335 }
336
6ae0ee68
BH
337 /*
338 * Sends a request with the parent if compatible.
339 */
340 private boolean sendWithParent(final ITmfEventRequest request) {
341 ITmfEventProvider parent = getParent();
342 if (parent instanceof TmfEventProvider) {
343 return ((TmfEventProvider) parent).sendIfCompatible(request);
344 }
345 return false;
346 }
347
348 /*
349 * Sends a request if compatible with a pending coalesced request.
8967c8c0 350 */
6ae0ee68 351 private boolean sendIfCompatible(ITmfEventRequest request) {
8967c8c0 352 synchronized (fLock) {
2b5c3b7e 353 for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) {
6ae0ee68
BH
354 if (coalescedRequest.isCompatible(request)) {
355 // Send so it can be coalesced with the parent(s)
356 sendRequest(request);
357 return true;
358 }
359 }
360 }
361 return sendWithParent(request);
362 }
363
364 /*
365 * Coalesces children requests with given request if compatible.
366 */
367 private void coalesceChildrenRequests(final TmfCoalescedEventRequest request) {
368 synchronized (fChildren) {
369 for (TmfEventProvider child : fChildren) {
370 child.coalesceCompatibleRequests(request);
371 }
372 }
373 }
374
375
376 /*
377 * Coalesces all pending requests that are compatible with coalesced request.
378 */
379 private void coalesceCompatibleRequests(TmfCoalescedEventRequest request) {
2b5c3b7e 380 Iterator<TmfCoalescedEventRequest> iter = getPendingRequests().iterator();
6ae0ee68
BH
381 while (iter.hasNext()) {
382 TmfCoalescedEventRequest pendingRequest = iter.next();
383 if (request.isCompatible(pendingRequest)) {
384 request.addRequest(pendingRequest);
385 if (TmfCoreTracer.isRequestTraced()) {
386 TmfCoreTracer.traceRequest(pendingRequest.getRequestId(), "COALESCED with " + request.getRequestId()); //$NON-NLS-1$
387 TmfCoreTracer.traceRequest(request.getRequestId(), "now contains " + request.getSubRequestIds()); //$NON-NLS-1$
8967c8c0 388 }
6ae0ee68 389 iter.remove();
8967c8c0
BH
390 }
391 }
8967c8c0
BH
392 }
393
fd3f1eff
AM
394 // ------------------------------------------------------------------------
395 // Request processing
396 // ------------------------------------------------------------------------
397
fd3f1eff
AM
398 /**
399 * Queue a request.
400 *
401 * @param request
402 * The data request
403 */
404 protected void queueRequest(final ITmfEventRequest request) {
405
406 if (fExecutor.isShutdown()) {
407 request.cancel();
408 return;
409 }
410
411 TmfEventThread thread = new TmfEventThread(this, request);
412
413 if (TmfCoreTracer.isRequestTraced()) {
8b56808c 414 TmfCoreTracer.traceRequest(request.getRequestId(), "QUEUED"); //$NON-NLS-1$
fd3f1eff
AM
415 }
416
417 fExecutor.execute(thread);
418 }
419
fd3f1eff
AM
420 /**
421 * Initialize the provider based on the request. The context is provider
422 * specific and will be updated by getNext().
423 *
424 * @param request
425 * The request
426 * @return An application specific context; null if request can't be
427 * serviced
fd3f1eff
AM
428 */
429 public abstract ITmfContext armRequest(ITmfEventRequest request);
430
431 /**
432 * Checks if the data meets the request completion criteria.
433 *
434 * @param request
435 * The request
436 * @param event
437 * The data to verify
438 * @param nbRead
439 * The number of events read so far
440 * @return true if completion criteria is met
441 */
442 public boolean isCompleted(ITmfEventRequest request, ITmfEvent event, int nbRead) {
443 boolean requestCompleted = isCompleted2(request, nbRead);
444 if (!requestCompleted) {
445 ITmfTimestamp endTime = request.getRange().getEndTime();
065cc19b 446 return event.getTimestamp().compareTo(endTime) > 0;
fd3f1eff
AM
447 }
448 return requestCompleted;
449 }
450
451 private static boolean isCompleted2(ITmfEventRequest request,int nbRead) {
452 return request.isCompleted() || nbRead >= request.getNbRequested();
453 }
454
455 // ------------------------------------------------------------------------
456 // Pass-through's to the request executor
457 // ------------------------------------------------------------------------
458
459 /**
460 * @return the shutdown state (i.e. if it is accepting new requests)
fd3f1eff
AM
461 */
462 protected boolean executorIsShutdown() {
463 return fExecutor.isShutdown();
464 }
465
466 /**
467 * @return the termination state
fd3f1eff
AM
468 */
469 protected boolean executorIsTerminated() {
470 return fExecutor.isTerminated();
471 }
472
473 // ------------------------------------------------------------------------
474 // Signal handlers
475 // ------------------------------------------------------------------------
476
477 /**
478 * Handler for the start synch signal
479 *
480 * @param signal
481 * Incoming signal
482 */
483 @TmfSignalHandler
484 public void startSynch(TmfStartSynchSignal signal) {
485 synchronized (fLock) {
486 fSignalDepth++;
487 }
488 }
489
490 /**
491 * Handler for the end synch signal
492 *
493 * @param signal
494 * Incoming signal
495 */
496 @TmfSignalHandler
497 public void endSynch(TmfEndSynchSignal signal) {
498 synchronized (fLock) {
499 fSignalDepth--;
500 if (fSignalDepth == 0) {
2b5c3b7e 501 fireRequest(false);
fd3f1eff 502 }
5419a136
AM
503 }
504 }
951d134a 505
d77f31da
BH
506 @Override
507 public ITmfEventProvider getParent() {
508 synchronized (fLock) {
509 return fParent;
510 }
511 }
512
513 @Override
514 public void setParent(ITmfEventProvider parent) {
515 if (!(parent instanceof TmfEventProvider)) {
516 throw new IllegalArgumentException();
517 }
518
519 synchronized (fLock) {
520 fParent = (TmfEventProvider) parent;
521 }
522 }
523
524 @Override
525 public List<ITmfEventProvider> getChildren() {
526 synchronized (fChildren) {
527 List<ITmfEventProvider> list = new ArrayList<>();
528 list.addAll(fChildren);
529 return list;
530 }
531 }
532
533 @Override
534 public <T extends ITmfEventProvider> List<T> getChildren(Class<T> clazz) {
aa353506 535 List<@NonNull T> list = new ArrayList<>();
d77f31da
BH
536 synchronized (fChildren) {
537 for (TmfEventProvider child : fChildren) {
538 if (clazz.isAssignableFrom(child.getClass())) {
aa353506 539 list.add(checkNotNull(clazz.cast(child)));
d77f31da
BH
540 }
541 }
542 }
543 return list;
544 }
545
546 @Override
547 public ITmfEventProvider getChild(String name) {
548 synchronized (fChildren) {
549 for (TmfEventProvider child : fChildren) {
550 if (child.getName().equals(name)) {
551 return child;
552 }
553 }
554 }
555 return null;
556 }
557
d77f31da
BH
558 @Override
559 public ITmfEventProvider getChild(int index) {
5db5a3a4 560 return NonNullUtils.checkNotNull(fChildren.get(index));
d77f31da
BH
561 }
562
563 @Override
564 public void addChild(ITmfEventProvider child) {
565 if (!(child instanceof TmfEventProvider)) {
566 throw new IllegalArgumentException();
567 }
fa62dc1d 568 child.setParent(this);
d77f31da
BH
569 fChildren.add((TmfEventProvider)child);
570 }
571
572 @Override
573 public int getNbChildren() {
574 return fChildren.size();
575 }
2b5c3b7e 576
8a580390
BH
577 /**
578 * Returns true if an event was provided by this event provider or one of
579 * its children event providers else false.
580 *
581 * @param event
582 * the event to check
583 * @return <code>true</code> if event was provided by this provider or one
584 * of its children else <code>false</code>
585 */
6badfac0 586 @Override
8a580390 587 public boolean matches(ITmfEvent event) {
6badfac0
BH
588 if ((event.getTrace() == this)) {
589 return true;
590 }
591 if (fChildren.size() > 0) {
592 synchronized (fLock) {
593 List <TmfEventProvider> children = getChildren(TmfEventProvider.class);
594 for (TmfEventProvider child : children) {
8a580390 595 if (child.matches(event)) {
6badfac0
BH
596 return true;
597 }
598 }
599 }
600 }
601 return false;
602 }
603
2b5c3b7e
BH
604 // ------------------------------------------------------------------------
605 // Debug code (will also used in tests using reflection)
606 // ------------------------------------------------------------------------
607
608 /**
609 * Gets a list of all pending requests. Debug code.
610 *
611 * @return a list of all pending requests
612 */
613 private List<TmfCoalescedEventRequest> getPendingRequests() {
614 return fPendingCoalescedRequests;
615 }
616
617 /**
618 * Clears all pending requests. Debug code.
619 */
620 private void clearPendingRequests() {
621 fPendingCoalescedRequests.clear();
622 }
623
624 /**
625 * Enables/disables the timer. Debug code.
626 *
627 * @param enabled
628 * the enable flag to set
629 */
630 private void setTimerEnabled(Boolean enabled) {
631 fIsTimerEnabled = enabled;
632 }
8c8bf09f 633}
This page took 0.126059 seconds and 5 git commands to generate.