Преглед изворни кода

ZOOKEEPER-4607. Fix decode problem when sub tnx type is error (#1915)

Co-authored-by: tison <wander4096@gmail.com>
Yan Zhao пре 1 година
родитељ
комит
6e746f8e88

+ 15 - 6
zookeeper-server/src/main/java/org/apache/zookeeper/server/persistence/TxnLogToolkit.java

@@ -30,6 +30,7 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.text.DateFormat;
 import java.util.Date;
@@ -47,6 +48,7 @@ import org.apache.commons.cli.ParseException;
 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.ExitCode;
 import org.apache.zookeeper.server.Request;
 import org.apache.zookeeper.server.TxnLogEntry;
@@ -307,11 +309,13 @@ public class TxnLogToolkit implements Closeable {
     }
 
     /**
-     * get the formatted string from the txn.
+     * Get the formatted string from the txn.
+     *
      * @param txn transaction log data
      * @return the formatted string
      */
-    private static String getFormattedTxnStr(Record txn) throws IOException {
+    // @VisibleForTesting
+    static String getFormattedTxnStr(Record txn) {
         StringBuilder txnData = new StringBuilder();
         if (txn == null) {
             return txnData.toString();
@@ -340,19 +344,24 @@ public class TxnLogToolkit implements Closeable {
             for (int i = 0; i < txnList.size(); i++) {
                 Txn t = txnList.get(i);
                 if (i == 0) {
-                    txnData.append(Request.op2String(t.getType()) + ":" + checkNullToEmpty(t.getData()));
+                    txnData.append(Request.op2String(t.getType())).append(":");
                 } else {
-                    txnData.append(";" + Request.op2String(t.getType()) + ":" + checkNullToEmpty(t.getData()));
+                    txnData.append(";").append(Request.op2String(t.getType())).append(":");
+                }
+                if (t.getType() == ZooDefs.OpCode.error) {
+                    txnData.append(ByteBuffer.wrap(t.getData()).getInt());
+                } else {
+                    txnData.append(checkNullToEmpty(t.getData()));
                 }
             }
         } else {
-            txnData.append(txn.toString());
+            txnData.append(txn);
         }
 
         return txnData.toString();
     }
 
-    private static String checkNullToEmpty(byte[] data) throws IOException {
+    private static String checkNullToEmpty(byte[] data) {
         if (data == null || data.length == 0) {
             return "";
         }

+ 34 - 0
zookeeper-server/src/test/java/org/apache/zookeeper/server/persistence/TxnLogToolkitTest.java

@@ -21,6 +21,7 @@ package org.apache.zookeeper.server.persistence;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.IsNot.not;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import java.io.ByteArrayOutputStream;
@@ -28,11 +29,19 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Scanner;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.io.FileUtils;
+import org.apache.jute.BinaryOutputArchive;
+import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.txn.ErrorTxn;
+import org.apache.zookeeper.txn.MultiTxn;
+import org.apache.zookeeper.txn.Txn;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -84,6 +93,31 @@ public class TxnLogToolkitTest {
         });
     }
 
+    @Test
+    public void testMultiTxnDecode() throws IOException {
+        //MultiTxn with four ops, and the first op error.
+        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()));
+            }
+        }
+        MultiTxn multiTxn = new MultiTxn(txns);
+
+        String formattedTxnStr = TxnLogToolkit.getFormattedTxnStr(multiTxn);
+        assertEquals("error:-101;error:-2;error:-2;error:-2", formattedTxnStr);
+    }
+
     @Test
     public void testInitWithRecoveryFileExists() {
         assertThrows(TxnLogToolkit.TxnLogToolkitException.class, () -> {