2 * Copyright (c) 2015 Brocade Communications 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.controller.cluster.datastore;
10 import com.google.common.collect.Lists;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
14 import javax.annotation.concurrent.GuardedBy;
15 import org.opendaylight.controller.cluster.datastore.identifiers.TransactionIdentifier;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
20 * A helper class that wraps an eventual TransactionContext instance. Operations destined for the target
21 * TransactionContext instance are cached until the TransactionContext instance becomes available at which
22 * time they are executed.
24 * @author Thomas Pantelis
26 class TransactionContextWrapper {
27 private static final Logger LOG = LoggerFactory.getLogger(TransactionContextWrapper.class);
30 * The list of transaction operations to execute once the TransactionContext becomes available.
32 @GuardedBy("queuedTxOperations")
33 private final List<TransactionOperation> queuedTxOperations = Lists.newArrayList();
36 * The resulting TransactionContext.
38 private volatile TransactionContext transactionContext;
40 private final TransactionIdentifier identifier;
42 TransactionContextWrapper(final TransactionIdentifier identifier) {
43 this.identifier = identifier;
46 TransactionContext getTransactionContext() {
47 return transactionContext;
50 TransactionIdentifier getIdentifier() {
55 * Adds a TransactionOperation to be executed once the TransactionContext becomes available.
57 private void enqueueTransactionOperation(final TransactionOperation operation) {
58 final boolean invokeOperation;
59 synchronized(queuedTxOperations) {
60 if (transactionContext == null) {
61 LOG.debug("Tx {} Queuing TransactionOperation", getIdentifier());
63 queuedTxOperations.add(operation);
64 invokeOperation = false;
66 invokeOperation = true;
70 if (invokeOperation) {
71 operation.invoke(transactionContext);
75 void maybeExecuteTransactionOperation(final TransactionOperation op) {
77 if (transactionContext != null) {
78 op.invoke(transactionContext);
80 // The shard Tx hasn't been created yet so add the Tx operation to the Tx Future
81 // callback to be executed after the Tx is created.
82 enqueueTransactionOperation(op);
86 void executePriorTransactionOperations(final TransactionContext localTransactionContext) {
88 // Access to queuedTxOperations and transactionContext must be protected and atomic
89 // (ie synchronized) with respect to #addTxOperationOnComplete to handle timing
90 // issues and ensure no TransactionOperation is missed and that they are processed
91 // in the order they occurred.
93 // We'll make a local copy of the queuedTxOperations list to handle re-entrancy
94 // in case a TransactionOperation results in another transaction operation being
95 // queued (eg a put operation from a client read Future callback that is notified
97 Collection<TransactionOperation> operationsBatch = null;
98 synchronized(queuedTxOperations) {
99 if(queuedTxOperations.isEmpty()) {
100 // We're done invoking the TransactionOperations so we can now publish the
101 // TransactionContext.
102 transactionContext = localTransactionContext;
106 operationsBatch = new ArrayList<>(queuedTxOperations);
107 queuedTxOperations.clear();
110 // Invoke TransactionOperations outside the sync block to avoid unnecessary blocking.
111 // A slight down-side is that we need to re-acquire the lock below but this should
113 for(TransactionOperation oper: operationsBatch) {
114 oper.invoke(localTransactionContext);