apurtell commented on code in PR #2540:
URL: https://github.com/apache/phoenix/pull/2540#discussion_r3500554618


##########
phoenix-core-server/src/main/java/org/apache/phoenix/replication/reader/ReplicationLogProcessor.java:
##########
@@ -246,21 +246,19 @@ public void processLogFile(FileSystem fs, Path filePath) 
throws IOException {
 
       for (LogFile.Record record : logFileReader) {
         final TableName tableName = 
TableName.valueOf(record.getHBaseTableName());
-        final Mutation mutation = record.getMutation();
-
-        tableToMutationsMap.computeIfAbsent(tableName, k -> new 
ArrayList<>()).add(mutation);
-
-        // Increment current batch size and current batch size bytes
-        currentBatchSize++;
-        currentBatchSizeBytes += mutation.heapSize();
-
-        // Process when we reach either the batch count or size limit
-        if (currentBatchSize >= getBatchSize() || currentBatchSizeBytes >= 
getBatchSizeBytes()) {
-          processReplicationLogBatch(tableToMutationsMap);
-          totalProcessed += currentBatchSize;
-          tableToMutationsMap.clear();
-          currentBatchSize = 0;
-          currentBatchSizeBytes = 0;
+        for (Mutation mutation : record.getMutations()) {
+          tableToMutationsMap.computeIfAbsent(tableName, k -> new 
ArrayList<>()).add(mutation);
+          currentBatchSize++;
+          currentBatchSizeBytes += mutation.heapSize();
+
+          // Process when we reach either the batch count or size limit

Review Comment:
   Before this change a record was always a single Mutation, so batches always 
split between records. Now a single record's mutations can be split across two 
processReplicationLogBatch invocations. I think it's fine but future 
maintainers cannot assume a certain atomicity here.



##########
phoenix-core-server/src/main/java/org/apache/phoenix/replication/log/LogFileCodec.java:
##########
@@ -26,55 +26,56 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.KeyValue;
-import org.apache.hadoop.hbase.client.Delete;
-import org.apache.hadoop.hbase.client.Mutation;
-import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.io.ByteBuffInputStream;
 import org.apache.hadoop.hbase.nio.ByteBuff;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.io.WritableUtils;
 
 /**
- * Default Codec for encoding and decoding ReplicationLog Records within a 
block buffer. This
- * implementation uses standard Java DataInput/DataOutput for serialization. 
Record Format within a
- * block:
+ * Default Codec for encoding and decoding ReplicationLog Records within a 
block buffer. The on-disk

Review Comment:
   This is the most interesting change (to me). I suppose it's of a piece with 
the evolution of HBase WAL with WALEdit to group cells and on the RPC side 
"cell blocks" instead of individually described cells in the IDL. 
   
   We may want to restructure the ascii art here further
   
   ```text
   RECORD LENGTH (vint)
   RECORD HEADER
     Table name length (vint)
     Table name bytes
     Commit id (vlong)
   ATTRIBUTES COUNT (vint)            -- NEW: record-level attribute map
   PER-ATTRIBUTE (repeated):
     Key length (vint)
     Key bytes (UTF-8)
     Value length (vint)
     Value bytes
   CELL COUNT (vint)
   PER-CELL (repeated):
     Row length (vint)                -- row written on EVERY cell
     Row bytes
     Family length (vint)             -- family written on EVERY cell
     Family bytes
     Qualifier length (vint)
     Qualifier bytes
     Cell timestamp (long, 8 bytes)
     Cell type byte (1 byte)
     Value length (vint)
     Value bytes
   ```



##########
phoenix-core/src/test/java/org/apache/phoenix/replication/ReplicationLogGroupTest.java:
##########
@@ -1429,59 +1456,15 @@ public void testRetryPicksUpStagedWriter() throws 
Exception {
     assertTrue("Should be using new writer", newWriter != initialWriter);
 
     // Old writer: received the append only
-    verify(initialWriter, times(1)).append(eq(tableName), eq(commitId), 
eq(put));
+    verify(initialWriter, times(1)).append(eq(tableName), eq(commitId),
+      eq(LogFileTestUtil.cellsOf(put)));
 
     // New writer: received replayed append + successful sync
-    verify(newWriter, times(1)).append(eq(tableName), eq(commitId), eq(put));
+    verify(newWriter, times(1)).append(eq(tableName), eq(commitId),
+      eq(LogFileTestUtil.cellsOf(put)));
     verify(newWriter, times(1)).sync();
   }
 
-  /**
-   * Tests the idle-then-lease-recovery scenario: after a sync clears 
currentBatch, the system goes
-   * idle. A rotation tick stages a pending writer. The reader performs HDFS 
lease recovery,
-   * breaking the old writer's stream. When events resume, apply() drains the 
healthy staged writer
-   * before the action — the broken writer is never touched. No replay needed 
(empty batch).
-   */
-  @Test
-  public void testIdleLeaseRecoveryDrainsStagedWriter() throws Exception {

Review Comment:
   I think this test is a real concurrency concern. After a sync clears 
`currentBatch`, the system goes idle, a rotation tick stages a pending writer, 
and the reader performs HDFS lease recovery, invalidating the old writer's 
outputstream. When events resume we need to ensure `apply()` drains to the new 
and healthy writer before the action and should ensure the broken writer is 
never touched.
   
   The body of this test only needs some simple updates (any(Mutation.class) → 
any(List.class), eq(put) → eq(LogFileTestUtil.cellsOf(put))) Let's restore and 
migrate it.



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to