Skip to content

Commit

Permalink
ZOOKEEPER-4864: Fix bad format when dump MultiTxn in TxnLogToolkit (#…
Browse files Browse the repository at this point in the history
…2192)

Decode Txn to record and format the output with the record for better format.
  • Loading branch information
luoxiner authored Oct 15, 2024
1 parent 935b5f4 commit b997145
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,18 @@
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;
Expand Down Expand Up @@ -315,7 +319,7 @@ private void printTxn(byte[] bytes, String prefix) throws IOException {
* @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();
Expand All @@ -338,6 +342,12 @@ static String getFormattedTxnStr(Record txn) {
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();
Expand All @@ -351,7 +361,7 @@ static String getFormattedTxnStr(Record txn) {
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 {
Expand All @@ -361,6 +371,40 @@ static String getFormattedTxnStr(Record txn) {
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 "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,26 @@
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;
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;
Expand Down Expand Up @@ -95,27 +104,31 @@ public void testInitMissingFile() throws FileNotFoundException, TxnLogToolkit.Tx

@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
Expand Down

0 comments on commit b997145

Please sign in to comment.