2 * Copyright (c) 2016 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.controller.cluster.databroker.actors.dds;
10 import com.google.common.annotations.Beta;
11 import com.google.common.base.Preconditions;
12 import java.util.Collection;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
16 import java.util.function.Function;
17 import javax.annotation.Nullable;
18 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
19 import org.opendaylight.yangtools.concepts.Identifiable;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
25 * Abstract superclass of both ClientSnapshot and ClientTransaction. Provided for convenience.
27 * @author Robert Varga
30 public abstract class AbstractClientHandle<T extends AbstractProxyTransaction> extends LocalAbortable
31 implements Identifiable<TransactionIdentifier> {
33 * Our state consist of the the proxy map, hence we just subclass ConcurrentHashMap directly.
35 private static final class State<T> extends ConcurrentHashMap<Long, T> {
36 private static final long serialVersionUID = 1L;
39 private static final Logger LOG = LoggerFactory.getLogger(AbstractClientHandle.class);
40 @SuppressWarnings("rawtypes")
41 private static final AtomicReferenceFieldUpdater<AbstractClientHandle, State> STATE_UPDATER =
42 AtomicReferenceFieldUpdater.newUpdater(AbstractClientHandle.class, State.class, "state");
44 private final TransactionIdentifier transactionId;
45 private final AbstractClientHistory parent;
47 private volatile State<T> state = new State<>();
49 // Hidden to prevent outside instantiation
50 AbstractClientHandle(final AbstractClientHistory parent, final TransactionIdentifier transactionId) {
51 this.transactionId = Preconditions.checkNotNull(transactionId);
52 this.parent = Preconditions.checkNotNull(parent);
56 public final TransactionIdentifier getIdentifier() {
61 * Release all state associated with this transaction.
63 * @return True if this transaction became closed during this call
65 public final boolean abort() {
67 parent.onTransactionAbort(this);
74 private boolean commonAbort() {
75 final Collection<T> toClose = ensureClosed();
76 if (toClose == null) {
80 toClose.forEach(AbstractProxyTransaction::abort);
85 final void localAbort(final Throwable cause) {
86 LOG.debug("Local abort of transaction {}", getIdentifier(), cause);
91 * Make sure this snapshot is closed. If it became closed as the effect of this call, return a collection of
92 * {@link AbstractProxyTransaction} handles which need to be closed, too.
94 * @return null if this snapshot has already been closed, otherwise a collection of proxies, which need to be
97 @Nullable final Collection<T> ensureClosed() {
98 @SuppressWarnings("unchecked")
99 final State<T> local = STATE_UPDATER.getAndSet(this, null);
100 return local == null ? null : local.values();
103 final T ensureProxy(final YangInstanceIdentifier path, final Function<Long, T> createProxy) {
104 final Map<Long, T> local = getState();
105 final Long shard = parent.resolveShardForPath(path);
107 return local.computeIfAbsent(shard, createProxy);
110 final AbstractClientHistory parent() {
114 private State<T> getState() {
115 final State<T> local = state;
116 Preconditions.checkState(local != null, "Transaction %s is closed", transactionId);