Remove all existing @since annotations
[deliverable/tracecompass.git] / 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
AM
171 /**
172 * Get the event type this provider handles
173 *
174 * @return The type of ITmfEvent
175 */
0f89d4ba 176 public Class<? extends ITmfEvent> getType() {
fd3f1eff
AM
177 return fType;
178 }
179
180 // ------------------------------------------------------------------------
181 // ITmfRequestHandler
00641a97
FC
182 // ------------------------------------------------------------------------
183
5419a136 184 @Override
fd3f1eff
AM
185 public void sendRequest(final ITmfEventRequest request) {
186 synchronized (fLock) {
5a597798
GB
187
188 if (TmfCoreTracer.isRequestTraced()) {
189 TmfCoreTracer.traceRequest(request.getRequestId(), "SENT to provider " + getName()); //$NON-NLS-1$
190 }
191
8a580390
BH
192 if (request.getProviderFilter() == null) {
193 request.setProviderFilter(this);
6badfac0
BH
194 }
195
6ae0ee68
BH
196 if (sendWithParent(request)) {
197 return;
198 }
199
8967c8c0
BH
200 if (request.getExecType() == ExecutionType.FOREGROUND) {
201 if ((fSignalDepth > 0) || (fRequestPendingCounter > 0)) {
202 coalesceEventRequest(request);
203 } else {
f45257df 204 queueRequest(request);
8967c8c0
BH
205 }
206 return;
207 }
208
506219d0
BH
209 /*
210 * Dispatch request in case timer is not running.
211 */
212 if (fTimer == null) {
213 queueRequest(request);
214 return;
215 }
216
8967c8c0 217 coalesceEventRequest(request);
6ae0ee68 218
2b5c3b7e
BH
219 if (fIsTimerEnabled) {
220 fCurrentTask.cancel();
221 fCurrentTask = new TimerTask() {
222 @Override
223 public void run() {
224 synchronized (fLock) {
225 fireRequest(true);
226 }
8967c8c0 227 }
2b5c3b7e
BH
228 };
229 fTimer.schedule(fCurrentTask, DELAY);
230 }
fd3f1eff
AM
231 }
232 }
233
2b5c3b7e 234 private void fireRequest(boolean isTimeout) {
fd3f1eff
AM
235 synchronized (fLock) {
236 if (fRequestPendingCounter > 0) {
237 return;
238 }
8967c8c0 239
fd3f1eff 240 if (fPendingCoalescedRequests.size() > 0) {
8967c8c0
BH
241 Iterator<TmfCoalescedEventRequest> iter = fPendingCoalescedRequests.iterator();
242 while (iter.hasNext()) {
2b5c3b7e 243 ExecutionType type = (isTimeout ? ExecutionType.BACKGROUND : ExecutionType.FOREGROUND);
8967c8c0
BH
244 ITmfEventRequest request = iter.next();
245 if (type == request.getExecType()) {
f45257df 246 queueRequest(request);
8967c8c0
BH
247 iter.remove();
248 }
fd3f1eff 249 }
fd3f1eff 250 }
5419a136 251 }
5419a136
AM
252 }
253
fd3f1eff
AM
254 /**
255 * Increments/decrements the pending requests counters and fires the request
256 * if necessary (counter == 0). Used for coalescing requests across multiple
257 * TmfDataProvider's.
258 *
259 * @param isIncrement
260 * Should we increment (true) or decrement (false) the pending
261 * counter
262 */
5419a136 263 @Override
fd3f1eff
AM
264 public void notifyPendingRequest(boolean isIncrement) {
265 synchronized (fLock) {
266 if (isIncrement) {
8967c8c0 267 fRequestPendingCounter++;
fd3f1eff
AM
268 } else {
269 if (fRequestPendingCounter > 0) {
270 fRequestPendingCounter--;
271 }
272
273 // fire request if all pending requests are received
274 if (fRequestPendingCounter == 0) {
2b5c3b7e 275 fireRequest(false);
6badfac0 276 fireRequest(true);
fd3f1eff
AM
277 }
278 }
279 }
280 }
281
282 // ------------------------------------------------------------------------
283 // Coalescing
284 // ------------------------------------------------------------------------
285
286 /**
287 * Create a new request from an existing one, and add it to the coalesced
288 * requests
289 *
290 * @param request
291 * The request to copy
292 */
8967c8c0
BH
293 protected void newCoalescedEventRequest(ITmfEventRequest request) {
294 synchronized (fLock) {
672a642a 295 TmfCoalescedEventRequest coalescedRequest = new TmfCoalescedEventRequest(
fd3f1eff
AM
296 request.getDataType(),
297 request.getRange(),
298 request.getIndex(),
299 request.getNbRequested(),
300 request.getExecType());
301 coalescedRequest.addRequest(request);
8a580390 302 coalescedRequest.setProviderFilter(this);
5419a136 303 if (TmfCoreTracer.isRequestTraced()) {
8b56808c
GB
304 TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$
305 TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$
5419a136 306 }
6ae0ee68 307 coalesceChildrenRequests(coalescedRequest);
5419a136 308 fPendingCoalescedRequests.add(coalescedRequest);
8967c8c0 309 }
fd3f1eff
AM
310 }
311
312 /**
313 * Add an existing requests to the list of coalesced ones
314 *
315 * @param request
316 * The request to add to the list
317 */
318 protected void coalesceEventRequest(ITmfEventRequest request) {
319 synchronized (fLock) {
2b5c3b7e 320 for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) {
fd3f1eff
AM
321 if (coalescedRequest.isCompatible(request)) {
322 coalescedRequest.addRequest(request);
323 if (TmfCoreTracer.isRequestTraced()) {
8b56808c
GB
324 TmfCoreTracer.traceRequest(request.getRequestId(), "COALESCED with " + coalescedRequest.getRequestId()); //$NON-NLS-1$
325 TmfCoreTracer.traceRequest(coalescedRequest.getRequestId(), "now contains " + coalescedRequest.getSubRequestIds()); //$NON-NLS-1$
fd3f1eff 326 }
6ae0ee68 327 coalesceChildrenRequests(coalescedRequest);
fd3f1eff
AM
328 return;
329 }
330 }
331 newCoalescedEventRequest(request);
332 }
333 }
334
6ae0ee68
BH
335 /*
336 * Sends a request with the parent if compatible.
337 */
338 private boolean sendWithParent(final ITmfEventRequest request) {
339 ITmfEventProvider parent = getParent();
340 if (parent instanceof TmfEventProvider) {
341 return ((TmfEventProvider) parent).sendIfCompatible(request);
342 }
343 return false;
344 }
345
346 /*
347 * Sends a request if compatible with a pending coalesced request.
8967c8c0 348 */
6ae0ee68 349 private boolean sendIfCompatible(ITmfEventRequest request) {
8967c8c0 350 synchronized (fLock) {
2b5c3b7e 351 for (TmfCoalescedEventRequest coalescedRequest : getPendingRequests()) {
6ae0ee68
BH
352 if (coalescedRequest.isCompatible(request)) {
353 // Send so it can be coalesced with the parent(s)
354 sendRequest(request);
355 return true;
356 }
357 }
358 }
359 return sendWithParent(request);
360 }
361
362 /*
363 * Coalesces children requests with given request if compatible.
364 */
365 private void coalesceChildrenRequests(final TmfCoalescedEventRequest request) {
366 synchronized (fChildren) {
367 for (TmfEventProvider child : fChildren) {
368 child.coalesceCompatibleRequests(request);
369 }
370 }
371 }
372
373
374 /*
375 * Coalesces all pending requests that are compatible with coalesced request.
376 */
377 private void coalesceCompatibleRequests(TmfCoalescedEventRequest request) {
2b5c3b7e 378 Iterator<TmfCoalescedEventRequest> iter = getPendingRequests().iterator();
6ae0ee68
BH
379 while (iter.hasNext()) {
380 TmfCoalescedEventRequest pendingRequest = iter.next();
381 if (request.isCompatible(pendingRequest)) {
382 request.addRequest(pendingRequest);
383 if (TmfCoreTracer.isRequestTraced()) {
384 TmfCoreTracer.traceRequest(pendingRequest.getRequestId(), "COALESCED with " + request.getRequestId()); //$NON-NLS-1$
385 TmfCoreTracer.traceRequest(request.getRequestId(), "now contains " + request.getSubRequestIds()); //$NON-NLS-1$
8967c8c0 386 }
6ae0ee68 387 iter.remove();
8967c8c0
BH
388 }
389 }
8967c8c0
BH
390 }
391
fd3f1eff
AM
392 // ------------------------------------------------------------------------
393 // Request processing
394 // ------------------------------------------------------------------------
395
fd3f1eff
AM
396 /**
397 * Queue a request.
398 *
399 * @param request
400 * The data request
401 */
402 protected void queueRequest(final ITmfEventRequest request) {
403
404 if (fExecutor.isShutdown()) {
405 request.cancel();
406 return;
407 }
408
409 TmfEventThread thread = new TmfEventThread(this, request);
410
411 if (TmfCoreTracer.isRequestTraced()) {
8b56808c 412 TmfCoreTracer.traceRequest(request.getRequestId(), "QUEUED"); //$NON-NLS-1$
fd3f1eff
AM
413 }
414
415 fExecutor.execute(thread);
416 }
417
fd3f1eff
AM
418 /**
419 * Initialize the provider based on the request. The context is provider
420 * specific and will be updated by getNext().
421 *
422 * @param request
423 * The request
424 * @return An application specific context; null if request can't be
425 * serviced
fd3f1eff
AM
426 */
427 public abstract ITmfContext armRequest(ITmfEventRequest request);
428
429 /**
430 * Checks if the data meets the request completion criteria.
431 *
432 * @param request
433 * The request
434 * @param event
435 * The data to verify
436 * @param nbRead
437 * The number of events read so far
438 * @return true if completion criteria is met
439 */
440 public boolean isCompleted(ITmfEventRequest request, ITmfEvent event, int nbRead) {
441 boolean requestCompleted = isCompleted2(request, nbRead);
442 if (!requestCompleted) {
443 ITmfTimestamp endTime = request.getRange().getEndTime();
065cc19b 444 return event.getTimestamp().compareTo(endTime) > 0;
fd3f1eff
AM
445 }
446 return requestCompleted;
447 }
448
449 private static boolean isCompleted2(ITmfEventRequest request,int nbRead) {
450 return request.isCompleted() || nbRead >= request.getNbRequested();
451 }
452
453 // ------------------------------------------------------------------------
454 // Pass-through's to the request executor
455 // ------------------------------------------------------------------------
456
457 /**
458 * @return the shutdown state (i.e. if it is accepting new requests)
fd3f1eff
AM
459 */
460 protected boolean executorIsShutdown() {
461 return fExecutor.isShutdown();
462 }
463
464 /**
465 * @return the termination state
fd3f1eff
AM
466 */
467 protected boolean executorIsTerminated() {
468 return fExecutor.isTerminated();
469 }
470
471 // ------------------------------------------------------------------------
472 // Signal handlers
473 // ------------------------------------------------------------------------
474
475 /**
476 * Handler for the start synch signal
477 *
478 * @param signal
479 * Incoming signal
480 */
481 @TmfSignalHandler
482 public void startSynch(TmfStartSynchSignal signal) {
483 synchronized (fLock) {
484 fSignalDepth++;
485 }
486 }
487
488 /**
489 * Handler for the end synch signal
490 *
491 * @param signal
492 * Incoming signal
493 */
494 @TmfSignalHandler
495 public void endSynch(TmfEndSynchSignal signal) {
496 synchronized (fLock) {
497 fSignalDepth--;
498 if (fSignalDepth == 0) {
2b5c3b7e 499 fireRequest(false);
fd3f1eff 500 }
5419a136
AM
501 }
502 }
951d134a 503
d77f31da
BH
504 @Override
505 public ITmfEventProvider getParent() {
506 synchronized (fLock) {
507 return fParent;
508 }
509 }
510
511 @Override
512 public void setParent(ITmfEventProvider parent) {
513 if (!(parent instanceof TmfEventProvider)) {
514 throw new IllegalArgumentException();
515 }
516
517 synchronized (fLock) {
518 fParent = (TmfEventProvider) parent;
519 }
520 }
521
522 @Override
523 public List<ITmfEventProvider> getChildren() {
524 synchronized (fChildren) {
525 List<ITmfEventProvider> list = new ArrayList<>();
526 list.addAll(fChildren);
527 return list;
528 }
529 }
530
531 @Override
532 public <T extends ITmfEventProvider> List<T> getChildren(Class<T> clazz) {
533 List<T> list = new ArrayList<>();
534 synchronized (fChildren) {
535 for (TmfEventProvider child : fChildren) {
536 if (clazz.isAssignableFrom(child.getClass())) {
537 list.add(clazz.cast(child));
538 }
539 }
540 }
541 return list;
542 }
543
544 @Override
545 public ITmfEventProvider getChild(String name) {
546 synchronized (fChildren) {
547 for (TmfEventProvider child : fChildren) {
548 if (child.getName().equals(name)) {
549 return child;
550 }
551 }
552 }
553 return null;
554 }
555
d77f31da
BH
556 @Override
557 public ITmfEventProvider getChild(int index) {
5db5a3a4 558 return NonNullUtils.checkNotNull(fChildren.get(index));
d77f31da
BH
559 }
560
561 @Override
562 public void addChild(ITmfEventProvider child) {
563 if (!(child instanceof TmfEventProvider)) {
564 throw new IllegalArgumentException();
565 }
fa62dc1d 566 child.setParent(this);
d77f31da
BH
567 fChildren.add((TmfEventProvider)child);
568 }
569
570 @Override
571 public int getNbChildren() {
572 return fChildren.size();
573 }
2b5c3b7e 574
8a580390
BH
575 /**
576 * Returns true if an event was provided by this event provider or one of
577 * its children event providers else false.
578 *
579 * @param event
580 * the event to check
581 * @return <code>true</code> if event was provided by this provider or one
582 * of its children else <code>false</code>
583 */
6badfac0 584 @Override
8a580390 585 public boolean matches(ITmfEvent event) {
6badfac0
BH
586 if ((event.getTrace() == this)) {
587 return true;
588 }
589 if (fChildren.size() > 0) {
590 synchronized (fLock) {
591 List <TmfEventProvider> children = getChildren(TmfEventProvider.class);
592 for (TmfEventProvider child : children) {
8a580390 593 if (child.matches(event)) {
6badfac0
BH
594 return true;
595 }
596 }
597 }
598 }
599 return false;
600 }
601
2b5c3b7e
BH
602 // ------------------------------------------------------------------------
603 // Debug code (will also used in tests using reflection)
604 // ------------------------------------------------------------------------
605
606 /**
607 * Gets a list of all pending requests. Debug code.
608 *
609 * @return a list of all pending requests
610 */
611 private List<TmfCoalescedEventRequest> getPendingRequests() {
612 return fPendingCoalescedRequests;
613 }
614
615 /**
616 * Clears all pending requests. Debug code.
617 */
618 private void clearPendingRequests() {
619 fPendingCoalescedRequests.clear();
620 }
621
622 /**
623 * Enables/disables the timer. Debug code.
624 *
625 * @param enabled
626 * the enable flag to set
627 */
628 private void setTimerEnabled(Boolean enabled) {
629 fIsTimerEnabled = enabled;
630 }
8c8bf09f 631}
This page took 0.104461 seconds and 5 git commands to generate.