Ver código fonte

ZOOKEEPER-4864: Fix bad format when dump MultiTxn in TxnLogToolkit (#2192)

Decode Txn to record and format the output with the record for better format.
Xin Luo 6 meses atrás
pai
commit
b99714543d

+ 46 - 2
zookeeper-server/src/main/java/org/apache/zookeeper/server/persistence/TxnLogToolkit.java

@@ -49,14 +49,18 @@ import org.apache.jute.BinaryInputArchive;
 import org.apache.jute.BinaryOutputArchive;
 import org.apache.jute.Record;
 import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.server.ByteBufferInputStream;
 import org.apache.zookeeper.server.ExitCode;
 import org.apache.zookeeper.server.Request;
 import org.apache.zookeeper.server.TxnLogEntry;
 import org.apache.zookeeper.server.util.LogChopper;
 import org.apache.zookeeper.server.util.SerializeUtils;
+import org.apache.zookeeper.txn.CheckVersionTxn;
 import org.apache.zookeeper.txn.CreateContainerTxn;
 import org.apache.zookeeper.txn.CreateTTLTxn;
 import org.apache.zookeeper.txn.CreateTxn;
+import org.apache.zookeeper.txn.DeleteTxn;
+import org.apache.zookeeper.txn.ErrorTxn;
 import org.apache.zookeeper.txn.MultiTxn;
 import org.apache.zookeeper.txn.SetDataTxn;
 import org.apache.zookeeper.txn.Txn;
@@ -315,7 +319,7 @@ public class TxnLogToolkit implements Closeable {
      * @return the formatted string
      */
     // @VisibleForTesting
-    static String getFormattedTxnStr(Record txn) {
+    static String getFormattedTxnStr(Record txn) throws IOException {
         StringBuilder txnData = new StringBuilder();
         if (txn == null) {
             return txnData.toString();
@@ -338,6 +342,12 @@ public class TxnLogToolkit implements Closeable {
             txnData.append(createTTLTxn.getPath() + "," + checkNullToEmpty(createTTLTxn.getData()))
                    .append("," + createTTLTxn.getAcl() + "," + createTTLTxn.getParentCVersion())
                    .append("," + createTTLTxn.getTtl());
+        } else if (txn instanceof DeleteTxn) {
+            DeleteTxn deleteTxn = ((DeleteTxn) txn);
+            txnData.append(deleteTxn.getPath());
+        } else if (txn instanceof CheckVersionTxn) {
+            CheckVersionTxn checkVersionTxn = ((CheckVersionTxn) txn);
+            txnData.append(checkVersionTxn.getPath()).append(",").append(checkVersionTxn.getVersion());
         } else if (txn instanceof MultiTxn) {
             MultiTxn multiTxn = ((MultiTxn) txn);
             List<Txn> txnList = multiTxn.getTxns();
@@ -351,7 +361,7 @@ public class TxnLogToolkit implements Closeable {
                 if (t.getType() == ZooDefs.OpCode.error) {
                     txnData.append(ByteBuffer.wrap(t.getData()).getInt());
                 } else {
-                    txnData.append(checkNullToEmpty(t.getData()));
+                    txnData.append(getFormattedTxnStr(deserializeSubTxn(t)));
                 }
             }
         } else {
@@ -361,6 +371,40 @@ public class TxnLogToolkit implements Closeable {
         return txnData.toString();
     }
 
+    private static Record deserializeSubTxn(Txn txn) throws IOException {
+        Record record;
+        switch (txn.getType()) {
+            case ZooDefs.OpCode.create:
+            case ZooDefs.OpCode.create2:
+                record = new CreateTxn();
+                break;
+            case ZooDefs.OpCode.createTTL:
+                record = new CreateTTLTxn();
+                break;
+            case ZooDefs.OpCode.createContainer:
+                record = new CreateContainerTxn();
+                break;
+            case ZooDefs.OpCode.delete:
+            case ZooDefs.OpCode.deleteContainer:
+                record = new DeleteTxn();
+                break;
+            case ZooDefs.OpCode.setData:
+                record = new SetDataTxn();
+                break;
+            case ZooDefs.OpCode.error:
+                record = new ErrorTxn();
+                break;
+            case ZooDefs.OpCode.check:
+                record = new CheckVersionTxn();
+                break;
+            default:
+                throw new IOException("Unsupported Txn with type=" + txn.getType());
+        }
+        ByteBuffer bb = ByteBuffer.wrap(txn.getData());
+        ByteBufferInputStream.byteBuffer2Record(bb, record);
+        return record;
+    }
+
     private static String checkNullToEmpty(byte[] data) {
         if (data == null || data.length == 0) {
             return "";

+ 31 - 18
zookeeper-server/src/test/java/org/apache/zookeeper/server/persistence/TxnLogToolkitTest.java

@@ -30,6 +30,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Scanner;
@@ -37,10 +38,18 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.io.FileUtils;
 import org.apache.jute.BinaryOutputArchive;
+import org.apache.jute.Record;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
 import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.txn.CheckVersionTxn;
+import org.apache.zookeeper.txn.CreateContainerTxn;
+import org.apache.zookeeper.txn.CreateTTLTxn;
+import org.apache.zookeeper.txn.CreateTxn;
+import org.apache.zookeeper.txn.DeleteTxn;
 import org.apache.zookeeper.txn.ErrorTxn;
 import org.apache.zookeeper.txn.MultiTxn;
+import org.apache.zookeeper.txn.SetDataTxn;
 import org.apache.zookeeper.txn.Txn;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -95,27 +104,31 @@ public class TxnLogToolkitTest {
 
     @Test
     public void testMultiTxnDecode() throws IOException {
-        //MultiTxn with four ops, and the first op error.
+        // MultiTxn with multi ops including errors
         List<Txn> txns = new ArrayList<>();
-        int type = -1;
-        for (int i = 0; i < 4; i++) {
-            ErrorTxn txn;
-            if (i == 0) {
-                txn = new ErrorTxn(KeeperException.Code.NONODE.intValue());
-            } else {
-                txn = new ErrorTxn(KeeperException.Code.RUNTIMEINCONSISTENCY.intValue());
-            }
-            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
-                BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
-                txn.serialize(boa, "request");
-                ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
-                txns.add(new Txn(type, bb.array()));
-            }
-        }
+        txns.add(newSubTxn(ZooDefs.OpCode.error, new ErrorTxn(KeeperException.Code.NONODE.intValue())));
+        txns.add(newSubTxn(ZooDefs.OpCode.error, new ErrorTxn(KeeperException.Code.RUNTIMEINCONSISTENCY.intValue())));
+        txns.add(newSubTxn(ZooDefs.OpCode.create, new CreateTxn("/test", "test-data".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, true, 1)));
+        txns.add(newSubTxn(ZooDefs.OpCode.createContainer, new CreateContainerTxn("/test_container", "test-data".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, 2)));
+        txns.add(newSubTxn(ZooDefs.OpCode.createTTL, new CreateTTLTxn("/test_container", "test-data".getBytes(StandardCharsets.UTF_8), ZooDefs.Ids.OPEN_ACL_UNSAFE, 2, 20)));
+        txns.add(newSubTxn(ZooDefs.OpCode.setData, new SetDataTxn("/test_set_data", "test-data".getBytes(StandardCharsets.UTF_8), 4)));
+        txns.add(newSubTxn(ZooDefs.OpCode.delete, new DeleteTxn("/test_delete")));
+        txns.add(newSubTxn(ZooDefs.OpCode.check, new CheckVersionTxn("/test_check_version", 5)));
         MultiTxn multiTxn = new MultiTxn(txns);
-
         String formattedTxnStr = TxnLogToolkit.getFormattedTxnStr(multiTxn);
-        assertEquals("error:-101;error:-2;error:-2;error:-2", formattedTxnStr);
+        assertEquals("error:-101;error:-2;create:/test,test-data,[31,s{'world,'anyone}\n"
+                    + "],true,1;createContainer:/test_container,test-data,[31,s{'world,'anyone}\n"
+                    + "],2;createTTL:/test_container,test-data,[31,s{'world,'anyone}\n"
+                    + "],2,20;setData:/test_set_data,test-data,4;delete:/test_delete;check:/test_check_version,5", formattedTxnStr);
+    }
+
+    private static Txn newSubTxn(int type, Record record) throws IOException {
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+            BinaryOutputArchive boa = BinaryOutputArchive.getArchive(baos);
+            record.serialize(boa, "request");
+            ByteBuffer bb = ByteBuffer.wrap(baos.toByteArray());
+            return new Txn(type, bb.array());
+        }
     }
 
     @Test