1 | package de.uka.ipd.sdq.reliability.solver.pcm2markov; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.Iterator; |
5 | import java.util.List; |
6 | |
7 | import org.apache.log4j.Logger; |
8 | import org.eclipse.emf.common.util.EList; |
9 | |
10 | import de.uka.ipd.sdq.markov.MarkovChain; |
11 | import de.uka.ipd.sdq.markov.State; |
12 | import de.uka.ipd.sdq.markov.StateType; |
13 | import de.uka.ipd.sdq.pcm.reliability.ExternalFailureOccurrenceDescription; |
14 | import de.uka.ipd.sdq.pcm.reliability.FailureType; |
15 | import de.uka.ipd.sdq.pcm.reliability.HardwareInducedFailureType; |
16 | import de.uka.ipd.sdq.pcm.reliability.InternalFailureOccurrenceDescription; |
17 | import de.uka.ipd.sdq.pcm.reliability.NetworkInducedFailureType; |
18 | import de.uka.ipd.sdq.pcm.reliability.SoftwareInducedFailureType; |
19 | import de.uka.ipd.sdq.pcm.repository.Role; |
20 | import de.uka.ipd.sdq.pcm.repository.Signature; |
21 | import de.uka.ipd.sdq.pcm.resourceenvironment.CommunicationLinkResourceSpecification; |
22 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
23 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
24 | import de.uka.ipd.sdq.pcm.seff.AbstractAction; |
25 | import de.uka.ipd.sdq.pcm.seff.AbstractBranchTransition; |
26 | import de.uka.ipd.sdq.pcm.seff.AbstractInternalControlFlowAction; |
27 | import de.uka.ipd.sdq.pcm.seff.AcquireAction; |
28 | import de.uka.ipd.sdq.pcm.seff.BranchAction; |
29 | import de.uka.ipd.sdq.pcm.seff.CollectionIteratorAction; |
30 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
31 | import de.uka.ipd.sdq.pcm.seff.ForkAction; |
32 | import de.uka.ipd.sdq.pcm.seff.ForkedBehaviour; |
33 | import de.uka.ipd.sdq.pcm.seff.InternalAction; |
34 | import de.uka.ipd.sdq.pcm.seff.LoopAction; |
35 | import de.uka.ipd.sdq.pcm.seff.ReleaseAction; |
36 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingBehaviour; |
37 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingSEFF; |
38 | import de.uka.ipd.sdq.pcm.seff.ServiceEffectSpecification; |
39 | import de.uka.ipd.sdq.pcm.seff.SetVariableAction; |
40 | import de.uka.ipd.sdq.pcm.seff.StartAction; |
41 | import de.uka.ipd.sdq.pcm.seff.StopAction; |
42 | import de.uka.ipd.sdq.pcm.seff.SynchronisationPoint; |
43 | import de.uka.ipd.sdq.pcm.seff.seff_performance.ParametricResourceDemand; |
44 | import de.uka.ipd.sdq.pcm.seff.seff_reliability.FailureHandlingEntity; |
45 | import de.uka.ipd.sdq.pcm.seff.seff_reliability.RecoveryAction; |
46 | import de.uka.ipd.sdq.pcm.seff.seff_reliability.RecoveryActionBehaviour; |
47 | import de.uka.ipd.sdq.pcm.seff.util.SeffSwitch; |
48 | import de.uka.ipd.sdq.pcmsolver.transformations.ContextWrapper; |
49 | import de.uka.ipd.sdq.pcmsolver.visitors.EMFQueryHelper; |
50 | import de.uka.ipd.sdq.probfunction.math.ManagedPMF; |
51 | import de.uka.ipd.sdq.reliability.core.MarkovEvaluationType; |
52 | import de.uka.ipd.sdq.reliability.core.MarkovHardwareInducedFailureType; |
53 | import de.uka.ipd.sdq.reliability.core.MarkovNetworkInducedFailureType; |
54 | import de.uka.ipd.sdq.reliability.core.MarkovSoftwareInducedFailureType; |
55 | |
56 | /** |
57 | * This class represents a visitor for an RDSEFF within a PCM instance. The |
58 | * visitor is used in the transformation from PCM with solved dependencies into |
59 | * a Markov Chain Model for reliability prediction. |
60 | * |
61 | * @author brosch |
62 | */ |
63 | public class MarkovSeffVisitor extends SeffSwitch<MarkovChain> { |
64 | |
65 | /** |
66 | * A logger to give detailed information about the PCM instance traversal. |
67 | */ |
68 | private static Logger logger = Logger.getLogger(MarkovSeffVisitor.class |
69 | .getName()); |
70 | |
71 | /** |
72 | * The ContextWrapper provides easy access to the decorations of the solved |
73 | * PCM instance. |
74 | */ |
75 | private ContextWrapper contextWrapper; |
76 | |
77 | /** |
78 | * The degree of distinction between failure types. |
79 | */ |
80 | private MarkovEvaluationType evaluationType; |
81 | |
82 | /** |
83 | * The Markov Builder is used to create Markov Chain instances. |
84 | */ |
85 | private MarkovBuilder markovBuilder; |
86 | |
87 | /** |
88 | * Indicates if the Markov Chain reduction is performed during the |
89 | * transformation. If so, then the chain as a whole never exists, because |
90 | * during construction, it is already reduced again. |
91 | */ |
92 | private boolean optimize; |
93 | |
94 | /** |
95 | * The prefix list enables unique naming of all Markov states, which in turn |
96 | * allows to search for differences between two chains. |
97 | */ |
98 | private List<String> prefixes; |
99 | |
100 | /** |
101 | * Indicates if the resulting Makov model shall be augmented with tracing |
102 | * information for diagnostic purposes. |
103 | */ |
104 | private boolean recordTraces; |
105 | |
106 | /** |
107 | * Indicates if resource states are handled according to the simpler |
108 | * "always ask" strategy, which may yield less accurate results, but avoids |
109 | * iterating over all possible state combinations. |
110 | */ |
111 | private boolean simplifiedStateHandling; |
112 | |
113 | /** |
114 | * A provider of information about the PCM instance and the corresponding |
115 | * resource descriptors. |
116 | */ |
117 | private MarkovTransformationSource transformationState; |
118 | |
119 | /** |
120 | * The constructor. |
121 | * |
122 | * @param transformationState |
123 | * the Markov transformation state |
124 | * @param wrapper |
125 | * the ContextWrapper provides easy access to the decorations of |
126 | * the solved PCM instance |
127 | * @param prefixes |
128 | * the list of prefixes for state names |
129 | * @param evaluationType |
130 | * the degree of differentiation between failure types |
131 | * @param simplifiedStateHandling |
132 | * controls the handling of physical resource states |
133 | * @param optimize |
134 | * controls if Markov Chain reduction is performed during |
135 | * transformation |
136 | * @param recordTraces |
137 | * controls if traces shall be recorded during transformation |
138 | */ |
139 | public MarkovSeffVisitor( |
140 | final MarkovTransformationSource transformationState, |
141 | final ContextWrapper wrapper, final List<String> prefixes, |
142 | final MarkovEvaluationType evaluationType, |
143 | final boolean simplifiedStateHandling, final boolean optimize, |
144 | final boolean recordTraces) { |
145 | this.transformationState = transformationState; |
146 | this.contextWrapper = wrapper; |
147 | this.prefixes = prefixes; |
148 | this.evaluationType = evaluationType; |
149 | this.optimize = optimize; |
150 | this.recordTraces = recordTraces; |
151 | this.simplifiedStateHandling = simplifiedStateHandling; |
152 | this.markovBuilder = new MarkovBuilder(recordTraces); |
153 | } |
154 | |
155 | /** |
156 | * Adds a new failure description to a list of existing descriptions. |
157 | * |
158 | * @param failureDescriptions |
159 | * the list of descriptions |
160 | * @param newFailureDescription |
161 | * the failure description to add |
162 | */ |
163 | private void addFailureDescription( |
164 | List<FailureDescription> failureDescriptions, |
165 | FailureDescription newFailureDescription) { |
166 | FailureDescription existingFailureDescription = null; |
167 | Iterator<FailureDescription> iterator = failureDescriptions.iterator(); |
168 | while (iterator.hasNext()) { |
169 | FailureDescription comparator = iterator.next(); |
170 | if (newFailureDescription.getFailureType().equals( |
171 | comparator.getFailureType())) { |
172 | existingFailureDescription = comparator; |
173 | break; |
174 | } |
175 | } |
176 | if (existingFailureDescription == null) { |
177 | failureDescriptions.add(newFailureDescription); |
178 | } else { |
179 | existingFailureDescription |
180 | .setFailureProbability(existingFailureDescription |
181 | .getFailureProbability() |
182 | + newFailureDescription.getFailureProbability()); |
183 | } |
184 | } |
185 | |
186 | /** |
187 | * Handles RecoveryActions. |
188 | * |
189 | * This is a workaround using the case for |
190 | * AbstractInternalControlFlowActions, because RecoveryActions are not |
191 | * directly contained in the SEFF package, and thus there is no case for |
192 | * them. |
193 | * |
194 | * First, for each RecoveryActionBehaviour a specific Markov chain is built. |
195 | * Then, specific chains are appended to each other according to the |
196 | * specification of handled failure types. |
197 | * |
198 | * @param controlFlowAction |
199 | * the control flow action |
200 | * @return the resulting Markov Chain. |
201 | */ |
202 | @Override |
203 | public MarkovChain caseAbstractInternalControlFlowAction( |
204 | final AbstractInternalControlFlowAction controlFlowAction) { |
205 | |
206 | // Only consider RecoveryBlockActions: |
207 | if (!(controlFlowAction instanceof RecoveryAction)) { |
208 | return null; |
209 | } |
210 | RecoveryAction action = (RecoveryAction) controlFlowAction; |
211 | |
212 | // Logging & naming: |
213 | String name = action.getEntityName() + "[" + action.getId() + "]"; |
214 | prefixes.add(name); |
215 | logger.debug("Visit RecoveryAction: " + name); |
216 | |
217 | // Retrieve the list of RecoveryBlockBehaviours: |
218 | List<RecoveryActionBehaviour> behaviours = action |
219 | .getRecoveryActionBehaviours__RecoveryAction(); |
220 | if (behaviours.size() == 0) { |
221 | throw new MarkovException("RecoveryAction '" |
222 | + action.getEntityName() |
223 | + "' does not specify any behaviours."); |
224 | } |
225 | |
226 | // Create the resulting Markov chain: |
227 | MarkovChain resultChain = processRecoveryActionBehaviour(action, action |
228 | .getPrimaryBehaviour__RecoveryAction()); |
229 | |
230 | // Naming: |
231 | prefixes.remove(prefixes.size() - 1); |
232 | |
233 | // Return the result: |
234 | return resultChain; |
235 | } |
236 | |
237 | /** |
238 | * An Acquire Action returns a trivial Markov Chain. |
239 | * |
240 | * @param acquireAction |
241 | * the acquire action |
242 | * @return the resulting Markov Chain. |
243 | */ |
244 | @Override |
245 | public MarkovChain caseAcquireAction(final AcquireAction acquireAction) { |
246 | |
247 | // Logging & naming: |
248 | String name = acquireAction.getEntityName() + "[" |
249 | + acquireAction.getId() + "]"; |
250 | prefixes.add(name); |
251 | logger.debug("Visit AcquireAction: " + name); |
252 | |
253 | // Create a Markov chain for the Acquire action: |
254 | MarkovChain resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
255 | |
256 | // Naming: |
257 | prefixes.remove(prefixes.size() - 1); |
258 | |
259 | // Return the result: |
260 | return resultChain; |
261 | } |
262 | |
263 | /** |
264 | * For a BranchAction, first the Markov Chain of each of the transition |
265 | * behaviours is built. The results are then inserted into a new Markov |
266 | * Chain that has one State for each of the possible branches. |
267 | * |
268 | * @param branchAction |
269 | * the BranchAction |
270 | * @return the resulting Markov Chain |
271 | */ |
272 | @Override |
273 | public MarkovChain caseBranchAction(final BranchAction branchAction) { |
274 | |
275 | // Logging & naming: |
276 | String name = branchAction.getEntityName() + "[" + branchAction.getId() |
277 | + "]"; |
278 | prefixes.add(name); |
279 | logger.debug("Visit BranchAction: " + name); |
280 | |
281 | // Determine the inner Markov Chains associated with the branch |
282 | // behaviors: |
283 | EList<AbstractBranchTransition> transitions = branchAction |
284 | .getBranches_Branch(); |
285 | ArrayList<MarkovChain> specificMarkovChains = new ArrayList<MarkovChain>(); |
286 | ArrayList<Double> branchProbabilities = new ArrayList<Double>(); |
287 | double branchProbabilitySum = 0.0; |
288 | for (int i = 0; i < transitions.size(); i++) { |
289 | Double branchProbability = contextWrapper |
290 | .getBranchProbability(transitions.get(i)); |
291 | branchProbabilitySum += branchProbability; |
292 | if (branchProbability > 1.0) { |
293 | throw new MarkovException( |
294 | "Error in solved parametric dependencies detected: " |
295 | + "BranchAction \"" |
296 | + branchAction.getEntityName() |
297 | + "\" has probability " + branchProbability |
298 | + ", which is greater than 1.0"); |
299 | } |
300 | if (branchProbabilitySum > 1.0) { |
301 | throw new MarkovException( |
302 | "Error in solved parametric dependencies detected: " |
303 | + "Branch probabilities of BranchAction \"" |
304 | + branchAction.getEntityName() |
305 | + "\" sum up to more than 1.0"); |
306 | } |
307 | branchProbabilities.add(branchProbability); |
308 | |
309 | // Handle only branches with positive branch probabilities; other |
310 | // branches don't influence the reliability. Furthermore, branches |
311 | // with zero probability could not be handled anyway, because the |
312 | // dependency solver omits them and leaves their parametric |
313 | // dependencies unsolved (see also Bug 615). |
314 | if (branchProbability > 0.0) { |
315 | prefixes.add(transitions.get(i).getEntityName() + "[" |
316 | + transitions.get(i).getId() + "]"); |
317 | specificMarkovChains.add((MarkovChain) doSwitch(transitions |
318 | .get(i).getBranchBehaviour_BranchTransition())); |
319 | prefixes.remove(prefixes.size() - 1); |
320 | } |
321 | } |
322 | |
323 | // Initialize the aggregate Markov Chain representing the loop: |
324 | MarkovChain aggregateMarkovChain = markovBuilder.initBranchMarkovChain( |
325 | prefixes, branchProbabilities); |
326 | |
327 | // Incorporate the specific MarkovChain into the aggregate one: |
328 | ArrayList<State> statesToReplace = new ArrayList<State>(); |
329 | for (int i = 0; i < aggregateMarkovChain.getStates().size(); i++) { |
330 | if (aggregateMarkovChain.getStates().get(i).getType().equals( |
331 | StateType.DEFAULT)) { |
332 | statesToReplace.add(aggregateMarkovChain.getStates().get(i)); |
333 | } |
334 | } |
335 | for (int i = 0; i < statesToReplace.size(); i++) { |
336 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
337 | specificMarkovChains.get(i), statesToReplace.get(i), |
338 | optimize, false); |
339 | } |
340 | |
341 | // Naming: |
342 | prefixes.remove(prefixes.size() - 1); |
343 | |
344 | // Return the result: |
345 | return aggregateMarkovChain; |
346 | } |
347 | |
348 | /** |
349 | * A collection iterator action is handled the same way as an ordinary loop. |
350 | * |
351 | * @param collectionIteratorAction |
352 | * the CollectionIteratoraction |
353 | * @return the resulting Markov Chain |
354 | */ |
355 | @Override |
356 | public MarkovChain caseCollectionIteratorAction( |
357 | final CollectionIteratorAction collectionIteratorAction) { |
358 | |
359 | // Logging & naming: |
360 | String name = collectionIteratorAction.getEntityName() + "[" |
361 | + collectionIteratorAction.getId() + "]"; |
362 | prefixes.add(name); |
363 | logger.debug("Visit CollectionIteratorAction: " + name); |
364 | |
365 | // Determine the inner Markov Chain associated with the loop behaviour: |
366 | ArrayList<String> prefixesCopy = new ArrayList<String>(); |
367 | prefixesCopy.addAll(prefixes); |
368 | prefixes.clear(); |
369 | MarkovChain specificMarkovChain = (MarkovChain) doSwitch(collectionIteratorAction |
370 | .getBodyBehaviour_Loop()); |
371 | prefixes.addAll(prefixesCopy); |
372 | |
373 | // Get the solved loop probability mass function: |
374 | ManagedPMF pmf = contextWrapper |
375 | .getLoopIterations(collectionIteratorAction); |
376 | |
377 | // Initialize the aggregate Markov Chain representing the loop: |
378 | MarkovChain aggregateMarkovChain = markovBuilder.initLoopMarkovChain( |
379 | prefixes, pmf); |
380 | |
381 | // Incorporate the specific MarkovChain into the aggregate one: |
382 | ArrayList<State> statesToReplace = new ArrayList<State>(); |
383 | for (int i = 0; i < aggregateMarkovChain.getStates().size(); i++) { |
384 | if (aggregateMarkovChain.getStates().get(i).getType().equals( |
385 | StateType.DEFAULT)) { |
386 | statesToReplace.add(aggregateMarkovChain.getStates().get(i)); |
387 | } |
388 | } |
389 | for (int i = 0; i < statesToReplace.size(); i++) { |
390 | markovBuilder |
391 | .incorporateMarkovChain(aggregateMarkovChain, |
392 | specificMarkovChain, statesToReplace.get(i), |
393 | optimize, true); |
394 | } |
395 | |
396 | // Naming: |
397 | prefixes.remove(prefixes.size() - 1); |
398 | |
399 | // Return the result: |
400 | return aggregateMarkovChain; |
401 | } |
402 | |
403 | /** |
404 | * Evaluates the availability of a resource container. Returns a |
405 | * corresponding Markov chain. |
406 | * |
407 | * @param descriptors |
408 | * the list of required resources and their states |
409 | * @return the resulting Markov chain |
410 | */ |
411 | private MarkovChain caseContainerAvailability( |
412 | final ResourceContainer container) { |
413 | |
414 | // Check for the requested type of analysis: |
415 | MarkovChain resultChain = null; |
416 | if (simplifiedStateHandling) { |
417 | // Simplified state handling; iterate over all resource states like |
418 | // a branch: |
419 | resultChain = caseContainerAvailabilityForIteratedResourceStates(container); |
420 | } else { |
421 | // Full state handling; container availability is evaluated |
422 | // only once (for the current resource state): |
423 | resultChain = caseContainerAvailabilityForResourceState(container); |
424 | } |
425 | |
426 | // Return the result: |
427 | return resultChain; |
428 | } |
429 | |
430 | /** |
431 | * Evaluates the availability of a resource container through iteration over |
432 | * the possible states of its required resources. Returns a corresponding |
433 | * Markov chain. |
434 | * |
435 | * @param container |
436 | * the resource container |
437 | * @return the resulting Markov chain |
438 | */ |
439 | private MarkovChain caseContainerAvailabilityForIteratedResourceStates( |
440 | final ResourceContainer container) { |
441 | |
442 | // Create the result chain: |
443 | MarkovChain resultChain; |
444 | |
445 | // Retrieve descriptors for the resources required by the container: |
446 | List<ProcessingResourceDescriptor> descriptors = getResourceDescriptors( |
447 | container, true); |
448 | |
449 | // Create the state probabilities and specific state chains: |
450 | ArrayList<Double> stateProbabilities = new ArrayList<Double>(); |
451 | ArrayList<MarkovChain> stateChains = new ArrayList<MarkovChain>(); |
452 | ArrayList<String> prefixesCopy = new ArrayList<String>(); |
453 | prefixesCopy.addAll(prefixes); |
454 | prefixes.clear(); |
455 | for (long i = 0; i < Math.pow(2, descriptors.size()); i++) { |
456 | setResourceState(descriptors, i); |
457 | stateProbabilities.add(getResourceStateProbability(descriptors)); |
458 | stateChains |
459 | .add(caseContainerAvailabilityForResourceState(container)); |
460 | } |
461 | prefixes.addAll(prefixesCopy); |
462 | |
463 | // Initialize the aggregate Markov chain representing the branch: |
464 | resultChain = markovBuilder.initBranchMarkovChain(prefixes, |
465 | stateProbabilities); |
466 | |
467 | // Incorporate the specific Markov chains into the aggregate one: |
468 | ArrayList<State> statesToReplace = new ArrayList<State>(); |
469 | for (int i = 0; i < resultChain.getStates().size(); i++) { |
470 | if (resultChain.getStates().get(i).getType().equals( |
471 | StateType.DEFAULT)) { |
472 | statesToReplace.add(resultChain.getStates().get(i)); |
473 | } |
474 | } |
475 | for (int i = 0; i < statesToReplace.size(); i++) { |
476 | markovBuilder.incorporateMarkovChain(resultChain, stateChains |
477 | .get(i), statesToReplace.get(i), optimize, true); |
478 | } |
479 | |
480 | // Return the result: |
481 | return resultChain; |
482 | } |
483 | |
484 | /** |
485 | * Evaluates the availability of a resource container. Returns a |
486 | * corresponding Markov chain. |
487 | * |
488 | * @param descriptors |
489 | * the list of required resources and their states |
490 | * @return the resulting Markov chain |
491 | */ |
492 | private MarkovChain caseContainerAvailabilityForResourceState( |
493 | final ResourceContainer container) { |
494 | |
495 | // Retrieve the resource failure descriptions: |
496 | List<ProcessingResourceDescriptor> descriptors = getResourceDescriptors( |
497 | container, true); |
498 | List<FailureDescription> failureDescriptions = getFailureDescriptionsForResourceState(descriptors); |
499 | |
500 | MarkovChain resultChain = null; |
501 | if (failureDescriptions.isEmpty()) { |
502 | // All resource available: |
503 | resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
504 | } else { |
505 | // If there are unavailable resources, build a Markov chain |
506 | // that reflects each unavailable resource: |
507 | resultChain = markovBuilder.initResourceFailureMarkovChain( |
508 | prefixes, failureDescriptions); |
509 | } |
510 | |
511 | // Return the result: |
512 | return resultChain; |
513 | } |
514 | |
515 | /** |
516 | * Handles an ExternalCallAction. Generates a Markov Chain of the executing |
517 | * behavior. The Markov Chain is generated by |
518 | * {@link MarkovSeffVisitor.createExternalCallActionChain}. If an retry |
519 | * count is set in the internal action, the chain is repeatedly appended to |
520 | * the main chains failure state. |
521 | * |
522 | * @param externalCallAction |
523 | * the ExternalCallAction |
524 | * @return the resulting Markov Chain. |
525 | */ |
526 | @Override |
527 | public MarkovChain caseExternalCallAction( |
528 | final ExternalCallAction externalCallAction) { |
529 | |
530 | // Logging & naming: |
531 | String name = externalCallAction.getEntityName() + "[" |
532 | + externalCallAction.getId() + "]"; |
533 | prefixes.add(name); |
534 | logger.debug("Visit ExternalCallAction: " + name); |
535 | |
536 | // Get a reference to the executing SEFF: |
537 | ServiceEffectSpecification seff = contextWrapper |
538 | .getNextSEFF(externalCallAction); |
539 | |
540 | // Build a specific Markov Chain depending on the type of call: |
541 | MarkovChain resultChain = null; |
542 | if (seff == null) { |
543 | |
544 | // A system external call might fail according to |
545 | // FailureOccurrenceDescriptions given as |
546 | // SpecifiedReliabilityAnnotations to the system: |
547 | resultChain = caseExternalCallActionOutsideSystem(externalCallAction); |
548 | |
549 | } else { |
550 | |
551 | // If the call is not system external, build a Markov chain that |
552 | // reflects the service-providing behaviour of the call: |
553 | resultChain = caseExternalCallActionInsideSystem(externalCallAction); |
554 | } |
555 | |
556 | // If a retry policy has been specified for this external call, |
557 | // and if the differentiation of failure types is fine-grained enough, |
558 | // then reflect the failure handling behaviour accordingly: |
559 | if ((evaluationType != MarkovEvaluationType.SINGLE) |
560 | && (evaluationType != MarkovEvaluationType.CLASSES)) { |
561 | int retryCount = externalCallAction.getRetryCount(); |
562 | if (retryCount < 0) { |
563 | logger.warn("Retry count of ExternalCallAction \"" |
564 | + externalCallAction.getEntityName() |
565 | + "\" is negative. Assuming 0."); |
566 | retryCount = 0; |
567 | } |
568 | List<String> failureTypeIds = getFailureTypeIds(externalCallAction); |
569 | MarkovChain handlingChain = markovBuilder |
570 | .copyMarkovChain(resultChain); |
571 | for (int i = 0; i < retryCount; ++i) { |
572 | markovBuilder.appendFailureHandlingMarkovChain(resultChain, |
573 | handlingChain, failureTypeIds, optimize); |
574 | } |
575 | } |
576 | |
577 | // Naming: |
578 | prefixes.remove(prefixes.size() - 1); |
579 | |
580 | // Return the result: |
581 | return resultChain; |
582 | } |
583 | |
584 | /** |
585 | * Evaluates an external call action that does not leave the system |
586 | * boundaries. Returns a corresponding Markov chain. |
587 | * |
588 | * @param call |
589 | * the ExternalCallAction |
590 | * @return the resulting Markov Chain. |
591 | */ |
592 | private MarkovChain caseExternalCallActionInsideSystem( |
593 | final ExternalCallAction call) { |
594 | |
595 | // Get a reference to the executing SEFF: |
596 | ServiceEffectSpecification seff = contextWrapper.getNextSEFF(call); |
597 | |
598 | // For the new SEFF, we need a new ContextWrapper. As during the |
599 | // creation of the new ContextWrapper, the old one is altered (which |
600 | // is certainly bad programming style!), we need to save a copy of |
601 | // the old one and restore it after generating the new one: |
602 | ContextWrapper originalContextWrapper = (ContextWrapper) contextWrapper |
603 | .clone(); |
604 | List<ContextWrapper> contextWrapperList = contextWrapper |
605 | .getContextWrapperFor(call); |
606 | |
607 | // FIXME: The Reliability solver does not support replication yet |
608 | if (contextWrapperList.size() > 1) { |
609 | logger |
610 | .error("The Reliability solver only supports one AllocationContext per AssemblyContext. Picking one of the called Allocation contexts for call " |
611 | + call.getEntityName() |
612 | + " " |
613 | + call.getId() |
614 | + " ignoring the others. Results will be inaccurate."); |
615 | } else if (contextWrapperList.size() == 0) { |
616 | throw new RuntimeException( |
617 | "Internal Error: Could not create a Context Wrapper for call " |
618 | + call.getEntityName() + " " + call.getId()); |
619 | } |
620 | ContextWrapper newContextWrapper = contextWrapperList.get(0); |
621 | contextWrapper = originalContextWrapper; |
622 | |
623 | // Build the Markov chain of the executing SEFF: |
624 | MarkovChain resultChain = null; |
625 | MarkovChain innerMarkovChain = new MarkovSeffVisitor( |
626 | this.transformationState, newContextWrapper, prefixes, |
627 | evaluationType, simplifiedStateHandling, optimize, recordTraces) |
628 | .doSwitch(seff); |
629 | |
630 | // Check if the external call crosses the border of one resource |
631 | // container and uses a communication link (if the specification |
632 | // of the communication link is omitted in the model, we treat |
633 | // the link as being perfect, i.e. never failing): |
634 | CommunicationLinkResourceSpecification commLink = contextWrapper |
635 | .getConcreteLinkingResource(call, newContextWrapper.getAllCtx()); |
636 | |
637 | // If a communication link is specified and used by the call, |
638 | // consider the possibility that the call fails: |
639 | if (commLink != null) { |
640 | |
641 | // The call can be modeled as a behavior with three steps: the |
642 | // sending of the message, the remote execution, and the message |
643 | // return. All of these steps contribute a potential for failure: |
644 | ArrayList<State> states = new ArrayList<State>(); |
645 | ArrayList<String> names = new ArrayList<String>(); |
646 | names.add("MessageTransfer(1)"); |
647 | names.add("ServiceExecution"); |
648 | names.add("MessageTransfer(2)"); |
649 | MarkovChain aggregateMarkovChain = markovBuilder |
650 | .initSequentialMarkovChain(prefixes, names, states); |
651 | |
652 | // The first and last steps can be modeled like an Internal |
653 | // Action which either fails or succeeds: |
654 | prefixes.add(names.get(0)); |
655 | MarkovChain messagingMarkovChain = caseMessageTransfer(commLink); |
656 | prefixes.remove(prefixes.size() - 1); |
657 | prefixes.add(names.get(2)); |
658 | MarkovChain returnMarkovChain = caseMessageTransfer(commLink); |
659 | prefixes.remove(prefixes.size() - 1); |
660 | |
661 | // The second step is the already computed inner Markov Chain. |
662 | // Incorporate all steps into the aggregate chain: |
663 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
664 | messagingMarkovChain, states.get(0), optimize, false); |
665 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
666 | innerMarkovChain, states.get(1), optimize, false); |
667 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
668 | returnMarkovChain, states.get(2), optimize, false); |
669 | |
670 | // Return the result: |
671 | resultChain = aggregateMarkovChain; |
672 | |
673 | } else { |
674 | |
675 | // If the call is local, or if the specification of the |
676 | // communication link has been omitted, then the Markov |
677 | // Chain just has to reflect the inner SEFF behavior: |
678 | resultChain = innerMarkovChain; |
679 | } |
680 | |
681 | // Return the result: |
682 | return resultChain; |
683 | } |
684 | |
685 | /** |
686 | * Evaluates an external call action that leaves the system boundaries. |
687 | * Returns a corresponding Markov chain. |
688 | * |
689 | * @param externalCallAction |
690 | * @return the resulting Markov chain |
691 | */ |
692 | private MarkovChain caseExternalCallActionOutsideSystem( |
693 | final ExternalCallAction externalCallAction) { |
694 | |
695 | // Create the result chain: |
696 | MarkovChain resultChain; |
697 | |
698 | // Get the raw failure occurrence descriptions of the system-external |
699 | // call: |
700 | List<ExternalFailureOccurrenceDescription> rawFailureDescriptions = contextWrapper |
701 | .getFailureOccurrenceDescriptionsForSystemExternalCall(externalCallAction); |
702 | |
703 | // Retrieve the failure descriptions list: |
704 | List<FailureDescription> resultFailureDescriptions = new ArrayList<FailureDescription>(); |
705 | for (ExternalFailureOccurrenceDescription description : rawFailureDescriptions) { |
706 | Role role = description |
707 | .getSpecifiedReliabilityAnnotation__ExternalFailureOccurrenceDescription() |
708 | .getRole_SpecifiedQoSAnnotation(); |
709 | Signature signature = description |
710 | .getSpecifiedReliabilityAnnotation__ExternalFailureOccurrenceDescription() |
711 | .getSignature_SpecifiedQoSAnnation(); |
712 | FailureType failureType = description |
713 | .getFailureType__ExternalFailureOccurrenceDescription(); |
714 | FailureDescription newFailureDescription = null; |
715 | if (failureType instanceof SoftwareInducedFailureType) { |
716 | newFailureDescription = new FailureDescription( |
717 | MarkovSoftwareInducedFailureType |
718 | .createExternalFailureType(evaluationType, |
719 | failureType.getId(), signature.getId(), |
720 | role.getId()), description |
721 | .getFailureProbability()); |
722 | } else if (failureType instanceof HardwareInducedFailureType) { |
723 | newFailureDescription = new FailureDescription( |
724 | MarkovHardwareInducedFailureType |
725 | .createExternalFailureType( |
726 | evaluationType, |
727 | ((HardwareInducedFailureType) failureType) |
728 | .getProcessingResourceType__HardwareInducedFailureType() |
729 | .getId(), signature.getId(), |
730 | role.getId()), description |
731 | .getFailureProbability()); |
732 | } else if (failureType instanceof NetworkInducedFailureType) { |
733 | newFailureDescription = new FailureDescription( |
734 | MarkovNetworkInducedFailureType |
735 | .createExternalFailureType( |
736 | evaluationType, |
737 | ((NetworkInducedFailureType) failureType) |
738 | .getCommunicationLinkResourceType__NetworkInducedFailureType() |
739 | .getId(), signature.getId(), |
740 | role.getId()), description |
741 | .getFailureProbability()); |
742 | } |
743 | addFailureDescription(resultFailureDescriptions, |
744 | newFailureDescription); |
745 | } |
746 | |
747 | // Check if failure descriptions exist for the system-external call: |
748 | if (resultFailureDescriptions.size() > 0) { |
749 | // Create a chain that reflects the existing failure descriptions: |
750 | resultChain = markovBuilder.initBasicMarkovChainWithFailures( |
751 | prefixes, resultFailureDescriptions); |
752 | } else { |
753 | // Create a basic chain: |
754 | resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
755 | } |
756 | |
757 | // Return the result: |
758 | return resultChain; |
759 | } |
760 | |
761 | /** |
762 | * Handles fork actions. |
763 | * |
764 | * All forked behaviours are handled sequentially. |
765 | */ |
766 | @Override |
767 | public MarkovChain caseForkAction(ForkAction forkAction) { |
768 | |
769 | // Logging & naming: |
770 | String name = forkAction.getEntityName() + "[" + forkAction.getId() |
771 | + "]"; |
772 | prefixes.add(name); |
773 | logger.debug("Visit ForkAction: " + name); |
774 | |
775 | // Go through the list of forked behaviours that are contained in the |
776 | // fork action. Each behaviour creates its own specific Markov Chain: |
777 | ArrayList<MarkovChain> chains = new ArrayList<MarkovChain>(); |
778 | ArrayList<ForkedBehaviour> behaviours = new ArrayList<ForkedBehaviour>(); |
779 | for (int i = 0; i < forkAction |
780 | .getAsynchronousForkedBehaviours_ForkAction().size(); i++) { |
781 | chains.add((MarkovChain) doSwitch(forkAction |
782 | .getAsynchronousForkedBehaviours_ForkAction().get(i))); |
783 | behaviours.add(forkAction |
784 | .getAsynchronousForkedBehaviours_ForkAction().get(i)); |
785 | } |
786 | SynchronisationPoint synch = forkAction |
787 | .getSynchronisingBehaviours_ForkAction(); |
788 | if (synch != null) { |
789 | for (int i = 0; i < synch |
790 | .getSynchronousForkedBehaviours_SynchronisationPoint() |
791 | .size(); i++) { |
792 | chains.add((MarkovChain) doSwitch(synch |
793 | .getSynchronousForkedBehaviours_SynchronisationPoint() |
794 | .get(i))); |
795 | behaviours.add(synch |
796 | .getSynchronousForkedBehaviours_SynchronisationPoint() |
797 | .get(i)); |
798 | } |
799 | } |
800 | |
801 | // Initialize a new aggregate Markov Chain that has one state for each |
802 | // behaviour of the fork action: |
803 | ArrayList<State> states = new ArrayList<State>(); |
804 | MarkovChain aggregateMarkovChain = markovBuilder.initForkMarkovChain( |
805 | prefixes, behaviours, states); |
806 | |
807 | // Incorporate the specific Chains into the aggregate Chain: |
808 | for (int i = 0; i < behaviours.size(); i++) { |
809 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, chains |
810 | .get(i), states.get(i), optimize, false); |
811 | } |
812 | |
813 | // Naming: |
814 | prefixes.remove(prefixes.size() - 1); |
815 | |
816 | // Return the result: |
817 | return aggregateMarkovChain; |
818 | } |
819 | |
820 | /** |
821 | * An InternalAction is an actual possible point of failure, either because |
822 | * a software failure might happen, or because a required physical resource |
823 | * may be currently unavailable. |
824 | * |
825 | * A Markov chain is returned that reflects all possible outcomes and their |
826 | * probabilities. |
827 | * |
828 | * @param internalAction |
829 | * the InternalAction |
830 | * @return the resulting Markov Chain |
831 | */ |
832 | @Override |
833 | public MarkovChain caseInternalAction(final InternalAction internalAction) { |
834 | |
835 | // Logging & naming: |
836 | String name = internalAction.getEntityName() + "[" |
837 | + internalAction.getId() + "]"; |
838 | prefixes.add(name); |
839 | logger.debug("Visit InternalAction: " + name); |
840 | |
841 | // Check for the requested type of analysis: |
842 | MarkovChain resultChain = null; |
843 | if (simplifiedStateHandling) { |
844 | // Simplified state handling; iterate over all resource states like |
845 | // a branch: |
846 | resultChain = caseInternalActionForIteratedResourceStates(internalAction); |
847 | } else { |
848 | // Full state handling; internal action is evaluated |
849 | // only once (for the current resource state): |
850 | resultChain = caseInternalActionForResourceState(internalAction); |
851 | } |
852 | |
853 | // Naming: |
854 | prefixes.remove(prefixes.size() - 1); |
855 | |
856 | // Return the result: |
857 | return resultChain; |
858 | } |
859 | |
860 | /** |
861 | * Evaluates an internal action through iteration over the possible states |
862 | * of its required resources. Returns a corresponding Markov chain. |
863 | * |
864 | * @param internalAction |
865 | * the internal action |
866 | * @return the resulting Markov chain |
867 | */ |
868 | private MarkovChain caseInternalActionForIteratedResourceStates( |
869 | final InternalAction internalAction) { |
870 | |
871 | // Create the result chain: |
872 | MarkovChain resultChain; |
873 | |
874 | // Retrieve descriptors for the resources required by this internal |
875 | // action: |
876 | List<ProcessingResourceDescriptor> descriptors = getResourceDescriptors(internalAction); |
877 | |
878 | // Create the state probabilities and specific state chains: |
879 | ArrayList<Double> stateProbabilities = new ArrayList<Double>(); |
880 | ArrayList<MarkovChain> stateChains = new ArrayList<MarkovChain>(); |
881 | ArrayList<String> prefixesCopy = new ArrayList<String>(); |
882 | prefixesCopy.addAll(prefixes); |
883 | prefixes.clear(); |
884 | for (long i = 0; i < Math.pow(2, descriptors.size()); i++) { |
885 | setResourceState(descriptors, i); |
886 | stateProbabilities.add(getResourceStateProbability(descriptors)); |
887 | stateChains.add(caseInternalActionForResourceState(internalAction)); |
888 | } |
889 | prefixes.addAll(prefixesCopy); |
890 | |
891 | // Initialize the aggregate Markov chain representing the branch: |
892 | resultChain = markovBuilder.initBranchMarkovChain(prefixes, |
893 | stateProbabilities); |
894 | |
895 | // Incorporate the specific Markov chains into the aggregate one: |
896 | ArrayList<State> statesToReplace = new ArrayList<State>(); |
897 | for (int i = 0; i < resultChain.getStates().size(); i++) { |
898 | if (resultChain.getStates().get(i).getType().equals( |
899 | StateType.DEFAULT)) { |
900 | statesToReplace.add(resultChain.getStates().get(i)); |
901 | } |
902 | } |
903 | for (int i = 0; i < statesToReplace.size(); i++) { |
904 | markovBuilder.incorporateMarkovChain(resultChain, stateChains |
905 | .get(i), statesToReplace.get(i), optimize, true); |
906 | } |
907 | |
908 | // Return the result: |
909 | return resultChain; |
910 | } |
911 | |
912 | /** |
913 | * Evaluates an internal action for one specific resource state and returns |
914 | * the resulting Markov chain. |
915 | * |
916 | * @param internalAction |
917 | * the internal action |
918 | * @return the resulting Markov chain |
919 | */ |
920 | private MarkovChain caseInternalActionForResourceState( |
921 | final InternalAction internalAction) { |
922 | |
923 | // Retrieve descriptors for the resources required by this internal |
924 | // action: |
925 | List<ProcessingResourceDescriptor> descriptors = getResourceDescriptors(internalAction); |
926 | |
927 | // Retrieve the resource failure descriptions: |
928 | List<FailureDescription> failureDescriptions = getFailureDescriptionsForResourceState(descriptors); |
929 | |
930 | MarkovChain resultChain = null; |
931 | if (failureDescriptions.isEmpty()) { |
932 | |
933 | // If all required resources are available, build a Markov chain |
934 | // that reflects the potential application failures: |
935 | failureDescriptions = getInternalActionSoftwareFailureDescriptions(internalAction); |
936 | |
937 | // Build the Markov chain: |
938 | resultChain = markovBuilder.initBasicMarkovChainWithFailures( |
939 | prefixes, failureDescriptions); |
940 | } else { |
941 | |
942 | // If there are unavailable resources, build a Markov chain |
943 | // that reflects each unavailable resource: |
944 | resultChain = markovBuilder.initResourceFailureMarkovChain( |
945 | prefixes, failureDescriptions); |
946 | } |
947 | |
948 | // Return the result: |
949 | return resultChain; |
950 | } |
951 | |
952 | /** |
953 | * For a LoopAction, first the Markov Chain of the body behaviour is built. |
954 | * The result is then inserted into a new Markov Chain that has one State |
955 | * for each of the possible iteration counts of the loop. |
956 | * |
957 | * @param loopAction |
958 | * the LoopAction |
959 | * @return the resulting Markov Chain |
960 | */ |
961 | @Override |
962 | public MarkovChain caseLoopAction(final LoopAction loopAction) { |
963 | |
964 | // Logging & naming: |
965 | String name = loopAction.getEntityName() + "[" + loopAction.getId() |
966 | + "]"; |
967 | prefixes.add(name); |
968 | logger.debug("Visit LoopAction: " + name); |
969 | |
970 | // Determine the inner Markov Chain associated with the loop behaviour: |
971 | ArrayList<String> prefixesCopy = new ArrayList<String>(); |
972 | prefixesCopy.addAll(prefixes); |
973 | prefixes.clear(); |
974 | MarkovChain specificMarkovChain = (MarkovChain) doSwitch(loopAction |
975 | .getBodyBehaviour_Loop()); |
976 | prefixes.addAll(prefixesCopy); |
977 | |
978 | // Get the solved loop probability mass function: |
979 | ManagedPMF pmf = contextWrapper.getLoopIterations(loopAction); |
980 | |
981 | // Initialize the aggregate Markov Chain representing the loop: |
982 | MarkovChain aggregateMarkovChain = markovBuilder.initLoopMarkovChain( |
983 | prefixes, pmf); |
984 | |
985 | // Incorporate the specific MarkovChain into the aggregate one: |
986 | ArrayList<State> statesToReplace = new ArrayList<State>(); |
987 | for (int i = 0; i < aggregateMarkovChain.getStates().size(); i++) { |
988 | if (aggregateMarkovChain.getStates().get(i).getType().equals( |
989 | StateType.DEFAULT)) { |
990 | statesToReplace.add(aggregateMarkovChain.getStates().get(i)); |
991 | } |
992 | } |
993 | for (int i = 0; i < statesToReplace.size(); i++) { |
994 | markovBuilder |
995 | .incorporateMarkovChain(aggregateMarkovChain, |
996 | specificMarkovChain, statesToReplace.get(i), |
997 | optimize, true); |
998 | } |
999 | |
1000 | // Naming: |
1001 | prefixes.remove(prefixes.size() - 1); |
1002 | |
1003 | // Return the result: |
1004 | return aggregateMarkovChain; |
1005 | } |
1006 | |
1007 | /** |
1008 | * Evaluates a message transfer over a communication link. Returns a |
1009 | * corresponding Markov chain. |
1010 | * |
1011 | * @param commLink |
1012 | * the communication link |
1013 | * @return the resulting Markov chain |
1014 | */ |
1015 | private MarkovChain caseMessageTransfer( |
1016 | CommunicationLinkResourceSpecification commLink) { |
1017 | List<FailureDescription> commFailureDescriptions = getFailureDescriptionsForCommunicationLink(commLink); |
1018 | MarkovChain messagingMarkovChain = markovBuilder |
1019 | .initBasicMarkovChainWithFailures(prefixes, |
1020 | commFailureDescriptions); |
1021 | return messagingMarkovChain; |
1022 | } |
1023 | |
1024 | /** |
1025 | * A Release Action returns a trivial Markov Chain. |
1026 | * |
1027 | * @param releaseAction |
1028 | * the release action |
1029 | * @return the resulting Markov Chain. |
1030 | */ |
1031 | @Override |
1032 | public MarkovChain caseReleaseAction(final ReleaseAction releaseAction) { |
1033 | |
1034 | // Logging & naming: |
1035 | String name = releaseAction.getEntityName() + "[" |
1036 | + releaseAction.getId() + "]"; |
1037 | prefixes.add(name); |
1038 | logger.debug("Visit ReleaseAction: " + name); |
1039 | |
1040 | // Create a Markov chain for the Release action: |
1041 | MarkovChain resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
1042 | |
1043 | // Naming: |
1044 | prefixes.remove(prefixes.size() - 1); |
1045 | |
1046 | // Return the result: |
1047 | return resultChain; |
1048 | } |
1049 | |
1050 | /** |
1051 | * Evaluates a resource demanding behaviour by considering all actions in |
1052 | * the behaviour. Returns a corresponding Markov chain. |
1053 | * |
1054 | * @param behaviour |
1055 | * the ResourceDemandingBehaviour |
1056 | * @return the resulting Markov Chain |
1057 | */ |
1058 | @Override |
1059 | public MarkovChain caseResourceDemandingBehaviour( |
1060 | final ResourceDemandingBehaviour behaviour) { |
1061 | |
1062 | // Logging & naming: |
1063 | logger.debug("Visit ResourceDemandingBehaviour"); |
1064 | |
1065 | // Go through the chain of actions that constitute this Behaviour. Each |
1066 | // action is expected to create its own specific Markov Chain: |
1067 | ArrayList<AbstractAction> actions = new ArrayList<AbstractAction>(); |
1068 | ArrayList<MarkovChain> chains = new ArrayList<MarkovChain>(); |
1069 | AbstractAction action = (StartAction) EMFQueryHelper.getObjectByType( |
1070 | behaviour.getSteps_Behaviour(), StartAction.class); |
1071 | while (action != null) { |
1072 | MarkovChain specificMarkovChain = (MarkovChain) doSwitch(action); |
1073 | actions.add(action); |
1074 | chains.add(specificMarkovChain); |
1075 | action = action.getSuccessor_AbstractAction(); |
1076 | } |
1077 | |
1078 | // Initialize a new aggregate Markov Chain that has one state for each |
1079 | // action of the action chain: |
1080 | ArrayList<State> states = new ArrayList<State>(); |
1081 | MarkovChain aggregateMarkovChain = markovBuilder |
1082 | .initBehaviourMarkovChainByAction(prefixes, actions, states); |
1083 | |
1084 | // Incorporate the specific Chains into the aggregate Chain: |
1085 | for (int i = 0; i < actions.size(); i++) { |
1086 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, chains |
1087 | .get(i), states.get(i), optimize, false); |
1088 | } |
1089 | |
1090 | // Return the resulting Markov Chain: |
1091 | return aggregateMarkovChain; |
1092 | } |
1093 | |
1094 | /** |
1095 | * Evaluates a resource demanding SEFF. In addition to the behavioural |
1096 | * evaluation, also the availability of the executing resource container is |
1097 | * checked. Returns a corresponding Markov chain. |
1098 | * |
1099 | * @param seff |
1100 | * the ResourceDemandingSEFF |
1101 | * @return the resulting Markov Chain |
1102 | */ |
1103 | @Override |
1104 | public MarkovChain caseResourceDemandingSEFF( |
1105 | final ResourceDemandingSEFF seff) { |
1106 | |
1107 | // Logging & naming: |
1108 | logger.debug("Visit ResourceDemandingSEFF: [" + seff.getId() + "]"); |
1109 | |
1110 | // Consider both the execution of the SEFF itself and the possibility |
1111 | // that the executing resource container is unavailable: |
1112 | ArrayList<State> states = new ArrayList<State>(); |
1113 | ArrayList<String> names = new ArrayList<String>(); |
1114 | names.add("ContainerAvailability"); |
1115 | names.add("ServiceExecution"); |
1116 | MarkovChain aggregateMarkovChain = markovBuilder |
1117 | .initSequentialMarkovChain(prefixes, names, states); |
1118 | |
1119 | // Model both aspects with an own specific Markov chain: |
1120 | prefixes.add(names.get(0)); |
1121 | ResourceContainer container = contextWrapper.getAllCtx() |
1122 | .getResourceContainer_AllocationContext(); |
1123 | MarkovChain containerAvailabilityMarkovChain = caseContainerAvailability(container); |
1124 | prefixes.remove(prefixes.size() - 1); |
1125 | prefixes.add(names.get(1)); |
1126 | MarkovChain innerMarkovChain = caseResourceDemandingBehaviour(seff); |
1127 | prefixes.remove(prefixes.size() - 1); |
1128 | |
1129 | // Incorporate all steps into the aggregate chain: |
1130 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
1131 | containerAvailabilityMarkovChain, states.get(0), optimize, |
1132 | false); |
1133 | markovBuilder.incorporateMarkovChain(aggregateMarkovChain, |
1134 | innerMarkovChain, states.get(1), optimize, false); |
1135 | |
1136 | // Return the result: |
1137 | return aggregateMarkovChain; |
1138 | } |
1139 | |
1140 | /** |
1141 | * A SetVariableAction returns a trivial Markov Chain. |
1142 | * |
1143 | * @param setVariableAction |
1144 | * the SetVariableAction |
1145 | * @return the resulting Markov Chain |
1146 | */ |
1147 | @Override |
1148 | public MarkovChain caseSetVariableAction( |
1149 | final SetVariableAction setVariableAction) { |
1150 | |
1151 | // Logging & naming: |
1152 | String name = setVariableAction.getEntityName() + "[" |
1153 | + setVariableAction.getId() + "]"; |
1154 | prefixes.add(name); |
1155 | logger.debug("Visit SetVariableAction: " + name); |
1156 | |
1157 | // Build the Markov chain for the SetVariable action: |
1158 | MarkovChain resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
1159 | |
1160 | // Naming: |
1161 | prefixes.remove(prefixes.size() - 1); |
1162 | |
1163 | // Return the result: |
1164 | return resultChain; |
1165 | } |
1166 | |
1167 | /** |
1168 | * A StartAction returns a trivial Markov Chain. |
1169 | * |
1170 | * @param startAction |
1171 | * the StartAction |
1172 | * @return the resulting trivial Markov Chain |
1173 | */ |
1174 | @Override |
1175 | public MarkovChain caseStartAction(final StartAction startAction) { |
1176 | |
1177 | // Logging & naming: |
1178 | String name = startAction.getEntityName() + "[" + startAction.getId() |
1179 | + "]"; |
1180 | prefixes.add(name); |
1181 | logger.debug("Visit StartAction: " + name); |
1182 | |
1183 | // Build the Markov chain for the Start action: |
1184 | MarkovChain resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
1185 | |
1186 | // Naming: |
1187 | prefixes.remove(prefixes.size() - 1); |
1188 | |
1189 | // Return the result: |
1190 | return resultChain; |
1191 | } |
1192 | |
1193 | /** |
1194 | * A StopAction returns a trivial Markov Chain. |
1195 | * |
1196 | * @param stopAction |
1197 | * the StopAction |
1198 | * @return the resulting trivial Markov Chain |
1199 | */ |
1200 | @Override |
1201 | public MarkovChain caseStopAction(final StopAction stopAction) { |
1202 | |
1203 | // Logging & naming: |
1204 | String name = stopAction.getEntityName() + "[" + stopAction.getId() |
1205 | + "]"; |
1206 | prefixes.add(name); |
1207 | logger.debug("Visit StopAction: " + name); |
1208 | |
1209 | // Build the Markov chain for the Stop action: |
1210 | MarkovChain resultChain = markovBuilder.initBasicMarkovChain(prefixes); |
1211 | |
1212 | // Naming: |
1213 | prefixes.remove(prefixes.size() - 1); |
1214 | |
1215 | // Return the result: |
1216 | return resultChain; |
1217 | } |
1218 | |
1219 | /** |
1220 | * Retrieves a list of failureDescriptions for a communication link. |
1221 | * |
1222 | * @param commLink |
1223 | * the communication link |
1224 | * @return the list of failure descriptions |
1225 | */ |
1226 | private List<FailureDescription> getFailureDescriptionsForCommunicationLink( |
1227 | CommunicationLinkResourceSpecification commLink) { |
1228 | List<FailureDescription> commFailureDescriptions = new ArrayList<FailureDescription>(); |
1229 | commFailureDescriptions |
1230 | .add(new FailureDescription( |
1231 | MarkovNetworkInducedFailureType |
1232 | .createInternalFailureType( |
1233 | evaluationType, |
1234 | commLink |
1235 | .getLinkingResource_CommunicationLinkResourceSpecification(), |
1236 | commLink |
1237 | .getCommunicationLinkResourceType_CommunicationLinkResourceSpecification()), |
1238 | commLink.getFailureProbability())); |
1239 | return commFailureDescriptions; |
1240 | } |
1241 | |
1242 | /** |
1243 | * Retrieves a list of failure descriptions for resource unavailability |
1244 | * failures under a given resource state. |
1245 | * |
1246 | * @param descriptors |
1247 | * the list of resources and their states |
1248 | * @return the list of failure descriptions |
1249 | */ |
1250 | private List<FailureDescription> getFailureDescriptionsForResourceState( |
1251 | final List<ProcessingResourceDescriptor> descriptors) { |
1252 | |
1253 | // List all possible unavailability failures: |
1254 | List<FailureDescription> failureDescriptions = new ArrayList<FailureDescription>(); |
1255 | FailureDescription newFailureDescription = null; |
1256 | |
1257 | // Check if any of the resources is unavailable: |
1258 | for (ProcessingResourceDescriptor descriptor : descriptors) { |
1259 | |
1260 | // Get the current state of the resource: |
1261 | MarkovResourceState state = descriptor.getCurrentState(); |
1262 | if (state == null) { |
1263 | logger.error("Resource state no set for " |
1264 | + descriptor.getType().getName() |
1265 | + " resource demand. Assume resource state = OK."); |
1266 | continue; |
1267 | } |
1268 | |
1269 | // If the resource is unavailable, create a corresponding |
1270 | // failure description: |
1271 | if (state.equals(MarkovResourceState.NA)) { |
1272 | newFailureDescription = new FailureDescription( |
1273 | MarkovHardwareInducedFailureType |
1274 | .createInternalFailureType(evaluationType, |
1275 | descriptor.getResourceContainerId(), |
1276 | descriptor.getType().getId()), 1.0); |
1277 | addFailureDescription(failureDescriptions, |
1278 | newFailureDescription); |
1279 | } |
1280 | } |
1281 | |
1282 | // Return the result: |
1283 | return failureDescriptions; |
1284 | } |
1285 | |
1286 | /** |
1287 | * Returns the ids of the failure types that a given failure handling entity |
1288 | * can handle. |
1289 | * |
1290 | * @param entity |
1291 | * the failure handling entity |
1292 | * @return the list of failure type names |
1293 | */ |
1294 | private List<String> getFailureTypeIds(final FailureHandlingEntity entity) { |
1295 | List<String> failureTypes = new ArrayList<String>(); |
1296 | for (FailureType failureType : entity |
1297 | .getFailureTypes_FailureHandlingEntity()) { |
1298 | if (failureType instanceof SoftwareInducedFailureType) { |
1299 | failureTypes.add(failureType.getId()); |
1300 | } else if (failureType instanceof HardwareInducedFailureType) { |
1301 | failureTypes |
1302 | .add(((HardwareInducedFailureType) failureType) |
1303 | .getProcessingResourceType__HardwareInducedFailureType() |
1304 | .getId()); |
1305 | } else if (failureType instanceof NetworkInducedFailureType) { |
1306 | failureTypes |
1307 | .add(((NetworkInducedFailureType) failureType) |
1308 | .getCommunicationLinkResourceType__NetworkInducedFailureType() |
1309 | .getId()); |
1310 | } else { |
1311 | throw new MarkovException("Unsupported failure type " |
1312 | + failureType.getClass().getName()); |
1313 | } |
1314 | } |
1315 | |
1316 | return failureTypes; |
1317 | } |
1318 | |
1319 | /** |
1320 | * Retrieves a list of software failure descriptions for a given internal |
1321 | * action. |
1322 | * |
1323 | * @param internalAction |
1324 | * the internal action |
1325 | * @return the list of software failure descriptions |
1326 | */ |
1327 | private List<FailureDescription> getInternalActionSoftwareFailureDescriptions( |
1328 | final InternalAction internalAction) { |
1329 | |
1330 | // List all possible software failures: |
1331 | List<FailureDescription> failureDescriptions = new ArrayList<FailureDescription>(); |
1332 | FailureDescription newFailureDescription = null; |
1333 | |
1334 | // Go through all failure occurrence descriptions of the internal |
1335 | // action: |
1336 | for (InternalFailureOccurrenceDescription description : internalAction |
1337 | .getInternalFailureOccurrenceDescriptions__InternalAction()) { |
1338 | newFailureDescription = new FailureDescription( |
1339 | MarkovSoftwareInducedFailureType |
1340 | .createInternalFailureType( |
1341 | evaluationType, |
1342 | description |
1343 | .getSoftwareInducedFailureType__InternalFailureOccurrenceDescription() |
1344 | .getId(), internalAction.getId()), |
1345 | description.getFailureProbability()); |
1346 | addFailureDescription(failureDescriptions, newFailureDescription); |
1347 | } |
1348 | |
1349 | // Return the result: |
1350 | return failureDescriptions; |
1351 | } |
1352 | |
1353 | /** |
1354 | * Retrieves the list of required physical resources of a given internal |
1355 | * action. |
1356 | * |
1357 | * @param internalAction |
1358 | * the internal action |
1359 | * @return the resulting list of resources |
1360 | */ |
1361 | private List<ProcessingResourceDescriptor> getResourceDescriptors( |
1362 | final InternalAction internalAction) { |
1363 | |
1364 | // Create the resource list: |
1365 | ArrayList<ProcessingResourceDescriptor> resultList = new ArrayList<ProcessingResourceDescriptor>(); |
1366 | |
1367 | // Go through the list of resource demands: |
1368 | for (ParametricResourceDemand demand : internalAction |
1369 | .getResourceDemand_Action()) { |
1370 | |
1371 | // Special case: ignore resource demands of type |
1372 | // "SystemExternalResource", as they have been internally introduced |
1373 | // by the dependency solver: |
1374 | if (demand.getRequiredResource_ParametricResourceDemand() |
1375 | .getEntityName().equals("SystemExternalResource")) { |
1376 | continue; |
1377 | } |
1378 | |
1379 | // Get the descriptor that corresponds to the demand: |
1380 | ProcessingResourceDescriptor descriptor = transformationState |
1381 | .getDescriptor(demand, contextWrapper); |
1382 | if (descriptor == null) { |
1383 | logger.error("Missing resource description for " |
1384 | + demand.getRequiredResource_ParametricResourceDemand() |
1385 | .getEntityName() |
1386 | + " resource demand. Assume resource state = OK."); |
1387 | continue; |
1388 | } |
1389 | |
1390 | // Add the descriptor to the list: |
1391 | resultList.add(descriptor); |
1392 | } |
1393 | |
1394 | // Return the result: |
1395 | return resultList; |
1396 | } |
1397 | |
1398 | /** |
1399 | * Retrieves the list of physical resources contained within the given |
1400 | * resource container. |
1401 | * |
1402 | * @param resourceContainer |
1403 | * the resource container |
1404 | * @param searchForRequiredResources |
1405 | * if set to TRUE, only the resources required by this container |
1406 | * will be returned |
1407 | * @return the resulting list of resources |
1408 | */ |
1409 | private List<ProcessingResourceDescriptor> getResourceDescriptors( |
1410 | final ResourceContainer resourceContainer, |
1411 | final boolean searchForRequiredResources) { |
1412 | |
1413 | // Create the resource list: |
1414 | ArrayList<ProcessingResourceDescriptor> resultList = new ArrayList<ProcessingResourceDescriptor>(); |
1415 | |
1416 | // Go through the list of specified resources: |
1417 | for (ProcessingResourceSpecification resource : resourceContainer |
1418 | .getActiveResourceSpecifications_ResourceContainer()) { |
1419 | |
1420 | // Check if this is a required resource: |
1421 | if (searchForRequiredResources && !resource.isRequiredByContainer()) { |
1422 | continue; |
1423 | } |
1424 | |
1425 | // Get the descriptor that corresponds to the specified resource: |
1426 | ProcessingResourceDescriptor descriptor = transformationState |
1427 | .getDescriptor(resource); |
1428 | if (descriptor == null) { |
1429 | logger |
1430 | .error("Missing resource description for resource " |
1431 | + resource |
1432 | .getActiveResourceType_ActiveResourceSpecification() |
1433 | .getEntityName() + " in container " |
1434 | + resourceContainer.getEntityName() |
1435 | + ". Assume resource state = OK."); |
1436 | continue; |
1437 | } |
1438 | |
1439 | // Add the descriptor to the list: |
1440 | resultList.add(descriptor); |
1441 | } |
1442 | |
1443 | // Return the result: |
1444 | return resultList; |
1445 | } |
1446 | |
1447 | /** |
1448 | * Retrieves the probability of a certain resource state. |
1449 | * |
1450 | * @param descriptors |
1451 | * the list of resources |
1452 | * @return the state probability |
1453 | */ |
1454 | private double getResourceStateProbability( |
1455 | List<ProcessingResourceDescriptor> descriptors) { |
1456 | // All single resource states are independent; hence, the |
1457 | // overall state probability is the product over all single |
1458 | // state probabilities: |
1459 | double stateProbability = 1.0; |
1460 | for (ProcessingResourceDescriptor descriptor : descriptors) { |
1461 | stateProbability *= descriptor.getStateProbability(descriptor |
1462 | .getCurrentState()); |
1463 | } |
1464 | return stateProbability; |
1465 | } |
1466 | |
1467 | /** |
1468 | * Returns a Markov chain that reflects a recovery action behaviour |
1469 | * including its failure handling alternatives. |
1470 | * |
1471 | * @param action |
1472 | * the surrounding recovery block action |
1473 | * @param behaviour |
1474 | * the behaviour to evaluate |
1475 | * @return the resulting Markov chain |
1476 | */ |
1477 | private MarkovChain processRecoveryActionBehaviour(RecoveryAction action, |
1478 | RecoveryActionBehaviour behaviour) { |
1479 | |
1480 | // Step 1: evaluate the behaviour itself: |
1481 | prefixes.add("Alternative(" |
1482 | + action.getRecoveryActionBehaviours__RecoveryAction().indexOf( |
1483 | behaviour) + ")"); |
1484 | MarkovChain resultChain = caseResourceDemandingBehaviour(behaviour); |
1485 | prefixes.remove(prefixes.size() - 1); |
1486 | |
1487 | // Step 2: consider any existing failure handling alternatives if |
1488 | // the differentiation of failure types is fine-grained enough: |
1489 | if ((evaluationType != MarkovEvaluationType.SINGLE) |
1490 | && (evaluationType != MarkovEvaluationType.CLASSES) |
1491 | && (behaviour |
1492 | .getFailureHandlingAlternatives__RecoveryActionBehaviour() |
1493 | .size() > 0)) { |
1494 | |
1495 | // Determine the chains and handled failure types of the |
1496 | // alternatives: |
1497 | List<MarkovChain> failureHandlingChains = new ArrayList<MarkovChain>(); |
1498 | List<List<String>> failureTypeLists = new ArrayList<List<String>>(); |
1499 | for (RecoveryActionBehaviour handlingAlternative : behaviour |
1500 | .getFailureHandlingAlternatives__RecoveryActionBehaviour()) { |
1501 | failureTypeLists.add(getFailureTypeIds(handlingAlternative)); |
1502 | failureHandlingChains.add(processRecoveryActionBehaviour( |
1503 | action, handlingAlternative)); |
1504 | } |
1505 | |
1506 | // Append the handling alternatives to the current chain: |
1507 | markovBuilder.appendFailureHandlingMarkovChains(resultChain, |
1508 | failureHandlingChains, failureTypeLists, optimize); |
1509 | } |
1510 | |
1511 | // Step 3: return the result: |
1512 | return resultChain; |
1513 | } |
1514 | |
1515 | /** |
1516 | * Sets a resource state according to the bit pattern of an numeric value. |
1517 | * |
1518 | * @param descriptors |
1519 | * the list of resources |
1520 | * @param number |
1521 | * the numeric value |
1522 | */ |
1523 | private void setResourceState( |
1524 | final List<ProcessingResourceDescriptor> descriptors, |
1525 | final long number) { |
1526 | |
1527 | // Iterate over all resources: |
1528 | for (int i = 0; i < descriptors.size(); i++) { |
1529 | MarkovResourceState state = (((number >> i) % 2) == 0) ? MarkovResourceState.OK |
1530 | : MarkovResourceState.NA; |
1531 | descriptors.get(i).setCurrentState(state); |
1532 | } |
1533 | } |
1534 | |
1535 | } |