/* * Copyright (c) 2015 Pantheon Technologies s.r.o. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.openflowjava.protocol.impl.core.connection; import com.google.common.util.concurrent.FutureCallback; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.function.Function; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class StackedOutboundQueue extends AbstractStackedOutboundQueue { private static final Logger LOG = LoggerFactory.getLogger(StackedOutboundQueue.class); private static final AtomicLongFieldUpdater<StackedOutboundQueue> BARRIER_XID_UPDATER = AtomicLongFieldUpdater.newUpdater(StackedOutboundQueue.class, "barrierXid"); private volatile long barrierXid = -1; StackedOutboundQueue(final AbstractOutboundQueueManager<?, ?> manager) { super(manager); } /* * This method is expected to be called from multiple threads concurrently */ @Override public void commitEntry(final Long xid, final OfHeader message, final FutureCallback<OfHeader> callback, final Function<OfHeader, Boolean> isCompletedFunction) { final OutboundQueueEntry entry = getEntry(xid); entry.commit(message, callback, isCompletedFunction); if (entry.isBarrier()) { long my = xid; for (;;) { final long prev = BARRIER_XID_UPDATER.getAndSet(this, my); if (prev < my) { LOG.debug("Queue {} recorded pending barrier XID {}", this, my); break; } // We have traveled back, recover LOG.debug("Queue {} retry pending barrier {} >= {}", this, prev, my); my = prev; } } LOG.trace("Queue {} committed XID {}", this, xid); manager.ensureFlushing(); } Long reserveBarrierIfNeeded() { if (isBarrierNeeded()) { return reserveEntry(); } return null; } /** * Checks if Barrier Request is the last message enqueued. If not, one needs * to be scheduled in order to collect data about previous messages. * @return true if last enqueued message is Barrier Request, false otherwise */ boolean isBarrierNeeded() { final long bXid = barrierXid; final long fXid = firstSegment.getBaseXid() + flushOffset; if (bXid >= fXid) { LOG.debug("Barrier found at XID {} (currently at {})", bXid, fXid); return false; } return true; } }