Correct Frontend{Client,History}Metadata deserialization
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / FrontendMetadata.java
index 6a04674b6ca2919c32b63a28e1b699a037d73cc1..d5ecbf6ea416c6c283f0e06b5537293bbdef99e8 100644 (file)
@@ -7,10 +7,15 @@
  */
 package org.opendaylight.controller.cluster.datastore;
 
+import static com.google.common.base.Verify.verify;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
 import java.util.HashMap;
 import java.util.Map;
-import javax.annotation.concurrent.NotThreadSafe;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.controller.cluster.access.concepts.ClientIdentifier;
 import org.opendaylight.controller.cluster.access.concepts.FrontendIdentifier;
 import org.opendaylight.controller.cluster.access.concepts.LocalHistoryIdentifier;
@@ -23,15 +28,19 @@ import org.slf4j.LoggerFactory;
 /**
  * Frontend state as observed by a shard follower. This class is responsible for maintaining metadata state
  * so that this can be used to seed {@link LeaderFrontendState} with proper state so that the frontend/backend
- * conversation can continue where it left off.
+ * conversation can continue where it left off. This class is NOT thread-safe.
  *
  * @author Robert Varga
  */
-@NotThreadSafe
 final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTreeSnapshotMetadata> {
     private static final Logger LOG = LoggerFactory.getLogger(FrontendMetadata.class);
 
     private final Map<FrontendIdentifier, FrontendClientMetadataBuilder> clients = new HashMap<>();
+    private final String shardName;
+
+    FrontendMetadata(final String shardName) {
+        this.shardName = requireNonNull(shardName);
+    }
 
     @Override
     Class<FrontendShardDataTreeSnapshotMetadata> getSupportedType() {
@@ -40,15 +49,22 @@ final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTree
 
     @Override
     void reset() {
+        LOG.debug("{}: clearing clients {}", shardName, clients);
         clients.clear();
     }
 
     @Override
     void doApplySnapshot(final FrontendShardDataTreeSnapshotMetadata snapshot) {
+        LOG.debug("{}: applying snapshot {} over clients {}", shardName, snapshot, clients);
         clients.clear();
 
         for (FrontendClientMetadata m : snapshot.getClients()) {
-            clients.put(m.getIdentifier().getFrontendId(), new FrontendClientMetadataBuilder(m));
+            LOG.debug("{}: applying metadata {}", shardName, m);
+            final FrontendClientMetadataBuilder b = FrontendClientMetadataBuilder.of(shardName, m);
+            final FrontendIdentifier client = m.getIdentifier().getFrontendId();
+
+            LOG.debug("{}: client {} updated to {}", shardName, client, b);
+            clients.put(client, b);
         }
     }
 
@@ -64,16 +80,21 @@ final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTree
             return existing;
         }
 
-        final FrontendClientMetadataBuilder client = new FrontendClientMetadataBuilder(id);
+        final FrontendClientMetadataBuilder client = new FrontendClientMetadataBuilder.Enabled(shardName, id);
         final FrontendClientMetadataBuilder previous = clients.put(id.getFrontendId(), client);
         if (previous != null) {
-            LOG.debug("Replaced client {} with {}", previous, client);
+            LOG.debug("{}: Replaced client {} with {}", shardName, previous, client);
         } else {
-            LOG.debug("Added client {}", client);
+            LOG.debug("{}: Added client {}", shardName, client);
         }
         return client;
     }
 
+    @Override
+    void onHistoryCreated(final LocalHistoryIdentifier historyId) {
+        ensureClient(historyId.getClientId()).onHistoryCreated(historyId);
+    }
+
     @Override
     void onHistoryClosed(final LocalHistoryIdentifier historyId) {
         ensureClient(historyId.getClientId()).onHistoryClosed(historyId);
@@ -84,8 +105,55 @@ final class FrontendMetadata extends ShardDataTreeMetadata<FrontendShardDataTree
         ensureClient(historyId.getClientId()).onHistoryPurged(historyId);
     }
 
+    @Override
+    void onTransactionAborted(final TransactionIdentifier txId) {
+        ensureClient(txId.getHistoryId().getClientId()).onTransactionAborted(txId);
+    }
+
     @Override
     void onTransactionCommitted(final TransactionIdentifier txId) {
         ensureClient(txId.getHistoryId().getClientId()).onTransactionCommitted(txId);
     }
+
+    @Override
+    void onTransactionPurged(final TransactionIdentifier txId) {
+        ensureClient(txId.getHistoryId().getClientId()).onTransactionPurged(txId);
+    }
+
+    /**
+     * Transform frontend metadata into an active leader state map.
+     *
+     * @return Leader frontend state
+     */
+    @NonNull Map<FrontendIdentifier, LeaderFrontendState> toLeaderState(final @NonNull Shard shard) {
+        return new HashMap<>(Maps.transformValues(clients, meta -> meta.toLeaderState(shard)));
+    }
+
+    void disableTracking(final ClientIdentifier clientId) {
+        final FrontendIdentifier frontendId = clientId.getFrontendId();
+        final FrontendClientMetadataBuilder client = clients.get(frontendId);
+        if (client == null) {
+            // When we havent seen the client before, we still need to disable tracking for him since this only gets
+            // triggered once.
+            LOG.debug("{}: disableTracking {} does not match any client, pre-disabling client.", shardName, clientId);
+            clients.put(frontendId, new FrontendClientMetadataBuilder.Disabled(shardName, clientId));
+            return;
+        }
+        if (!clientId.equals(client.getIdentifier())) {
+            LOG.debug("{}: disableTracking {} does not match client {}, ignoring", shardName, clientId, client);
+            return;
+        }
+        if (client instanceof FrontendClientMetadataBuilder.Disabled) {
+            LOG.debug("{}: client {} is has already disabled tracking", shardName, client);
+            return;
+        }
+
+        verify(clients.replace(frontendId, client, new FrontendClientMetadataBuilder.Disabled(shardName, clientId)));
+    }
+
+    ImmutableSet<ClientIdentifier> getClients() {
+        return clients.values().stream()
+                .map(FrontendClientMetadataBuilder::getIdentifier)
+                .collect(ImmutableSet.toImmutableSet());
+    }
 }