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