Define DataStoreVersions.MAGNESIUM_VERSION
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / FrontendMetadata.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.datastore;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.Collections2;
14 import com.google.common.collect.Maps;
15 import java.util.HashMap;
16 import java.util.Map;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
19 import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier;
20 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
21 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
22 import org.opendaylight.controller.cluster.datastore.persisted.FrontendClientMetadata;
23 import org.opendaylight.controller.cluster.datastore.persisted.FrontendShardDataTreeSnapshotMetadata;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Frontend state as observed by a shard follower. This class is responsible for maintaining metadata state
29  * so that this can be used to seed {@link LeaderFrontendState} with proper state so that the frontend/backend
30  * conversation can continue where it left off. This class is NOT thread-safe.
31  *
32  * @author Robert Varga
33  */
34 final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTreeSnapshotMetadata> {
35     private static final Logger LOG = LoggerFactory.getLogger(FrontendMetadata.class);
36
37     private final Map<FrontendIdentifier, FrontendClientMetadataBuilder> clients = new HashMap<>();
38     private final String shardName;
39
40     FrontendMetadata(final String shardName) {
41         this.shardName = requireNonNull(shardName);
42     }
43
44     @Override
45     Class<FrontendShardDataTreeSnapshotMetadata> getSupportedType() {
46         return FrontendShardDataTreeSnapshotMetadata.class;
47     }
48
49     @Override
50     void reset() {
51         LOG.debug("{}: clearing clients {}", shardName, clients);
52         clients.clear();
53     }
54
55     @Override
56     void doApplySnapshot(final FrontendShardDataTreeSnapshotMetadata snapshot) {
57         LOG.debug("{}: applying snapshot {} over clients {}", shardName, snapshot, clients);
58         clients.clear();
59
60         for (FrontendClientMetadata m : snapshot.getClients()) {
61             LOG.debug("{}: applying metadata {}", shardName, m);
62             final FrontendClientMetadataBuilder b = FrontendClientMetadataBuilder.of(shardName, m);
63             final FrontendIdentifier client = m.getIdentifier().getFrontendId();
64
65             LOG.debug("{}: client {} updated to {}", shardName, client, b);
66             clients.put(client, b);
67         }
68     }
69
70     @Override
71     FrontendShardDataTreeSnapshotMetadata toSnapshot() {
72         return new FrontendShardDataTreeSnapshotMetadata(Collections2.transform(clients.values(),
73             FrontendClientMetadataBuilder::build));
74     }
75
76     private FrontendClientMetadataBuilder ensureClient(final ClientIdentifier id) {
77         final FrontendClientMetadataBuilder existing = clients.get(id.getFrontendId());
78         if (existing != null && id.equals(existing.getIdentifier())) {
79             return existing;
80         }
81
82         final FrontendClientMetadataBuilder client = new FrontendClientMetadataBuilder.Enabled(shardName, id);
83         final FrontendClientMetadataBuilder previous = clients.put(id.getFrontendId(), client);
84         if (previous != null) {
85             LOG.debug("{}: Replaced client {} with {}", shardName, previous, client);
86         } else {
87             LOG.debug("{}: Added client {}", shardName, client);
88         }
89         return client;
90     }
91
92     @Override
93     void onHistoryCreated(final LocalHistoryIdentifier historyId) {
94         ensureClient(historyId.getClientId()).onHistoryCreated(historyId);
95     }
96
97     @Override
98     void onHistoryClosed(final LocalHistoryIdentifier historyId) {
99         ensureClient(historyId.getClientId()).onHistoryClosed(historyId);
100     }
101
102     @Override
103     void onHistoryPurged(final LocalHistoryIdentifier historyId) {
104         ensureClient(historyId.getClientId()).onHistoryPurged(historyId);
105     }
106
107     @Override
108     void onTransactionAborted(final TransactionIdentifier txId) {
109         ensureClient(txId.getHistoryId().getClientId()).onTransactionAborted(txId);
110     }
111
112     @Override
113     void onTransactionCommitted(final TransactionIdentifier txId) {
114         ensureClient(txId.getHistoryId().getClientId()).onTransactionCommitted(txId);
115     }
116
117     @Override
118     void onTransactionPurged(final TransactionIdentifier txId) {
119         ensureClient(txId.getHistoryId().getClientId()).onTransactionPurged(txId);
120     }
121
122     /**
123      * Transform frontend metadata into an active leader state map.
124      *
125      * @return Leader frontend state
126      */
127     @NonNull Map<FrontendIdentifier, LeaderFrontendState> toLeaderState(final @NonNull Shard shard) {
128         return new HashMap<>(Maps.transformValues(clients, meta -> meta.toLeaderState(shard)));
129     }
130
131     void disableTracking(final ClientIdentifier clientId) {
132         final FrontendIdentifier frontendId = clientId.getFrontendId();
133         final FrontendClientMetadataBuilder client = clients.get(frontendId);
134         if (client == null) {
135             // When we havent seen the client before, we still need to disable tracking for him since this only gets
136             // triggered once.
137             LOG.debug("{}: disableTracking {} does not match any client, pre-disabling client.", shardName, clientId);
138             clients.put(frontendId, new FrontendClientMetadataBuilder.Disabled(shardName, clientId));
139             return;
140         }
141         if (!clientId.equals(client.getIdentifier())) {
142             LOG.debug("{}: disableTracking {} does not match client {}, ignoring", shardName, clientId, client);
143             return;
144         }
145         if (client instanceof FrontendClientMetadataBuilder.Disabled) {
146             LOG.debug("{}: client {} is has already disabled tracking", shardName, client);
147             return;
148         }
149
150         verify(clients.replace(frontendId, client, new FrontendClientMetadataBuilder.Disabled(shardName, clientId)));
151     }
152 }