Merge pull request #1516 from shenhui0509/sync_pipeline

[ISSUE #1515] SYNC_MASTER could be change into pipeline manner
This commit is contained in:
Heng Du
2020-02-28 18:22:06 +08:00
committed by GitHub
31 changed files with 1086 additions and 220 deletions
@@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.test.client.rmq;
import org.apache.log4j.Logger;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
import org.apache.rocketmq.test.sendresult.ResultWrapper;
public class RMQTransactionalProducer extends AbstractMQProducer {
private static Logger logger = Logger.getLogger(RMQTransactionalProducer.class);
private TransactionMQProducer producer = null;
private String nsAddr = null;
public RMQTransactionalProducer(String nsAddr, String topic, TransactionListener transactionListener) {
this(nsAddr, topic, false, transactionListener);
}
public RMQTransactionalProducer(String nsAddr, String topic, boolean useTLS, TransactionListener transactionListener) {
super(topic);
this.nsAddr = nsAddr;
create(useTLS, transactionListener);
start();
}
protected void create(boolean useTLS, TransactionListener transactionListener) {
producer = new TransactionMQProducer();
producer.setProducerGroup(getProducerGroupName());
producer.setInstanceName(getProducerInstanceName());
producer.setTransactionListener(transactionListener);
producer.setUseTLS(useTLS);
if (nsAddr != null) {
producer.setNamesrvAddr(nsAddr);
}
}
public void start() {
try {
producer.start();
super.setStartSuccess(true);
} catch (MQClientException e) {
super.setStartSuccess(false);
logger.error(e);
e.printStackTrace();
}
}
@Override
public ResultWrapper send(Object msg, Object arg) {
boolean commitMsg = ((Pair<Boolean, LocalTransactionState>) arg).getObject2() == LocalTransactionState.COMMIT_MESSAGE;
org.apache.rocketmq.client.producer.SendResult metaqResult = null;
Message message = (Message) msg;
try {
long start = System.currentTimeMillis();
metaqResult = producer.sendMessageInTransaction(message, arg);
this.msgRTs.addData(System.currentTimeMillis() - start);
if (isDebug) {
logger.info(metaqResult);
}
sendResult.setMsgId(metaqResult.getMsgId());
sendResult.setSendResult(true);
sendResult.setBrokerIp(metaqResult.getMessageQueue().getBrokerName());
if (commitMsg) {
msgBodys.addData(new String(message.getBody()));
}
originMsgs.addData(msg);
originMsgIndex.put(new String(message.getBody()), metaqResult);
} catch (MQClientException e) {
if (isDebug) {
e.printStackTrace();
}
sendResult.setSendResult(false);
sendResult.setSendException(e);
errorMsgs.addData(msg);
}
return sendResult;
}
@Override
public void shutdown() {
producer.shutdown();
}
}
@@ -22,12 +22,14 @@ import java.util.List;
import org.apache.log4j.Logger;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.namesrv.NamesrvController;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.test.client.rmq.RMQAsyncSendProducer;
import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
import org.apache.rocketmq.test.client.rmq.RMQTransactionalProducer;
import org.apache.rocketmq.test.clientinterface.AbstractMQConsumer;
import org.apache.rocketmq.test.clientinterface.AbstractMQProducer;
import org.apache.rocketmq.test.factory.ConsumerFactory;
@@ -96,6 +98,15 @@ public class BaseConf {
return producer;
}
public static RMQTransactionalProducer getTransactionalProducer(String nsAddr, String topic, TransactionListener transactionListener) {
RMQTransactionalProducer producer = new RMQTransactionalProducer(nsAddr, topic, false, transactionListener);
if (debug) {
producer.setDebug();
}
mqClients.add(producer);
return producer;
}
public static RMQNormalProducer getProducer(String nsAddr, String topic, String producerGoup,
String instanceName) {
RMQNormalProducer producer = new RMQNormalProducer(nsAddr, topic, producerGoup,
@@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.test.client.producer.transaction;
import org.apache.log4j.Logger;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.test.base.BaseConf;
import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
import org.apache.rocketmq.test.client.rmq.RMQTransactionalProducer;
import org.apache.rocketmq.test.factory.MQMessageFactory;
import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListener;
import org.apache.rocketmq.test.util.MQWait;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static com.google.common.truth.Truth.assertThat;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
public class TransactionalMsgIT extends BaseConf {
private static Logger logger = Logger.getLogger(TransactionalMsgIT.class);
private RMQTransactionalProducer producer = null;
private RMQNormalConsumer consumer = null;
private String topic = null;
@Before
public void setUp() {
topic = initTopic();
logger.info(String.format("use topic: %s;", topic));
producer = getTransactionalProducer(nsAddr, topic, new TransactionListenerImpl());
consumer = getConsumer(nsAddr, topic, "*", new RMQNormalListener());
}
@After
public void tearDown() {
super.shutdown();
}
@Test
public void testMessageVisibility() throws Exception {
Thread.sleep(3000);
int msgSize = 120;
List<Object> msgs = MQMessageFactory.getMsg(topic, msgSize);
for (int i = 0; i < msgSize; i++) {
producer.send(msgs.get(i), getTransactionHandle(i));
}
boolean recvAll = MQWait.waitConsumeAll(consumeTime, producer.getAllMsgBody(), consumer.getListener());
assertThat(recvAll).isEqualTo(true);
}
static Pair<Boolean, LocalTransactionState> getTransactionHandle(int msgIndex) {
switch (msgIndex % 5) {
case 0:
//commit immediately
return new Pair<>(true, LocalTransactionState.COMMIT_MESSAGE);
case 1:
//rollback immediately
return new Pair<>(true, LocalTransactionState.ROLLBACK_MESSAGE);
case 2:
//commit in check
return new Pair<>(false, LocalTransactionState.COMMIT_MESSAGE);
case 3:
//rollback in check
return new Pair<>(false, LocalTransactionState.ROLLBACK_MESSAGE);
case 4:
default:
return new Pair<>(false, LocalTransactionState.UNKNOW);
}
}
static private class TransactionListenerImpl implements TransactionListener {
ConcurrentHashMap<String, LocalTransactionState> checkStatus = new ConcurrentHashMap<>();
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
Pair<Boolean, LocalTransactionState> transactionHandle = (Pair<Boolean,LocalTransactionState>) arg;
if (transactionHandle.getObject1()) {
return transactionHandle.getObject2();
} else {
checkStatus.put(msg.getTransactionId(), transactionHandle.getObject2());
return LocalTransactionState.UNKNOW;
}
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
LocalTransactionState state = checkStatus.get(msg.getTransactionId());
if (state == null) {
return LocalTransactionState.UNKNOW;
} else {
return state;
}
}
}
}