f364994e3deb40fd8ee41f2c87a88363840bb173
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / actors / dds / AbstractClientHistory.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.databroker.actors.dds;
9
10 import com.google.common.base.Preconditions;
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
14 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
15 import org.opendaylight.yangtools.concepts.Identifiable;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 /**
20  * Abstract base class for client view of a history. This class has two implementations, one for normal local histories
21  * and the other for single transactions.
22  *
23  * @author Robert Varga
24  */
25 abstract class AbstractClientHistory extends LocalAbortable implements Identifiable<LocalHistoryIdentifier> {
26     static enum State {
27         IDLE,
28         TX_OPEN,
29         CLOSED,
30     }
31
32     private static final Logger LOG = LoggerFactory.getLogger(AbstractClientHistory.class);
33     private static final AtomicReferenceFieldUpdater<AbstractClientHistory, State> STATE_UPDATER =
34             AtomicReferenceFieldUpdater.newUpdater(AbstractClientHistory.class, State.class, "state");
35
36     private final Map<Long, LocalHistoryIdentifier> histories = new ConcurrentHashMap<>();
37     private final DistributedDataStoreClientBehavior client;
38     private final LocalHistoryIdentifier identifier;
39
40     private volatile State state = State.IDLE;
41
42     AbstractClientHistory(final DistributedDataStoreClientBehavior client, final LocalHistoryIdentifier identifier) {
43         this.client = Preconditions.checkNotNull(client);
44         this.identifier = Preconditions.checkNotNull(identifier);
45         Preconditions.checkArgument(identifier.getCookie() == 0);
46     }
47
48     final State state() {
49         return state;
50     }
51
52     final void updateState(final State expected, final State next) {
53         final boolean success = STATE_UPDATER.compareAndSet(this, expected, next);
54         Preconditions.checkState(success, "Race condition detected, state changed from %s to %s", expected, state);
55     }
56
57     final LocalHistoryIdentifier getHistoryForCookie(final Long cookie) {
58         LocalHistoryIdentifier ret = histories.get(cookie);
59         if (ret == null) {
60             ret = new LocalHistoryIdentifier(identifier.getClientId(), identifier.getHistoryId(), cookie);
61             final LocalHistoryIdentifier existing = histories.putIfAbsent(cookie, ret);
62             if (existing != null) {
63                 ret = existing;
64             }
65         }
66
67         return ret;
68     }
69
70     @Override
71     public final LocalHistoryIdentifier getIdentifier() {
72         return identifier;
73     }
74
75     final DistributedDataStoreClientBehavior getClient() {
76         return client;
77     }
78
79     @Override
80     final void localAbort(final Throwable cause) {
81         LOG.debug("Force-closing history {}", getIdentifier(), cause);
82         state = State.CLOSED;
83     }
84
85     /**
86      * Callback invoked from {@link ClientTransaction} when a transaction has been sub
87      *
88      * @param transaction Transaction handle
89      */
90     void onTransactionReady(final ClientTransaction transaction) {
91         client.transactionComplete(transaction);
92     }
93 }