2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.bgpcep.programming.impl;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.SettableFuture;
15 import io.netty.util.Timeout;
17 import java.util.ArrayList;
18 import java.util.Iterator;
19 import java.util.List;
21 import javax.annotation.concurrent.GuardedBy;
23 import org.opendaylight.bgpcep.programming.spi.ExecutionResult;
24 import org.opendaylight.bgpcep.programming.spi.Instruction;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.CancelFailure;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.InstructionId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.InstructionStatus;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.UncancellableInstruction;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.instruction.status.changed.Details;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.programming.rev130930.instruction.status.changed.DetailsBuilder;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 final class InstructionImpl implements Instruction {
35 private static final Logger LOG = LoggerFactory.getLogger(InstructionImpl.class);
36 private final List<InstructionImpl> dependants = new ArrayList<>();
37 private final SettableFuture<Instruction> schedulingFuture;
38 private final List<InstructionImpl> dependencies;
39 private final QueueInstruction queue;
40 private final InstructionId id;
41 private SettableFuture<ExecutionResult<Details>> executionFuture;
42 private InstructionStatus status = InstructionStatus.Queued;
43 private Details heldUpDetails;
44 private Timeout timeout;
46 InstructionImpl(final QueueInstruction queue, final SettableFuture<Instruction> future, final InstructionId id,
47 final List<InstructionImpl> dependencies, final Timeout timeout) {
48 this.schedulingFuture = Preconditions.checkNotNull(future);
49 this.dependencies = Preconditions.checkNotNull(dependencies);
50 this.timeout = Preconditions.checkNotNull(timeout);
51 this.queue = Preconditions.checkNotNull(queue);
52 this.id = Preconditions.checkNotNull(id);
55 InstructionId getId() {
59 InstructionStatus getStatus() {
63 synchronized void setStatus(final InstructionStatus status, final Details details) {
66 LOG.debug("Instruction {} transitioned to status {}", id, status);
68 // Send out a notification
69 this.queue.instructionUpdated(status, details);
86 private void cancelTimeout() {
87 if (timeout != null) {
93 public synchronized void timeout() {
94 if (timeout != null) {
101 LOG.debug("Instruction {} has status {}, timeout is a no-op", id, status);
104 LOG.warn("Instruction {} has status {} before timeout completed", id, status);
107 LOG.info("Instruction {} timed out while executing, transitioning into Unknown", id);
108 setStatus(InstructionStatus.Unknown, null);
112 LOG.debug("Instruction {} timed out while Queued, cancelling it", id);
114 final List<InstructionId> ids = new ArrayList<>();
115 for (final InstructionImpl d : dependencies) {
116 if (d.getStatus() != InstructionStatus.Successful) {
121 cancel(new DetailsBuilder().setUnmetDependencies(ids).build());
124 LOG.debug("Instruction {} timed out while Scheduled, cancelling it", id);
125 cancel(heldUpDetails);
132 private void cancelDependants() {
133 final Details details = new DetailsBuilder().setUnmetDependencies(ImmutableList.of(id)).build();
134 for (final InstructionImpl d : dependants) {
135 d.tryCancel(details);
140 private void cancel(final Details details) {
142 schedulingFuture.cancel(false);
143 setStatus(InstructionStatus.Cancelled, details);
146 synchronized Class<? extends CancelFailure> tryCancel(final Details details) {
153 LOG.debug("Instruction {} can no longer be cancelled due to status {}", id, status);
154 return UncancellableInstruction.class;
161 throw new IllegalStateException("Unhandled instruction state " + status);
165 public synchronized boolean checkedExecutionStart() {
166 if (status != InstructionStatus.Scheduled) {
170 setStatus(InstructionStatus.Executing, null);
175 public synchronized boolean executionHeldUp(final Details details) {
176 if (status != InstructionStatus.Scheduled) {
180 this.heldUpDetails = details;
185 public synchronized void executionCompleted(final InstructionStatus status, final Details details) {
186 Preconditions.checkState(executionFuture != null);
190 // We reuse the preconditions set down in this class
191 final ExecutionResult<Details> result = new ExecutionResult<Details>(status, details);
192 setStatus(status, details);
193 executionFuture.set(result);
196 synchronized void addDependant(final InstructionImpl d) {
200 private synchronized void removeDependant(final InstructionImpl d) {
201 dependants.remove(d);
204 private synchronized void removeDependency(final InstructionImpl other) {
205 dependencies.remove(other);
208 synchronized Iterator<InstructionImpl> getDependants() {
209 return dependants.iterator();
212 synchronized void clean() {
213 for (final Iterator<InstructionImpl> it = dependencies.iterator(); it.hasNext();) {
214 it.next().removeDependant(this);
216 dependencies.clear();
218 for (final Iterator<InstructionImpl> it = dependants.iterator(); it.hasNext();) {
219 it.next().removeDependency(this);
223 this.queue.instructionRemoved();
226 synchronized ListenableFuture<ExecutionResult<Details>> ready() {
227 Preconditions.checkState(status == InstructionStatus.Queued);
228 Preconditions.checkState(executionFuture == null);
231 * Check all vertices we depend on. We start off as ready for
232 * scheduling. If we encounter a cancelled/failed/unknown
233 * dependency, we cancel this instruction (and cascade). If we
234 * encounter an executing/queued/scheduled dependency, we hold
235 * of scheduling this one.
237 boolean ready = true;
239 final List<InstructionId> unmet = new ArrayList<>();
240 for (final InstructionImpl d : dependencies) {
241 switch (d.getStatus()) {
245 unmet.add(d.getId());
258 if (!unmet.isEmpty()) {
259 LOG.warn("Instruction {} was Queued, while some dependencies were resolved unsuccessfully, cancelling it", id);
260 cancel(new DetailsBuilder().setUnmetDependencies(unmet).build());
268 LOG.debug("Instruction {} is ready for execution", id);
269 setStatus(InstructionStatus.Scheduled, null);
270 executionFuture = SettableFuture.create();
271 schedulingFuture.set(this);
272 return executionFuture;