You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by av...@apache.org on 2021/12/06 19:50:33 UTC

[ozone] branch master updated: HDDS-5965. Recon should be able to distinguish between containers that have no replicas and those have all replicas as UNHEALTHY. (#2874)

This is an automated email from the ASF dual-hosted git repository.

avijayan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new e86119f  HDDS-5965. Recon should be able to distinguish between containers that have no replicas and those have all replicas as UNHEALTHY. (#2874)
e86119f is described below

commit e86119f2d029ec0f7e6042be364079077cd1c88f
Author: avijayanhwx <14...@users.noreply.github.com>
AuthorDate: Mon Dec 6 11:50:08 2021 -0800

    HDDS-5965. Recon should be able to distinguish between containers that have no replicas and those have all replicas as UNHEALTHY. (#2874)
---
 .../interface-client/src/main/proto/hdds.proto     | 11 ++++++
 .../recon/schema/ContainerSchemaDefinition.java    |  3 +-
 .../codec/ContainerReplicaHistoryListCodec.java    | 45 +++-------------------
 .../ozone/recon/fsck/ContainerHealthStatus.java    | 17 ++++----
 .../persistence/ContainerHealthSchemaManager.java  | 12 +++++-
 .../ozone/recon/persistence/ContainerHistory.java  |  9 ++++-
 .../ozone/recon/scm/ContainerReplicaHistory.java   | 27 ++++++++++++-
 .../recon/scm/ContainerReplicaHistoryList.java     | 32 +++++++++++----
 .../ozone/recon/scm/ReconContainerManager.java     | 21 ++++++----
 .../impl/ReconContainerMetadataManagerImpl.java    |  4 +-
 .../ozone/recon/spi/impl/ReconDBDefinition.java    | 13 ++++++-
 .../ozone/recon/api/TestContainerEndpoint.java     | 26 ++++++-------
 .../ozone/recon/fsck/TestContainerHealthTask.java  | 16 +++++++-
 .../ozone/recon/scm/TestReconContainerManager.java | 13 +++++--
 14 files changed, 161 insertions(+), 88 deletions(-)

diff --git a/hadoop-hdds/interface-client/src/main/proto/hdds.proto b/hadoop-hdds/interface-client/src/main/proto/hdds.proto
index ee50354..133f4c6 100644
--- a/hadoop-hdds/interface-client/src/main/proto/hdds.proto
+++ b/hadoop-hdds/interface-client/src/main/proto/hdds.proto
@@ -368,3 +368,14 @@ message CertInfoProto {
     required uint64 timestamp = 2;
 }
 
+message ContainerReplicaHistoryListProto {
+    repeated ContainerReplicaHistoryProto replicaHistory = 1;
+}
+
+message ContainerReplicaHistoryProto {
+    required string uuid = 1;
+    required int64 firstSeenTime = 2;
+    required int64 lastSeenTime = 3;
+    required int64 bcsId = 4;
+}
+
diff --git a/hadoop-ozone/recon-codegen/src/main/java/org/hadoop/ozone/recon/schema/ContainerSchemaDefinition.java b/hadoop-ozone/recon-codegen/src/main/java/org/hadoop/ozone/recon/schema/ContainerSchemaDefinition.java
index c2fade35..1a04563 100644
--- a/hadoop-ozone/recon-codegen/src/main/java/org/hadoop/ozone/recon/schema/ContainerSchemaDefinition.java
+++ b/hadoop-ozone/recon-codegen/src/main/java/org/hadoop/ozone/recon/schema/ContainerSchemaDefinition.java
@@ -49,7 +49,8 @@ public class ContainerSchemaDefinition implements ReconSchemaDefinition {
     MISSING,
     UNDER_REPLICATED,
     OVER_REPLICATED,
-    MIS_REPLICATED
+    MIS_REPLICATED,
+    ALL_REPLICAS_UNHEALTHY
   }
 
   private static final String CONTAINER_ID = "container_id";
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/codec/ContainerReplicaHistoryListCodec.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/codec/ContainerReplicaHistoryListCodec.java
index cef9ff7..5cf575d 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/codec/ContainerReplicaHistoryListCodec.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/codec/ContainerReplicaHistoryListCodec.java
@@ -19,18 +19,11 @@
 
 package org.apache.hadoop.ozone.recon.codec;
 
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ContainerReplicaHistoryListProto;
 import org.apache.hadoop.hdds.utils.db.Codec;
-import org.apache.hadoop.hdds.utils.db.LongCodec;
-import org.apache.hadoop.ozone.recon.scm.ContainerReplicaHistory;
 import org.apache.hadoop.ozone.recon.scm.ContainerReplicaHistoryList;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
 
 /**
  * Codec for ContainerReplicaHistoryList.
@@ -38,44 +31,16 @@ import java.util.UUID;
 public class ContainerReplicaHistoryListCodec
     implements Codec<ContainerReplicaHistoryList> {
 
-  // UUID takes 2 long to store. Each timestamp takes 1 long to store.
-  static final int SIZE_PER_ENTRY = 4 * Long.BYTES;
-  private final Codec<Long> lc = new LongCodec();
-
   @Override
-  public byte[] toPersistedFormat(ContainerReplicaHistoryList obj)
-      throws IOException {
-
-    List<ContainerReplicaHistory> lst = obj.getList();
-    final int sizeOfRes = SIZE_PER_ENTRY * lst.size();
-    // ByteArrayOutputStream constructor has a sanity check on size.
-    ByteArrayOutputStream out = new ByteArrayOutputStream(sizeOfRes);
-    for (ContainerReplicaHistory ts : lst) {
-      out.write(lc.toPersistedFormat(ts.getUuid().getMostSignificantBits()));
-      out.write(lc.toPersistedFormat(ts.getUuid().getLeastSignificantBits()));
-      out.write(lc.toPersistedFormat(ts.getFirstSeenTime()));
-      out.write(lc.toPersistedFormat(ts.getLastSeenTime()));
-    }
-    return out.toByteArray();
+  public byte[] toPersistedFormat(ContainerReplicaHistoryList obj) {
+    return obj.toProto().toByteArray();
   }
 
   @Override
   public ContainerReplicaHistoryList fromPersistedFormat(byte[] rawData)
       throws IOException {
-
-    assert(rawData.length % SIZE_PER_ENTRY == 0);
-    DataInputStream in = new DataInputStream(new ByteArrayInputStream(rawData));
-    List<ContainerReplicaHistory> lst = new ArrayList<>();
-    while (in.available() > 0) {
-      final long uuidMsb = in.readLong();
-      final long uuidLsb = in.readLong();
-      final long firstSeenTime = in.readLong();
-      final long lastSeenTime = in.readLong();
-      final UUID id = new UUID(uuidMsb, uuidLsb);
-      lst.add(new ContainerReplicaHistory(id, firstSeenTime, lastSeenTime));
-    }
-    in.close();
-    return new ContainerReplicaHistoryList(lst);
+    return ContainerReplicaHistoryList.fromProto(
+        ContainerReplicaHistoryListProto.parseFrom(rawData));
   }
 
   @Override
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/fsck/ContainerHealthStatus.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/fsck/ContainerHealthStatus.java
index 4b2a665..5b5d4cc 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/fsck/ContainerHealthStatus.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/fsck/ContainerHealthStatus.java
@@ -37,20 +37,23 @@ public class ContainerHealthStatus {
 
   private ContainerInfo container;
   private int replicaDelta;
-  private Set<ContainerReplica> replicas;
+  private Set<ContainerReplica> healthyReplicas;
   private ContainerPlacementStatus placementStatus;
+  private int numReplicas;
 
   ContainerHealthStatus(ContainerInfo container,
-      Set<ContainerReplica> replicas, PlacementPolicy placementPolicy) {
+                        Set<ContainerReplica> healthyReplicas,
+                        PlacementPolicy placementPolicy) {
     this.container = container;
     int repFactor = container.getReplicationConfig().getRequiredNodes();
-    this.replicas = replicas
+    this.healthyReplicas = healthyReplicas
         .stream()
         .filter(r -> !r.getState()
             .equals((ContainerReplicaProto.State.UNHEALTHY)))
         .collect(Collectors.toSet());
-    this.replicaDelta = repFactor - this.replicas.size();
+    this.replicaDelta = repFactor - this.healthyReplicas.size();
     this.placementStatus = getPlacementStatus(placementPolicy, repFactor);
+    this.numReplicas = healthyReplicas.size();
   }
 
   public long getContainerID() {
@@ -87,7 +90,7 @@ public class ContainerHealthStatus {
   }
 
   public int getReplicaCount() {
-    return replicas.size();
+    return healthyReplicas.size();
   }
 
   public boolean isMisReplicated() {
@@ -111,12 +114,12 @@ public class ContainerHealthStatus {
   }
 
   public boolean isMissing() {
-    return replicas.size() == 0;
+    return numReplicas == 0;
   }
 
   private ContainerPlacementStatus getPlacementStatus(
       PlacementPolicy policy, int repFactor) {
-    List<DatanodeDetails> dns = replicas.stream()
+    List<DatanodeDetails> dns = healthyReplicas.stream()
         .map(ContainerReplica::getDatanodeDetails)
         .collect(Collectors.toList());
     return policy.validateContainerPlacement(dns, repFactor);
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
index 817f5f1..364aff1 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHealthSchemaManager.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.ozone.recon.persistence;
 
+import static org.hadoop.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates.UNDER_REPLICATED;
+import static org.hadoop.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates.ALL_REPLICAS_UNHEALTHY;
 import static org.hadoop.ozone.recon.schema.tables.UnhealthyContainersTable.UNHEALTHY_CONTAINERS;
 import static org.jooq.impl.DSL.count;
 
@@ -69,8 +71,14 @@ public class ContainerHealthSchemaManager {
     SelectQuery<Record> query = dslContext.selectQuery();
     query.addFrom(UNHEALTHY_CONTAINERS);
     if (state != null) {
-      query.addConditions(
-          UNHEALTHY_CONTAINERS.CONTAINER_STATE.eq(state.toString()));
+      if (state.equals(ALL_REPLICAS_UNHEALTHY)) {
+        query.addConditions(UNHEALTHY_CONTAINERS.CONTAINER_STATE
+            .eq(UNDER_REPLICATED.toString()));
+        query.addConditions(UNHEALTHY_CONTAINERS.ACTUAL_REPLICA_COUNT.eq(0));
+      } else {
+        query.addConditions(
+            UNHEALTHY_CONTAINERS.CONTAINER_STATE.eq(state.toString()));
+      }
     }
     query.addOrderBy(UNHEALTHY_CONTAINERS.CONTAINER_ID.asc(),
         UNHEALTHY_CONTAINERS.CONTAINER_STATE.asc());
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHistory.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHistory.java
index 4d9543e..a1d0b5d 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHistory.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/persistence/ContainerHistory.java
@@ -30,14 +30,21 @@ public class ContainerHistory implements Serializable {
   private String datanodeHost;
   private long firstSeenTime;
   private long lastSeenTime;
+  private long bcsId;
 
   public ContainerHistory(long containerId, String datanodeUuid,
-      String datanodeHost, long firstSeenTime, long lastSeenTime) {
+                          String datanodeHost, long firstSeenTime,
+                          long lastSeenTime, long lastBcsId) {
     this.containerId = containerId;
     this.datanodeUuid = datanodeUuid;
     this.datanodeHost = datanodeHost;
     this.firstSeenTime = firstSeenTime;
     this.lastSeenTime = lastSeenTime;
+    this.bcsId = lastBcsId;
+  }
+
+  public long getLastBcsId() {
+    return bcsId;
   }
 
   public long getContainerId() {
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistory.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistory.java
index c43bf05..79ea9b6 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistory.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistory.java
@@ -20,6 +20,8 @@ package org.apache.hadoop.ozone.recon.scm;
 
 import java.util.UUID;
 
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ContainerReplicaHistoryProto;
+
 /**
  * A ContainerReplica timestamp class that tracks first and last seen time.
  *
@@ -37,11 +39,22 @@ public class ContainerReplicaHistory {
   // Last reported time of the replica
   private Long lastSeenTime;
 
+  private long bcsId;
+
   public ContainerReplicaHistory(UUID id, Long firstSeenTime,
-      Long lastSeenTime) {
+      Long lastSeenTime, long bcsId) {
     this.uuid = id;
     this.firstSeenTime = firstSeenTime;
     this.lastSeenTime = lastSeenTime;
+    this.bcsId = bcsId;
+  }
+
+  public long getBcsId() {
+    return bcsId;
+  }
+
+  public void setBcsId(long bcsId) {
+    this.bcsId = bcsId;
   }
 
   public UUID getUuid() {
@@ -59,4 +72,16 @@ public class ContainerReplicaHistory {
   public void setLastSeenTime(Long lastSeenTime) {
     this.lastSeenTime = lastSeenTime;
   }
+
+  public static ContainerReplicaHistory fromProto(
+      ContainerReplicaHistoryProto proto) {
+    return new ContainerReplicaHistory(UUID.fromString(proto.getUuid()),
+        proto.getFirstSeenTime(), proto.getLastSeenTime(), proto.getBcsId());
+  }
+
+  public ContainerReplicaHistoryProto toProto() {
+    return ContainerReplicaHistoryProto.newBuilder().setUuid(uuid.toString())
+        .setFirstSeenTime(firstSeenTime).setLastSeenTime(lastSeenTime)
+        .setBcsId(bcsId).build();
+  }
 }
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistoryList.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistoryList.java
index fd905ec..0a19665 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistoryList.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ContainerReplicaHistoryList.java
@@ -18,9 +18,13 @@
 
 package org.apache.hadoop.ozone.recon.scm;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ContainerReplicaHistoryListProto;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ContainerReplicaHistoryProto;
+
 /**
  * A list of ContainerReplicaHistory.
  *
@@ -28,23 +32,37 @@ import java.util.List;
  */
 public class ContainerReplicaHistoryList {
 
-  private List<ContainerReplicaHistory> tsList;
+  private List<ContainerReplicaHistory> replicaHistories;
 
   public ContainerReplicaHistoryList(
-      List<ContainerReplicaHistory> tsList) {
-    this.tsList = tsList;
+      List<ContainerReplicaHistory> replicaHistories) {
+    this.replicaHistories = new ArrayList<>(replicaHistories);
   }
 
   public List<ContainerReplicaHistory> asList() {
-    return Collections.unmodifiableList(tsList);
+    return Collections.unmodifiableList(replicaHistories);
   }
 
   public List<ContainerReplicaHistory> getList() {
-    return tsList;
+    return replicaHistories;
+  }
+
+  public static ContainerReplicaHistoryList fromProto(
+      ContainerReplicaHistoryListProto proto) {
+    List<ContainerReplicaHistory> replicaHistoryList = new ArrayList<>();
+    for (ContainerReplicaHistoryProto rhProto : proto.getReplicaHistoryList()) {
+      replicaHistoryList.add(ContainerReplicaHistory.fromProto(rhProto));
+    }
+    return new ContainerReplicaHistoryList(replicaHistoryList);
   }
 
-  public void setList(List<ContainerReplicaHistory> list) {
-    this.tsList = list;
+  public ContainerReplicaHistoryListProto toProto() {
+    ContainerReplicaHistoryListProto.Builder builder =
+        ContainerReplicaHistoryListProto.newBuilder();
+    replicaHistories.stream()
+        .map(ContainerReplicaHistory::toProto)
+        .forEach(builder::addReplicaHistory);
+    return builder.build();
   }
 
 }
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconContainerManager.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconContainerManager.java
index 215ceb1..8e15162 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconContainerManager.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconContainerManager.java
@@ -286,13 +286,15 @@ public class ReconContainerManager extends ContainerManagerImpl {
         replicaHistoryMap.get(id);
 
     boolean flushToDB = false;
+    long bcsId = replica.getSequenceId() != null ? replica.getSequenceId() : -1;
 
     // If replica doesn't exist in in-memory map, add to DB and add to map
     if (replicaLastSeenMap == null) {
       // putIfAbsent to avoid TOCTOU
       replicaHistoryMap.putIfAbsent(id,
           new ConcurrentHashMap<UUID, ContainerReplicaHistory>() {{
-            put(uuid, new ContainerReplicaHistory(uuid, currTime, currTime));
+            put(uuid, new ContainerReplicaHistory(uuid, currTime, currTime,
+                bcsId));
           }});
       flushToDB = true;
     } else {
@@ -301,16 +303,17 @@ public class ReconContainerManager extends ContainerManagerImpl {
       if (ts == null) {
         // New Datanode
         replicaLastSeenMap.put(uuid,
-            new ContainerReplicaHistory(uuid, currTime, currTime));
+            new ContainerReplicaHistory(uuid, currTime, currTime, bcsId));
         flushToDB = true;
       } else {
-        // if the object exists, only update the last seen time field
+        // if the object exists, only update the last seen time & bcsId fields
         ts.setLastSeenTime(currTime);
+        ts.setBcsId(bcsId);
       }
     }
 
     if (flushToDB) {
-      upsertContainerHistory(id, uuid, currTime);
+      upsertContainerHistory(id, uuid, currTime, bcsId);
     }
   }
 
@@ -333,7 +336,7 @@ public class ReconContainerManager extends ContainerManagerImpl {
       final ContainerReplicaHistory ts = replicaLastSeenMap.get(uuid);
       if (ts != null) {
         // Flush to DB, then remove from in-memory map
-        upsertContainerHistory(id, uuid, ts.getLastSeenTime());
+        upsertContainerHistory(id, uuid, ts.getLastSeenTime(), ts.getBcsId());
         replicaLastSeenMap.remove(uuid);
       }
     }
@@ -390,8 +393,9 @@ public class ReconContainerManager extends ContainerManagerImpl {
       }
       final long firstSeenTime = entry.getValue().getFirstSeenTime();
       final long lastSeenTime = entry.getValue().getLastSeenTime();
+      long bcsId = entry.getValue().getBcsId();
       resList.add(new ContainerHistory(containerID, uuid.toString(), hostname,
-          firstSeenTime, lastSeenTime));
+          firstSeenTime, lastSeenTime, bcsId));
     }
     return resList;
   }
@@ -425,14 +429,15 @@ public class ReconContainerManager extends ContainerManagerImpl {
     }
   }
 
-  public void upsertContainerHistory(long containerID, UUID uuid, long time) {
+  public void upsertContainerHistory(long containerID, UUID uuid, long time,
+                                     long bcsId) {
     Map<UUID, ContainerReplicaHistory> tsMap;
     try {
       tsMap = cdbServiceProvider.getContainerReplicaHistory(containerID);
       ContainerReplicaHistory ts = tsMap.get(uuid);
       if (ts == null) {
         // New entry
-        tsMap.put(uuid, new ContainerReplicaHistory(uuid, time, time));
+        tsMap.put(uuid, new ContainerReplicaHistory(uuid, time, time, bcsId));
       } else {
         // Entry exists, update last seen time and put it back to DB.
         ts.setLastSeenTime(time);
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconContainerMetadataManagerImpl.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconContainerMetadataManagerImpl.java
index d93ccad..406cb79 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconContainerMetadataManagerImpl.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconContainerMetadataManagerImpl.java
@@ -19,10 +19,10 @@
 package org.apache.hadoop.ozone.recon.spi.impl;
 
 import static org.apache.hadoop.ozone.recon.ReconConstants.CONTAINER_COUNT_KEY;
+import static org.apache.hadoop.ozone.recon.spi.impl.ReconDBDefinition.REPLICA_HISTORY_V2;
 import static org.apache.hadoop.ozone.recon.spi.impl.ReconDBProvider.truncateTable;
 import static org.apache.hadoop.ozone.recon.spi.impl.ReconDBDefinition.CONTAINER_KEY;
 import static org.apache.hadoop.ozone.recon.spi.impl.ReconDBDefinition.CONTAINER_KEY_COUNT;
-import static org.apache.hadoop.ozone.recon.spi.impl.ReconDBDefinition.REPLICA_HISTORY;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -119,7 +119,7 @@ public class ReconContainerMetadataManagerImpl
       this.containerKeyCountTable =
           CONTAINER_KEY_COUNT.getTable(containerDbStore);
       this.containerReplicaHistoryTable =
-          REPLICA_HISTORY.getTable(containerDbStore);
+          REPLICA_HISTORY_V2.getTable(containerDbStore);
     } catch (IOException e) {
       LOG.error("Unable to create Container Key tables.", e);
     }
diff --git a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconDBDefinition.java b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconDBDefinition.java
index cfaa2b0..845e6b2 100644
--- a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconDBDefinition.java
+++ b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/spi/impl/ReconDBDefinition.java
@@ -74,6 +74,16 @@ public class ReconDBDefinition implements DBDefinition {
           NSSummary.class,
           new NSSummaryCodec());
 
+  // Container Replica History with bcsId tracking.
+  public static final DBColumnFamilyDefinition
+      <Long, ContainerReplicaHistoryList> REPLICA_HISTORY_V2 =
+      new DBColumnFamilyDefinition<Long, ContainerReplicaHistoryList>(
+          "replica_history_v2",
+          Long.class,
+          new LongCodec(),
+          ContainerReplicaHistoryList.class,
+          new ContainerReplicaHistoryListCodec());
+
   @Override
   public String getName() {
     return dbName;
@@ -87,6 +97,7 @@ public class ReconDBDefinition implements DBDefinition {
   @Override
   public DBColumnFamilyDefinition[] getColumnFamilies() {
     return new DBColumnFamilyDefinition[] {
-        CONTAINER_KEY, CONTAINER_KEY_COUNT, REPLICA_HISTORY, NAMESPACE_SUMMARY};
+        CONTAINER_KEY, CONTAINER_KEY_COUNT, REPLICA_HISTORY,
+        NAMESPACE_SUMMARY, REPLICA_HISTORY_V2};
   }
 }
diff --git a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
index c5d9944..c44c67b 100644
--- a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
+++ b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/api/TestContainerEndpoint.java
@@ -439,10 +439,10 @@ public class TestContainerEndpoint {
     final UUID u2 = newDatanode("host2", "127.0.0.2");
     final UUID u3 = newDatanode("host3", "127.0.0.3");
     final UUID u4 = newDatanode("host4", "127.0.0.4");
-    reconContainerManager.upsertContainerHistory(1L, u1, 1L);
-    reconContainerManager.upsertContainerHistory(1L, u2, 2L);
-    reconContainerManager.upsertContainerHistory(1L, u3, 3L);
-    reconContainerManager.upsertContainerHistory(1L, u4, 4L);
+    reconContainerManager.upsertContainerHistory(1L, u1, 1L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u2, 2L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u3, 3L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u4, 4L, 1L);
 
     response = containerEndpoint.getMissingContainers();
     responseObject = (MissingContainersResponse) response.getEntity();
@@ -670,12 +670,12 @@ public class TestContainerEndpoint {
     final UUID u2 = newDatanode("host2", "127.0.0.2");
     final UUID u3 = newDatanode("host3", "127.0.0.3");
     final UUID u4 = newDatanode("host4", "127.0.0.4");
-    reconContainerManager.upsertContainerHistory(1L, u1, 1L);
-    reconContainerManager.upsertContainerHistory(1L, u2, 2L);
-    reconContainerManager.upsertContainerHistory(1L, u3, 3L);
-    reconContainerManager.upsertContainerHistory(1L, u4, 4L);
+    reconContainerManager.upsertContainerHistory(1L, u1, 1L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u2, 2L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u3, 3L, 1L);
+    reconContainerManager.upsertContainerHistory(1L, u4, 4L, 1L);
 
-    reconContainerManager.upsertContainerHistory(1L, u1, 5L);
+    reconContainerManager.upsertContainerHistory(1L, u1, 5L, 1L);
 
     Response response = containerEndpoint.getReplicaHistoryForContainer(1L);
     List<ContainerHistory> histories =
@@ -755,10 +755,10 @@ public class TestContainerEndpoint {
     missingList.add(missing);
     containerHealthSchemaManager.insertUnhealthyContainerRecords(missingList);
 
-    reconContainerManager.upsertContainerHistory(cID, uuid1, 1L);
-    reconContainerManager.upsertContainerHistory(cID, uuid2, 2L);
-    reconContainerManager.upsertContainerHistory(cID, uuid3, 3L);
-    reconContainerManager.upsertContainerHistory(cID, uuid4, 4L);
+    reconContainerManager.upsertContainerHistory(cID, uuid1, 1L, 1L);
+    reconContainerManager.upsertContainerHistory(cID, uuid2, 2L, 1L);
+    reconContainerManager.upsertContainerHistory(cID, uuid3, 3L, 1L);
+    reconContainerManager.upsertContainerHistory(cID, uuid4, 4L, 1L);
   }
 
   private BucketLayout getBucketLayout() {
diff --git a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
index 800d004..ac5aeaf 100644
--- a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
+++ b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/fsck/TestContainerHealthTask.java
@@ -19,6 +19,7 @@
 package org.apache.hadoop.ozone.recon.fsck;
 
 import static junit.framework.TestCase.assertEquals;
+import static org.hadoop.ozone.recon.schema.ContainerSchemaDefinition.UnHealthyContainerStates.ALL_REPLICAS_UNHEALTHY;
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -63,6 +64,8 @@ import org.junit.Test;
  * Class to test a single run of the Container Health Task.
  */
 public class TestContainerHealthTask extends AbstractReconSqlDBTest {
+
+  @SuppressWarnings("checkstyle:methodlength")
   @Test
   public void testRun() throws Exception {
     UnhealthyContainersDao unHealthyContainersTableHandle =
@@ -98,7 +101,7 @@ public class TestContainerHealthTask extends AbstractReconSqlDBTest {
     when(containerManagerMock.getContainerReplicas(ContainerID.valueOf(1L)))
         .thenReturn(getMockReplicas(1L, State.CLOSED, State.UNHEALTHY));
 
-    // return one UNHEALTHY replica for container ID 2 -> Missing
+    // return all UNHEALTHY replicas for container ID 2 -> UNDER_REPLICATED
     when(containerManagerMock.getContainerReplicas(ContainerID.valueOf(2L)))
         .thenReturn(getMockReplicas(2L, State.UNHEALTHY));
 
@@ -145,9 +148,18 @@ public class TestContainerHealthTask extends AbstractReconSqlDBTest {
     assertEquals(2, rec.getReplicaDelta().intValue());
 
     rec = unHealthyContainersTableHandle.fetchByContainerId(2L).get(0);
-    assertEquals("MISSING", rec.getContainerState());
+    assertEquals("UNDER_REPLICATED", rec.getContainerState());
     assertEquals(3, rec.getReplicaDelta().intValue());
 
+    List<UnhealthyContainers> unhealthyContainers =
+        containerHealthSchemaManager.getUnhealthyContainers(
+            ALL_REPLICAS_UNHEALTHY, 0, Integer.MAX_VALUE);
+    assertEquals(1, unhealthyContainers.size());
+    assertEquals(2L,
+        unhealthyContainers.get(0).getContainerId().longValue());
+    assertEquals(0,
+        unhealthyContainers.get(0).getActualReplicaCount().intValue());
+
     rec = unHealthyContainersTableHandle.fetchByContainerId(3L).get(0);
     assertEquals("MISSING", rec.getContainerState());
     assertEquals(3, rec.getReplicaDelta().intValue());
diff --git a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/scm/TestReconContainerManager.java b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/scm/TestReconContainerManager.java
index cf4d89b..6a86a91 100644
--- a/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/scm/TestReconContainerManager.java
+++ b/hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/scm/TestReconContainerManager.java
@@ -206,9 +206,9 @@ public class TestReconContainerManager
     final UUID uuid1 = UUID.randomUUID();
     final DatanodeDetails datanodeDetails1 = DatanodeDetails.newBuilder()
         .setUuid(uuid1).setHostName("host1").setIpAddress("127.0.0.1").build();
-    final ContainerReplica containerReplica1 = ContainerReplica.newBuilder()
+    ContainerReplica containerReplica1 = ContainerReplica.newBuilder()
         .setContainerID(containerID1).setContainerState(State.OPEN)
-        .setDatanodeDetails(datanodeDetails1).build();
+        .setDatanodeDetails(datanodeDetails1).setSequenceId(1001L).build();
 
     final ReconContainerManager containerManager = getContainerManager();
     final Map<Long, Map<UUID, ContainerReplicaHistory>> repHistMap =
@@ -234,13 +234,19 @@ public class TestReconContainerManager
     Assert.assertEquals(uuid1, repHist1.getUuid());
     // Because this is a new entry, first seen time equals last seen time
     assertEquals(repHist1.getLastSeenTime(), repHist1.getFirstSeenTime());
+    assertEquals(containerReplica1.getSequenceId().longValue(),
+        repHist1.getBcsId());
 
     // Let's update the entry again
+    containerReplica1 = ContainerReplica.newBuilder()
+        .setContainerID(containerID1).setContainerState(State.OPEN)
+        .setDatanodeDetails(datanodeDetails1).setSequenceId(1051L).build();
     containerManager.updateContainerReplica(containerID1, containerReplica1);
     // Should still have 1 entry in the replica history map
     Assert.assertEquals(1, repHistMap.size());
     // Now last seen time should be larger than first seen time
     Assert.assertTrue(repHist1.getLastSeenTime() > repHist1.getFirstSeenTime());
+    assertEquals(1051L, repHist1.getBcsId());
 
     // Init DN02
     final UUID uuid2 = UUID.randomUUID();
@@ -248,7 +254,7 @@ public class TestReconContainerManager
         .setUuid(uuid2).setHostName("host2").setIpAddress("127.0.0.2").build();
     final ContainerReplica containerReplica2 = ContainerReplica.newBuilder()
         .setContainerID(containerID1).setContainerState(State.OPEN)
-        .setDatanodeDetails(datanodeDetails2).build();
+        .setDatanodeDetails(datanodeDetails2).setSequenceId(1051L).build();
 
     // Add replica to DN02
     containerManager.updateContainerReplica(containerID1, containerReplica2);
@@ -261,6 +267,7 @@ public class TestReconContainerManager
     Assert.assertEquals(uuid2, repHist2.getUuid());
     // Because this is a new entry, first seen time equals last seen time
     assertEquals(repHist2.getLastSeenTime(), repHist2.getFirstSeenTime());
+    assertEquals(1051L, repHist2.getBcsId());
 
     // Remove replica from DN01
     containerManager.removeContainerReplica(containerID1, containerReplica1);

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org