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.datastore;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.collect.Collections2;
14 import com.google.common.collect.ImmutableSet;
15 import com.google.common.collect.Maps;
16 import java.util.HashMap;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
20 import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier;
21 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
22 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
23 import org.opendaylight.controller.cluster.datastore.persisted.FrontendClientMetadata;
24 import org.opendaylight.controller.cluster.datastore.persisted.FrontendShardDataTreeSnapshotMetadata;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Frontend state as observed by a shard follower. This class is responsible for maintaining metadata state
30 * so that this can be used to seed {@link LeaderFrontendState} with proper state so that the frontend/backend
31 * conversation can continue where it left off. This class is NOT thread-safe.
33 * @author Robert Varga
35 final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTreeSnapshotMetadata> {
36 private static final Logger LOG = LoggerFactory.getLogger(FrontendMetadata.class);
38 private final Map<FrontendIdentifier, FrontendClientMetadataBuilder> clients = new HashMap<>();
39 private final String shardName;
41 FrontendMetadata(final String shardName) {
42 this.shardName = requireNonNull(shardName);
46 Class<FrontendShardDataTreeSnapshotMetadata> getSupportedType() {
47 return FrontendShardDataTreeSnapshotMetadata.class;
52 LOG.debug("{}: clearing clients {}", shardName, clients);
57 void doApplySnapshot(final FrontendShardDataTreeSnapshotMetadata snapshot) {
58 LOG.debug("{}: applying snapshot {} over clients {}", shardName, snapshot, clients);
61 for (FrontendClientMetadata m : snapshot.getClients()) {
62 LOG.debug("{}: applying metadata {}", shardName, m);
63 final FrontendClientMetadataBuilder b = FrontendClientMetadataBuilder.of(shardName, m);
64 final FrontendIdentifier client = m.getIdentifier().getFrontendId();
66 LOG.debug("{}: client {} updated to {}", shardName, client, b);
67 clients.put(client, b);
72 FrontendShardDataTreeSnapshotMetadata toSnapshot() {
73 return new FrontendShardDataTreeSnapshotMetadata(Collections2.transform(clients.values(),
74 FrontendClientMetadataBuilder::build));
77 private FrontendClientMetadataBuilder ensureClient(final ClientIdentifier id) {
78 final FrontendClientMetadataBuilder existing = clients.get(id.getFrontendId());
79 if (existing != null && id.equals(existing.getIdentifier())) {
83 final FrontendClientMetadataBuilder client = new FrontendClientMetadataBuilder.Enabled(shardName, id);
84 final FrontendClientMetadataBuilder previous = clients.put(id.getFrontendId(), client);
85 if (previous != null) {
86 LOG.debug("{}: Replaced client {} with {}", shardName, previous, client);
88 LOG.debug("{}: Added client {}", shardName, client);
94 void onHistoryCreated(final LocalHistoryIdentifier historyId) {
95 ensureClient(historyId.getClientId()).onHistoryCreated(historyId);
99 void onHistoryClosed(final LocalHistoryIdentifier historyId) {
100 ensureClient(historyId.getClientId()).onHistoryClosed(historyId);
104 void onHistoryPurged(final LocalHistoryIdentifier historyId) {
105 ensureClient(historyId.getClientId()).onHistoryPurged(historyId);
109 void onTransactionAborted(final TransactionIdentifier txId) {
110 ensureClient(txId.getHistoryId().getClientId()).onTransactionAborted(txId);
114 void onTransactionCommitted(final TransactionIdentifier txId) {
115 ensureClient(txId.getHistoryId().getClientId()).onTransactionCommitted(txId);
119 void onTransactionPurged(final TransactionIdentifier txId) {
120 ensureClient(txId.getHistoryId().getClientId()).onTransactionPurged(txId);
124 * Transform frontend metadata into an active leader state map.
126 * @return Leader frontend state
128 @NonNull Map<FrontendIdentifier, LeaderFrontendState> toLeaderState(final @NonNull Shard shard) {
129 return new HashMap<>(Maps.transformValues(clients, meta -> meta.toLeaderState(shard)));
132 void disableTracking(final ClientIdentifier clientId) {
133 final FrontendIdentifier frontendId = clientId.getFrontendId();
134 final FrontendClientMetadataBuilder client = clients.get(frontendId);
135 if (client == null) {
136 // When we havent seen the client before, we still need to disable tracking for him since this only gets
138 LOG.debug("{}: disableTracking {} does not match any client, pre-disabling client.", shardName, clientId);
139 clients.put(frontendId, new FrontendClientMetadataBuilder.Disabled(shardName, clientId));
142 if (!clientId.equals(client.getIdentifier())) {
143 LOG.debug("{}: disableTracking {} does not match client {}, ignoring", shardName, clientId, client);
146 if (client instanceof FrontendClientMetadataBuilder.Disabled) {
147 LOG.debug("{}: client {} is has already disabled tracking", shardName, client);
151 verify(clients.replace(frontendId, client, new FrontendClientMetadataBuilder.Disabled(shardName, clientId)));
154 ImmutableSet<ClientIdentifier> getClients() {
155 return clients.values().stream()
156 .map(FrontendClientMetadataBuilder::getIdentifier)
157 .collect(ImmutableSet.toImmutableSet());