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.pcep.topology.provider;
10 import com.google.common.util.concurrent.ListenableFuture;
11 import com.google.common.util.concurrent.SettableFuture;
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import io.netty.util.Timeout;
14 import java.lang.invoke.MethodHandles;
15 import java.lang.invoke.VarHandle;
16 import java.util.concurrent.TimeUnit;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.OperationResult;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.lsp.metadata.Metadata;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
22 final class PCEPRequest {
24 * Logical state of a {@link PCEPRequest}.
28 * The request has not been written out to the session.
32 * The request has been sent to to the sesssion, but has not been acknowledged by the peer.
36 * The request has been completed.
41 private static final Logger LOG = LoggerFactory.getLogger(PCEPRequest.class);
42 private static final VarHandle STATE;
46 STATE = MethodHandles.lookup().findVarHandle(PCEPRequest.class, "state", State.class);
47 } catch (NoSuchFieldException | IllegalAccessException e) {
48 throw new ExceptionInInitializerError(e);
52 private final SettableFuture<OperationResult> future = SettableFuture.create();
53 private final long startNanos = System.nanoTime();
54 private final Metadata metadata;
56 // Manipulated via STATE
57 @SuppressWarnings("unused")
58 @SuppressFBWarnings(value = "URF_UNREAD_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
59 private volatile State state = State.UNSENT;
61 // Guarded by state going to State.DONE
62 private Timeout timeout;
64 PCEPRequest(final Metadata metadata, final Timeout timeout) {
65 this.metadata = metadata;
66 this.timeout = timeout;
69 protected ListenableFuture<OperationResult> getFuture() {
73 public Metadata getMetadata() {
77 long getElapsedMillis() {
78 final long elapsedNanos = System.nanoTime() - startNanos;
79 final long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(elapsedNanos);
81 // FIXME: this is weird: it scales (0,1) up to 1, but otherwise scales down
82 return elapsedMillis == 0 && elapsedNanos > 0 ? 1 : elapsedMillis;
86 * Mark this request as {@link State#UNACKED} if it currently is {@link State#UNSENT}.
89 if (STATE.compareAndSet(this, State.UNSENT, State.UNACKED)) {
90 LOG.debug("Request went from {} to {}", State.UNSENT, State.UNACKED);
95 * Mark this request as {@link State#DONE} with specified {@link OperationResult}. If it is already done, this
96 * method does nothing.
98 * @param result Result to report
100 void finish(final OperationResult result) {
101 final var prev = setDone();
102 if (prev != State.DONE) {
103 setFuture(prev, result);
108 * Mark this request as {@link State#DONE} with a result derived from its current state. If it is already done, this
109 * method does nothing.
111 * @return Previous state
114 final var prev = setDone();
115 // FIXME: exhaustive when we have JDK17+
118 setFuture(prev, OperationResults.UNSENT);
121 setFuture(prev, OperationResults.NOACK);
127 throw new IllegalStateException("Unhandled state " + prev);
132 private State setDone() {
133 return (State) STATE.getAndSet(this, State.DONE);
136 private void setFuture(final State prev, final OperationResult result) {
137 LOG.debug("Request went from {} to {}", prev, State.DONE);
138 if (timeout != null) {