org.opendaylight.ovsdb.hwvtepsouthbound.transactions.md.TransactionInvokerImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2015, 2017 Cisco Systems, Inc. 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.ovsdb.hwvtepsouthbound.transactions.md;
import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import org.checkerframework.checker.lock.qual.GuardedBy;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
import org.opendaylight.mdsal.binding.api.Transaction;
import org.opendaylight.mdsal.binding.api.TransactionChain;
import org.opendaylight.mdsal.binding.api.TransactionChainListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/* TODO:
* Copied over as-is from southbound plugin. Good candidate to be common
* when refactoring code.
*/
public class TransactionInvokerImpl implements TransactionInvoker,TransactionChainListener, Runnable, AutoCloseable,
Thread.UncaughtExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(TransactionInvokerImpl.class);
private static final int QUEUE_SIZE = 10000;
private final DataBroker db;
private final BlockingQueue inputQueue = new LinkedBlockingQueue<>(QUEUE_SIZE);
private final BlockingQueue failedTransactionQueue = new LinkedBlockingQueue<>(QUEUE_SIZE);
private final ExecutorService executor;
@GuardedBy("this")
private final Map transactionToCommand = new HashMap<>();
@GuardedBy("this")
private final List pendingTransactions = new ArrayList<>();
private TransactionChain chain;
//This is made volatile as it is accessed from uncaught exception handler thread also
private volatile ReadWriteTransaction transactionInFlight = null;
private Iterator commandIterator = null;
public TransactionInvokerImpl(final DataBroker db) {
this.db = db;
this.chain = db.createTransactionChain(this);
ThreadFactory threadFact = new ThreadFactoryBuilder().setNameFormat("transaction-invoker-impl-%d")
.setUncaughtExceptionHandler(this).build();
executor = Executors.newSingleThreadExecutor(threadFact);
//Using the execute method here so that un caught exception handler gets triggered upon exception.
//The other way to do it is using submit method and wait on the future to catch any exceptions
executor.execute(this);
}
@Override
public void invoke(final TransactionCommand command) {
// TODO what do we do if queue is full?
if (!inputQueue.offer(command)) {
LOG.error("inputQueue is full (size: {}) - could not offer {}", inputQueue.size(), command);
}
}
@Override
public void onTransactionChainFailed(final TransactionChain txChain,
final Transaction transaction, final Throwable cause) {
offerFailedTransaction(transaction);
}
@Override
public void onTransactionChainSuccessful(final TransactionChain txChain) {
// NO OP
}
@Override
public void run() {
while (true) {
final List commands;
try {
commands = extractCommands();
} catch (InterruptedException e) {
LOG.warn("Extracting commands was interrupted.", e);
continue;
}
commandIterator = commands.iterator();
try {
while (commandIterator.hasNext()) {
executeCommand(commandIterator.next());
}
transactionInFlight = null;
} catch (IllegalStateException e) {
if (transactionInFlight != null) {
// TODO: This method should distinguish exceptions on which the command should be
// retried from exceptions on which the command should NOT be retried.
// Then it should retry only the commands which should be retried, otherwise
// this method will retry commands which will never be successful forever.
offerFailedTransaction(transactionInFlight);
}
transactionInFlight = null;
LOG.warn("Failed to process an update notification from OVS.", e);
}
}
}
private synchronized void executeCommand(final TransactionCommand command) {
final ReadWriteTransaction transaction = chain.newReadWriteTransaction();
transactionInFlight = transaction;
recordPendingTransaction(command, transaction);
command.execute(transaction);
FluentFuture> ft = transaction.commit();
command.setTransactionResultFuture(ft);
ft.addCallback(new FutureCallback
© 2015 - 2025 Weber Informatics LLC | Privacy Policy