aswinshakil commented on code in PR #8402:
URL: https://github.com/apache/ozone/pull/8402#discussion_r2078200691


##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/checksum/ContainerChecksumTreeManager.java:
##########
@@ -354,8 +375,6 @@ private void write(ContainerData data, 
ContainerProtos.ContainerChecksumInfo che
       throw new IOException("Error occurred when writing container merkle tree 
for containerID "
           + data.getContainerID(), ex);
     }
-    // Set in-memory data checksum.
-    
data.setDataChecksum(checksumInfo.getContainerMerkleTree().getDataChecksum());

Review Comment:
   Right now this is also being used by `markBlockAsDeleted` in case of failure 
in that code flow we also want set the checksum. 



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/checksum/ContainerMerkleTreeWriter.java:
##########
@@ -49,21 +49,67 @@ public class ContainerMerkleTreeWriter {
   public static final Supplier<ChecksumByteBuffer> CHECKSUM_BUFFER_SUPPLIER = 
ChecksumByteBufferFactory::crc32CImpl;
 
   /**
-   * Constructs an empty Container merkle tree object.
+   * Constructs a writer for an initially empty container merkle tree.
    */
   public ContainerMerkleTreeWriter() {
     id2Block = new TreeMap<>();
   }
 
+  /**
+   * Constructs a writer for a container merkle tree which initially contains 
all the information from the specified
+   * proto.
+   */
+  public ContainerMerkleTreeWriter(ContainerProtos.ContainerMerkleTree 
fromTree) {
+    id2Block = new TreeMap<>();
+    for (ContainerProtos.BlockMerkleTree blockTree: 
fromTree.getBlockMerkleTreeList()) {
+      long blockID = blockTree.getBlockID();
+      addBlock(blockID);

Review Comment:
   Same as the above, I don't think this is adding any entry to the `id2Block` 
map. 



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/checksum/ContainerChecksumTreeManager.java:
##########
@@ -81,35 +81,45 @@ public void stop() {
    * The data merkle tree within the file is replaced with the {@code tree} 
parameter, but all other content of the
    * file remains unchanged.
    * Concurrent writes to the same file are coordinated internally.
+   * This method also updates the container's data checksum in the {@code 
data} parameter, which will be seen by SCM
+   * on container reports.
    */
   public ContainerProtos.ContainerChecksumInfo 
writeContainerDataTree(ContainerData data,
-                                                                      
ContainerMerkleTreeWriter tree)
-      throws IOException {
+      ContainerMerkleTreeWriter tree) throws IOException {
     long containerID = data.getContainerID();
+    // If there is an error generating the tree and we cannot obtain a final 
checksum, use 0 to indicate a metadata
+    // failure.
+    long dataChecksum = 0;
+    ContainerProtos.ContainerChecksumInfo checksumInfo = null;
     Lock writeLock = getLock(containerID);
     writeLock.lock();
     try {
       ContainerProtos.ContainerChecksumInfo.Builder checksumInfoBuilder = null;
       try {
         // If the file is not present, we will create the data for the first 
time. This happens under a write lock.
-        checksumInfoBuilder = readBuilder(data)
-            .orElse(ContainerProtos.ContainerChecksumInfo.newBuilder());
+        checksumInfoBuilder = 
readBuilder(data).orElse(ContainerProtos.ContainerChecksumInfo.newBuilder());
       } catch (IOException ex) {
-        LOG.error("Failed to read container checksum tree file for container 
{}. Overwriting it with a new instance.",
+        LOG.error("Failed to read container checksum tree file for container 
{}. Creating a new instance.",
             containerID, ex);
         checksumInfoBuilder = 
ContainerProtos.ContainerChecksumInfo.newBuilder();
       }
 
-      ContainerProtos.ContainerChecksumInfo checksumInfo = checksumInfoBuilder
+      ContainerProtos.ContainerMerkleTree treeProto = 
captureLatencyNs(metrics.getCreateMerkleTreeLatencyNS(),
+          tree::toProto);
+      checksumInfoBuilder
           .setContainerID(containerID)
-          
.setContainerMerkleTree(captureLatencyNs(metrics.getCreateMerkleTreeLatencyNS(),
 tree::toProto))
-          .build();
+          .setContainerMerkleTree(treeProto);
+      checksumInfo = checksumInfoBuilder.build();
       write(data, checksumInfo);
-      LOG.debug("Data merkle tree for container {} updated", containerID);
-      return checksumInfo;
+      // If write succeeds, update the checksum in memory. Otherwise 0 will be 
used to indicate the metadata failure.
+      dataChecksum = treeProto.getDataChecksum();
+      LOG.debug("Data merkle tree for container {} updated with container 
checksum {}", containerID, dataChecksum);

Review Comment:
   If it is 0 we should show it as 0, and if it is not 0 then do the 
`checksumToString` conversion. We can add this condition to `checksumToString` 
to simplify this.
   ```suggestion
         LOG.debug("Data merkle tree for container {} updated with container 
checksum {}", containerID, checksumToString(dataChecksum));
   ```



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/checksum/ContainerMerkleTreeWriter.java:
##########
@@ -49,21 +49,67 @@ public class ContainerMerkleTreeWriter {
   public static final Supplier<ChecksumByteBuffer> CHECKSUM_BUFFER_SUPPLIER = 
ChecksumByteBufferFactory::crc32CImpl;
 
   /**
-   * Constructs an empty Container merkle tree object.
+   * Constructs a writer for an initially empty container merkle tree.
    */
   public ContainerMerkleTreeWriter() {
     id2Block = new TreeMap<>();
   }
 
+  /**
+   * Constructs a writer for a container merkle tree which initially contains 
all the information from the specified
+   * proto.
+   */
+  public ContainerMerkleTreeWriter(ContainerProtos.ContainerMerkleTree 
fromTree) {
+    id2Block = new TreeMap<>();
+    for (ContainerProtos.BlockMerkleTree blockTree: 
fromTree.getBlockMerkleTreeList()) {
+      long blockID = blockTree.getBlockID();
+      addBlock(blockID);
+      for (ContainerProtos.ChunkMerkleTree chunkTree: 
blockTree.getChunkMerkleTreeList()) {
+        addChunks(blockID, chunkTree);
+      }
+    }
+  }
+
   /**
    * Adds chunks to a block in the tree. The block entry will be created if it 
is the first time adding chunks to it.
    * If the block entry already exists, the chunks will be added to the 
existing chunks for that block.
    *
    * @param blockID The ID of the block that these chunks belong to.
+   * @param healthy True if there were no errors detected with these chunks. 
False indicates that all the chunks
+   *                being added had errors.
    * @param chunks A list of chunks to add to this block. The chunks will be 
sorted internally by their offset.
    */
-  public void addChunks(long blockID, Collection<ContainerProtos.ChunkInfo> 
chunks) {
-    id2Block.computeIfAbsent(blockID, 
BlockMerkleTreeWriter::new).addChunks(chunks);
+  public void addChunks(long blockID, boolean healthy, 
Collection<ContainerProtos.ChunkInfo> chunks) {
+    for (ContainerProtos.ChunkInfo chunk: chunks) {
+      addChunks(blockID, healthy, chunk);
+    }
+  }
+
+  public void addChunks(long blockID, boolean healthy, 
ContainerProtos.ChunkInfo... chunks) {
+    for (ContainerProtos.ChunkInfo chunk: chunks) {
+      addChunks(blockID, new ChunkMerkleTreeWriter(chunk, healthy));
+    }
+  }
+
+

Review Comment:
   nit: extra line
   ```suggestion
   ```



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/checksum/ContainerMerkleTreeWriter.java:
##########
@@ -49,21 +49,67 @@ public class ContainerMerkleTreeWriter {
   public static final Supplier<ChecksumByteBuffer> CHECKSUM_BUFFER_SUPPLIER = 
ChecksumByteBufferFactory::crc32CImpl;
 
   /**
-   * Constructs an empty Container merkle tree object.
+   * Constructs a writer for an initially empty container merkle tree.
    */
   public ContainerMerkleTreeWriter() {
     id2Block = new TreeMap<>();
   }
 
+  /**
+   * Constructs a writer for a container merkle tree which initially contains 
all the information from the specified
+   * proto.
+   */
+  public ContainerMerkleTreeWriter(ContainerProtos.ContainerMerkleTree 
fromTree) {
+    id2Block = new TreeMap<>();
+    for (ContainerProtos.BlockMerkleTree blockTree: 
fromTree.getBlockMerkleTreeList()) {
+      long blockID = blockTree.getBlockID();
+      addBlock(blockID);
+      for (ContainerProtos.ChunkMerkleTree chunkTree: 
blockTree.getChunkMerkleTreeList()) {
+        addChunks(blockID, chunkTree);
+      }
+    }
+  }
+
   /**
    * Adds chunks to a block in the tree. The block entry will be created if it 
is the first time adding chunks to it.
    * If the block entry already exists, the chunks will be added to the 
existing chunks for that block.
    *
    * @param blockID The ID of the block that these chunks belong to.
+   * @param healthy True if there were no errors detected with these chunks. 
False indicates that all the chunks
+   *                being added had errors.
    * @param chunks A list of chunks to add to this block. The chunks will be 
sorted internally by their offset.
    */
-  public void addChunks(long blockID, Collection<ContainerProtos.ChunkInfo> 
chunks) {
-    id2Block.computeIfAbsent(blockID, 
BlockMerkleTreeWriter::new).addChunks(chunks);
+  public void addChunks(long blockID, boolean healthy, 
Collection<ContainerProtos.ChunkInfo> chunks) {
+    for (ContainerProtos.ChunkInfo chunk: chunks) {
+      addChunks(blockID, healthy, chunk);
+    }
+  }
+
+  public void addChunks(long blockID, boolean healthy, 
ContainerProtos.ChunkInfo... chunks) {
+    for (ContainerProtos.ChunkInfo chunk: chunks) {
+      addChunks(blockID, new ChunkMerkleTreeWriter(chunk, healthy));
+    }
+  }
+
+
+  public void addChunks(long blockID, ContainerProtos.ChunkMerkleTree... 
chunks) {
+    for (ContainerProtos.ChunkMerkleTree chunkTree: chunks) {
+      addChunks(blockID, new ChunkMerkleTreeWriter(chunkTree));
+    }
+  }
+
+  private void addChunks(long blockID, ChunkMerkleTreeWriter chunkWriter) {
+    id2Block.computeIfAbsent(blockID, 
BlockMerkleTreeWriter::new).addChunks(chunkWriter);
+  }
+
+  /**
+   * Adds an empty block to the tree. This method is not a pre-requisite to 
{@code addChunks}.
+   * If the block entry already exists, it will not be modified.
+   *
+   * @param blockID The ID of the empty block to add to the tree
+   */
+  public void addBlock(long blockID) {

Review Comment:
   This `addBlock` calls `addChunks(long blockID, boolean healthy, 
ContainerProtos.ChunkInfo... chunks)`. This only adds the block to `id2Block` 
if there are any chunks. If no chunks are there this function does nothing. Is 
this something modified for #7490 ?



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java:
##########
@@ -645,6 +646,31 @@ public void createContainerMerkleTree(Container container) 
{
     }
   }
 
+  /**
+   * Write the merkle tree for this container using the existing checksum 
metadata only. The data is not read or
+   * validated by this method, so it is expected to run quickly.
+   *
+   * If a checksum file already exists on the disk, this method will do 
nothing. The existing file would have either
+   * been made from the metadata or data itself so there is no need to 
recreate it from the metadata.
+   *
+   * TODO: This method should be changed to private after HDDS-10374 is merged.
+   *
+   * @param container The container which will have a tree generated.
+   */
+  public void createContainerMerkleTreeFromMetadata(Container container) {

Review Comment:
   Can we remove the above function `createContainerMerkleTree`? It is a 
duplicate.



##########
hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java:
##########
@@ -1425,7 +1451,6 @@ public void markContainerUnhealthy(Container container, 
ScanResult reason)
     } finally {
       container.writeUnlock();
     }
-    createContainerMerkleTree(container);

Review Comment:
   Since it's marked unhealthy, do we want the scanner to create the Merkle 
tree, rather than creating it from the metadata?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@ozone.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@ozone.apache.org
For additional commands, e-mail: issues-h...@ozone.apache.org

Reply via email to