[CTF] fix support for traces with per-event contexts
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / request / TmfCoalescedRequest.java
CommitLineData
8584dc20
FC
1/*******************************************************************************
2 * Copyright (c) 2012 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 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.internal.tmf.core.request;
14
15import java.util.ArrayList;
16import java.util.List;
17
18import org.eclipse.core.runtime.IStatus;
19import org.eclipse.core.runtime.MultiStatus;
20import org.eclipse.linuxtools.internal.tmf.core.Activator;
21import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
22import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
23import org.eclipse.linuxtools.tmf.core.request.ITmfRequest;
24import org.eclipse.linuxtools.tmf.core.request.TmfBlockFilter;
25import org.eclipse.linuxtools.tmf.core.request.TmfRangeFilter;
26import org.eclipse.linuxtools.tmf.core.request.TmfRequest;
27
28/**
29 * The TMF coalesced request
30 * <p>
31 * Since different TMF components can issue simultaneous requests to their event
32 * provider (e.g. as the result of a user action), it is desirable to coalesce
33 * these requests when possible in order to reduce costly I/O with the back-end.
34 * <p>
35 * The TmfCoalescedRequest acts as a request aggregator. It bundles compatible
36 * requests and is the one dispatched to the event provider. As each event is
37 * read in sequence, it re-distributes them to its sub-requests as appropriate.
38 * <p>
39 * The sub-request compatibility is evaluated based on the following criteria:
40 * <ul>
41 * <li>Request type (pre-emptible or not)
42 * <li>Block ranges (start index + nb requested) overlap or are contiguous
43 * <li>Time ranges overlap or are contiguous
44 * </ul>
45 *
46 * @author Francois Chouinard
47 * @version 1.0
48 */
49public class TmfCoalescedRequest extends TmfRequest {
50
51 // ------------------------------------------------------------------------
52 // Attributes
53 // ------------------------------------------------------------------------
54
55 /** The list of coalesced requests */
56 private final List<ITmfRequest> fSubRequests = new ArrayList<ITmfRequest>();
57
58 /** The list of coalesced requests */
59 private int fNbSubRequests;
60
61 // ------------------------------------------------------------------------
62 // Constructor
63 // ------------------------------------------------------------------------
64
65 /**
66 * Default constructor
67 */
68 public TmfCoalescedRequest() {
69 this(TmfRequestPriority.NORMAL);
70 }
71
72 /**
73 * Basic constructor
74 * @param priority the request priority
75 */
76 public TmfCoalescedRequest(TmfRequestPriority priority) {
77 super(priority);
78 }
79
80 /**
81 * Create a coalesced request based on the provided request
82 *
83 * @param request the base request
84 */
85 public TmfCoalescedRequest(ITmfRequest request) {
86 super(request != null ? request.getRequestPriority() : null);
87
88 // Initialize sub-requests list with the request
89 if (request != null) {
90 fSubRequests.add(request);
91 fNbSubRequests++;
92 request.setParent(this);
93
94 // Collect the filter values of interestIndex
95 TmfBlockFilter blockFilter = (TmfBlockFilter) request.getEventFilter(TmfBlockFilter.class);
96 long startIndex = blockFilter.getStartIndex();
97 long nbRequested = blockFilter.getNbRequested();
98 addEventFilter(new TmfBlockFilter(startIndex, nbRequested));
99
100 TmfRangeFilter rangeFilter = (TmfRangeFilter) request.getEventFilter(TmfRangeFilter.class);
101 TmfTimeRange timeRange = rangeFilter.getTimeRange();
102 addEventFilter(new TmfRangeFilter(timeRange));
103 }
104 }
105
106 // ------------------------------------------------------------------------
107 // Request execution state
108 // ------------------------------------------------------------------------
109
110 /* (non-Javadoc)
111 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#isCompleted()
112 */
113 @Override
114 public synchronized boolean isCompleted() {
115 for (ITmfRequest request : fSubRequests) {
116 if (!request.isCompleted()) {
117 return false;
118 }
119 }
120 return super.isCompleted();
121 }
122
123 // ------------------------------------------------------------------------
124 // Request completion status
125 // ------------------------------------------------------------------------
126
127 /* (non-Javadoc)
128 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#isCancelled()
129 */
130 @Override
131 public synchronized boolean isCancelled() {
132 for (ITmfRequest request : fSubRequests) {
133 if (!request.isCancelled()) {
134 return false;
135 }
136 }
137 return super.isCancelled();
138 }
139
140 // ------------------------------------------------------------------------
141 // Request operations
142 // ------------------------------------------------------------------------
143
144 /* (non-Javadoc)
145 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#start()
146 */
147 @Override
148 public void start() {
149 for (ITmfRequest request : fSubRequests) {
150 if (!request.isCompleted()) {
151 request.start();
152 }
153 }
154 super.start();
155 }
156
157 /* (non-Javadoc)
158 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#done()
159 */
160 @Override
161 public void done() {
162 if (fRequestStatus == null) {
163 fRequestStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.OK, "OK", null); //$NON-NLS-1$
164 for (ITmfRequest request : fSubRequests) {
165 if (!request.isCompleted()) {
166 request.done();
167 }
168 ((MultiStatus) fRequestStatus).add(request.getStatus());
169 }
170 }
171 super.done();
172 }
173
174 /* (non-Javadoc)
175 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#fail()
176 */
177 @Override
178 public void fail() {
179 fRequestStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.ERROR, "FAIL", null); //$NON-NLS-1$
180 for (ITmfRequest request : fSubRequests) {
181 if (!request.isCompleted()) {
182 request.fail();
183 ((MultiStatus) fRequestStatus).add(request.getStatus());
184 }
185 }
186 super.fail();
187 }
188
189 /* (non-Javadoc)
190 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#cancel()
191 */
192 @Override
193 public void cancel() {
194 fRequestStatus = new MultiStatus(Activator.PLUGIN_ID, IStatus.CANCEL, "CANCEL", null); //$NON-NLS-1$
195 for (ITmfRequest request : fSubRequests) {
196 if (!request.isCompleted()) {
197 request.cancel();
198 }
199 ((MultiStatus) fRequestStatus).add(request.getStatus());
200 }
201 super.cancel();
202 }
203
204 // ------------------------------------------------------------------------
205 // Request processing hooks
206 // ------------------------------------------------------------------------
207
208 /* (non-Javadoc)
209 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#handleEvent(org.eclipse.linuxtools.tmf.core.event.ITmfEvent)
210 */
211 @Override
212 public synchronized void handleEvent(ITmfEvent event) {
213 super.handleEvent(event);
214 for (ITmfRequest request : fSubRequests) {
215 if (!request.isCompleted() && request.matches(event)) {
216 request.handleEvent(event);
217 }
218 }
219 }
220
221 /* (non-Javadoc)
222 * @see org.eclipse.linuxtools.tmf.core.request.ITmfRequest#notifyParent(org.eclipse.linuxtools.tmf.core.request.ITmfRequest)
223 */
224 @Override
140b65fa 225 public synchronized void notifyParent(ITmfRequest child) {
8584dc20
FC
226 if (--fNbSubRequests <= 0) {
227 done();
228 super.notifyParent(this);
229 }
230 }
231
232 // ------------------------------------------------------------------------
233 // Management
234 // ------------------------------------------------------------------------
235
236 /**
237 * Add a request to this one.
238 *
239 * @param request The request to add
240 * @return true if the request was successfully coalesced, false otherwise
241 */
242 public synchronized boolean addRequest(ITmfRequest request) {
243 if (isCompatible(request)) {
244 fSubRequests.add(request);
245 fNbSubRequests++;
246 request.setParent(this);
247 adjustFilters(request);
248 return true;
249 }
250 return false;
251 }
252
253 /**
254 * @return The list of IDs of the sub-requests
255 */
256 @SuppressWarnings("nls")
257 public String getSubRequestIds() {
258 StringBuffer result = new StringBuffer("[");
259 for (int i = 0; i < fSubRequests.size(); i++) {
260 if (i != 0) {
261 result.append(",");
262 }
263 result.append(fSubRequests.get(i).getRequestId());
264 }
265 result.append("]");
266 return result.toString();
267 }
268
269 // ------------------------------------------------------------------------
270 // Compatibility checks
271 // ------------------------------------------------------------------------
272
273 /**
274 * Check if a request is compatible i.e. can be coalesced with the
275 * other sub-requests.
276 * Compatibility is evaluated on the following criteria:
277 * - Request type (pre-emptible or not)
278 * - Block parameters (start index + requested)
279 * - Time range
280 *
281 * @param request The request to evaluate
282 * @return true if the request is compatible, false otherwise
283 */
284 public boolean isCompatible(ITmfRequest request) {
285 if (request.getRequestPriority() != getRequestPriority()) {
286 return false;
287 }
288 // Check the block range
289 TmfBlockFilter blockFilter = (TmfBlockFilter) request.getEventFilter(TmfBlockFilter.class);
290 if (!isCompatible(blockFilter)) {
291 return false;
292 }
293 // Check the time range
294 TmfRangeFilter rangeFilter = (TmfRangeFilter) request.getEventFilter(TmfRangeFilter.class);
295 if (!isCompatible(rangeFilter)) {
296 return false;
297 }
298 return true;
299 }
300
301 /**
302 * Check if the filter time range overlaps the coalesced request time range.
303 * The test boils down to a verification of the intersection of the ranges.
304 *
305 * @param filter the time range filter to test
306 * @return true if the time range is compatible; false otherwise
307 */
308 private boolean isCompatible(TmfRangeFilter filter) {
309 TmfRangeFilter rangeFilter = (TmfRangeFilter) getEventFilter(TmfRangeFilter.class);
310 return rangeFilter.getTimeRange().getIntersection(filter.getTimeRange()) != null;
311 }
312
313 /**
314 * Check if the filter block overlaps the coalesced request block.
315 * The test boils down to a verification that at least one of the block
316 * boundaries falls within the other block boundaries.
317 *
318 * @param filter the block filter to test
319 * @return true if the time range is compatible; false otherwise
320 */
321 private boolean isCompatible(TmfBlockFilter filter) {
322 TmfBlockFilter blockFilter = (TmfBlockFilter) getEventFilter(TmfBlockFilter.class);
323 return filter.getStartIndex() - 1 <= (blockFilter.getEndIndex()) &&
324 filter.getEndIndex() - 1 >= (blockFilter.getStartIndex());
325 }
326
327 // ------------------------------------------------------------------------
328 // Filter adjustments
329 // ------------------------------------------------------------------------
330
331 /**
332 * Adjust the coalesced request filters based on a given request
333 *
334 * @param request the request to consider
335 */
336 private void adjustFilters(ITmfRequest request) {
337 TmfBlockFilter blockFilter = (TmfBlockFilter) request.getEventFilter(TmfBlockFilter.class);
338 adjustFilter(blockFilter);
339 TmfRangeFilter rangeFilter = (TmfRangeFilter) request.getEventFilter(TmfRangeFilter.class);
340 adjustFilter(rangeFilter);
341 }
342
343 /**
344 * @param filter the block filter to adjust
345 */
346 private void adjustFilter(TmfBlockFilter filter) {
347 TmfBlockFilter blockFilter = (TmfBlockFilter) getEventFilter(TmfBlockFilter.class);
348 long startIndex = Math.min(blockFilter.getStartIndex(), filter.getStartIndex());
349 long endIndex = Math.max(blockFilter.getEndIndex(), filter.getEndIndex());
350 long nbRequested = endIndex - startIndex;
351 addEventFilter(new TmfBlockFilter(startIndex, nbRequested));
352 }
353
354 /**
355 * @param filter the time range filter to adjust
356 */
357 private void adjustFilter(TmfRangeFilter filter) {
358 TmfRangeFilter rangeFilter = (TmfRangeFilter) getEventFilter(TmfRangeFilter.class);
359 TmfTimeRange timeRange = rangeFilter.getTimeRange().getUnion(filter.getTimeRange());
360 addEventFilter(new TmfRangeFilter(timeRange));
361 }
362
363 // ------------------------------------------------------------------------
364 // Object
365 // ------------------------------------------------------------------------
366
367 /* (non-Javadoc)
368 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#hashCode()
369 */
370 @Override
371 public int hashCode() {
372 final int prime = 31;
373 int result = super.hashCode();
374 result = prime * result + ((fSubRequests == null) ? 0 : fSubRequests.hashCode());
375 return result;
376 }
377
378 /* (non-Javadoc)
379 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#equals(java.lang.Object)
380 */
381 @Override
382 public boolean equals(Object obj) {
383 if (this == obj) {
384 return true;
385 }
386 if (!super.equals(obj)) {
387 return false;
388 }
389 if (!(obj instanceof TmfCoalescedRequest)) {
390 return false;
391 }
392 TmfCoalescedRequest other = (TmfCoalescedRequest) obj;
393 if (fSubRequests == null) {
394 if (other.fSubRequests != null) {
395 return false;
396 }
397 } else if (!fSubRequests.equals(other.fSubRequests)) {
398 return false;
399 }
400 return true;
401 }
402
403 /* (non-Javadoc)
404 * @see org.eclipse.linuxtools.tmf.core.request.TmfRequest#toString()
405 */
406 @Override
407 @SuppressWarnings("nls")
408 public String toString() {
409 return "TmfCoalescedRequest [fSubRequests=" + fSubRequests + "]";
410 }
411
412}
This page took 0.040163 seconds and 5 git commands to generate.