From 6051cbabfe99c494b4f3b75aca516fb6f27338ad Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Mon, 23 Feb 2015 23:56:38 +0100 Subject: [PATCH] Fix a race in PingPong transaction scheduling We have failed to re-check inflighTx after taking the lock, which meant that completion and readiness may have raced resulting in warnings about transaction being submitted while there are others in-flight. Fix also the shutdown case, which could trigger an unexpected warnings if there is an inflight transaction. Change-Id: Ie3a3845335754860a831070d5a73dbc9a4d67d3c Signed-off-by: Robert Varga --- .../broker/impl/PingPongTransactionChain.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/PingPongTransactionChain.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/PingPongTransactionChain.java index 961b6c7b93..9895ff9ad5 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/PingPongTransactionChain.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/PingPongTransactionChain.java @@ -158,13 +158,16 @@ public final class PingPongTransactionChain implements DOMTransactionChain { /* * This forces allocateTransaction() on a slow path, which has to happen after - * this method has completed executing. + * this method has completed executing. Also inflightTx may be updated outside + * the lock, hence we need to re-check. */ @GuardedBy("this") private void processIfReady() { - final PingPongTransaction tx = READY_UPDATER.getAndSet(this, null); - if (tx != null) { - processTransaction(tx); + if (inflightTx == null) { + final PingPongTransaction tx = READY_UPDATER.getAndSet(this, null); + if (tx != null) { + processTransaction(tx); + } } } @@ -251,14 +254,27 @@ public final class PingPongTransactionChain implements DOMTransactionChain { } @Override - public void close() { + public synchronized void close() { final PingPongTransaction notLocked = lockedTx; Preconditions.checkState(notLocked == null, "Attempted to close chain with outstanding transaction %s", notLocked); - synchronized (this) { - processIfReady(); - delegate.close(); + // Force allocations on slow path. We will complete the rest + final PingPongTransaction tx = READY_UPDATER.getAndSet(this, null); + + // Make sure no transaction is outstanding. Otherwise sleep a bit and retry + while (inflightTx != null) { + LOG.debug("Busy-waiting for in-flight transaction {} to complete", inflightTx); + Thread.yield(); + continue; } + + // If we have an outstanding transaction, send it down + if (tx != null) { + processTransaction(tx); + } + + // All done, close the delegate. All new allocations should fail. + delegate.close(); } @Override -- 2.36.6