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 io.netty.util.Timeout;
13 import java.lang.invoke.MethodHandles;
14 import java.lang.invoke.VarHandle;
15 import java.util.concurrent.TimeUnit;
16 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.OperationResult;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev220730.lsp.metadata.Metadata;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
21 final class PCEPRequest {
23 * Logical state of a {@link PCEPRequest}.
27 * The request has not been written out to the session.
31 * The request has been sent to to the sesssion, but has not been acknowledged by the peer.
35 * The request has been completed.
40 private static final Logger LOG = LoggerFactory.getLogger(PCEPRequest.class);
41 private static final VarHandle STATE;
45 STATE = MethodHandles.lookup().findVarHandle(PCEPRequest.class, "state", State.class);
46 } catch (NoSuchFieldException | IllegalAccessException e) {
47 throw new ExceptionInInitializerError(e);
51 private final SettableFuture<OperationResult> future = SettableFuture.create();
52 private final long startNanos = System.nanoTime();
53 private final Metadata metadata;
55 // Manipulated via STATE
56 @SuppressWarnings("unused")
57 private volatile State state = State.UNSENT;
59 // Guarded by state going to State.DONE
60 private Timeout timeout;
62 PCEPRequest(final Metadata metadata, final Timeout timeout) {
63 this.metadata = metadata;
64 this.timeout = timeout;
67 protected ListenableFuture<OperationResult> getFuture() {
71 public Metadata getMetadata() {
75 long getElapsedMillis() {
76 final long elapsedNanos = System.nanoTime() - startNanos;
77 final long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(elapsedNanos);
79 // FIXME: this is weird: it scales (0,1) up to 1, but otherwise scales down
80 return elapsedMillis == 0 && elapsedNanos > 0 ? 1 : elapsedMillis;
84 * Mark this request as {@link State#UNACKED} if it currently is {@link State#UNSENT}.
87 if (STATE.compareAndSet(this, State.UNSENT, State.UNACKED)) {
88 LOG.debug("Request went from {} to {}", State.UNSENT, State.UNACKED);
93 * Mark this request as {@link State#DONE} with specified {@link OperationResult}. If it is already done, this
94 * method does nothing.
96 * @param result Result to report
98 void finish(final OperationResult result) {
99 final var prev = setDone();
100 if (prev != State.DONE) {
101 setFuture(prev, result);
106 * Mark this request as {@link State#DONE} with a result derived from its current state. If it is already done, this
107 * method does nothing.
109 * @return Previous state
112 final var prev = setDone();
113 // FIXME: exhaustive when we have JDK17+
116 setFuture(prev, OperationResults.UNSENT);
119 setFuture(prev, OperationResults.NOACK);
125 throw new IllegalStateException("Unhandled state " + prev);
130 private State setDone() {
131 return (State) STATE.getAndSet(this, State.DONE);
134 private void setFuture(final State prev, final OperationResult result) {
135 LOG.debug("Request went from {} to {}", prev, State.DONE);
136 if (timeout != null) {