You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by do...@apache.org on 2017/06/08 07:54:22 UTC
[01/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-172]log
improvement for rocketmq client closes apache/incubator-rocketmq#90 [Forced
Update!]
Repository: incubator-rocketmq
Updated Branches:
refs/heads/release-4.1.0-incubating 5c16892e5 -> 10933cc0a (forced update)
[ROCKETMQ-172]log improvement for rocketmq client closes apache/incubator-rocketmq#90
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/c183e0d4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/c183e0d4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/c183e0d4
Branch: refs/heads/release-4.1.0-incubating
Commit: c183e0d4026770a68bedce02507446431cdf6265
Parents: 7bcb3b3
Author: Jaskey <li...@gmail.com>
Authored: Mon Apr 17 19:28:26 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Mon Apr 17 19:28:26 2017 +0800
----------------------------------------------------------------------
.../java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java | 6 +++---
.../apache/rocketmq/client/impl/factory/MQClientInstance.java | 2 +-
.../apache/rocketmq/remoting/netty/NettyRemotingClient.java | 2 ++
3 files changed, 6 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c183e0d4/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index 6119e24..ff25334 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -593,12 +593,12 @@ public class MQClientAPIImpl {
}
} else {
if (!responseFuture.isSendRequestOK()) {
- pullCallback.onException(new MQClientException("send request failed", responseFuture.getCause()));
+ pullCallback.onException(new MQClientException("send request failed to " + addr + ". Request: " + request, responseFuture.getCause()));
} else if (responseFuture.isTimeout()) {
- pullCallback.onException(new MQClientException("wait response timeout " + responseFuture.getTimeoutMillis() + "ms",
+ pullCallback.onException(new MQClientException("wait response from " + addr + " timeout :" + responseFuture.getTimeoutMillis() + "ms" + ". Request: " + request,
responseFuture.getCause()));
} else {
- pullCallback.onException(new MQClientException("unknow reseaon", responseFuture.getCause()));
+ pullCallback.onException(new MQClientException("unknown reason. addr: " + addr + ", timeoutMillis: " + timeoutMillis + ". Request: " + request, responseFuture.getCause()));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c183e0d4/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 11266c4..d7e02fe 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -596,7 +596,7 @@ public class MQClientInstance {
}
}
}
- log.info("topicRouteTable.put TopicRouteData[{}]", cloneTopicRouteData);
+ log.info("topicRouteTable.put. Topic = {}, TopicRouteData[{}]", topic, cloneTopicRouteData);
this.topicRouteTable.put(topic, cloneTopicRouteData);
return true;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c183e0d4/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
index 85f9244..26088aa 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
@@ -321,6 +321,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
if (update) {
Collections.shuffle(addrs);
+ log.info("name server address updated. NEW : {} , OLD: {}",addrs,old);
this.namesrvAddrList.set(addrs);
}
}
@@ -398,6 +399,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
String newAddr = addrList.get(index);
this.namesrvAddrChoosed.set(newAddr);
+ log.info("new name server is chosen. OLD: {} , NEW: {}. namesrvIndex = {}", addr, newAddr, namesrvIndex);
Channel channelNew = this.createChannel(newAddr);
if (channelNew != null)
return channelNew;
[12/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-179] Fix
errors of IT test cases closes apache/incubator-rocketmq#94
Posted by do...@apache.org.
[ROCKETMQ-179] Fix errors of IT test cases closes apache/incubator-rocketmq#94
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/6a9628b3
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/6a9628b3
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/6a9628b3
Branch: refs/heads/release-4.1.0-incubating
Commit: 6a9628b3c3e6835e37baf7b58ad9300364d4d384
Parents: 58f1574
Author: vsair <li...@gmail.com>
Authored: Fri Apr 21 18:21:35 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri Apr 21 18:21:35 2017 +0800
----------------------------------------------------------------------
pom.xml | 4 --
.../test/clientinterface/MQCollector.java | 20 +++++++---
.../rmq/concurrent/RMQNormalListner.java | 4 +-
.../org/apache/rocketmq/test/util/MQAdmin.java | 1 -
.../rocketmq/test/base/IntegrationTestBase.java | 39 ++++++++++++++------
.../tag/TagMessageWithSameGroupConsumerIT.java | 10 ++---
.../async/AsyncSendWithMessageQueueIT.java | 5 +--
.../AsyncSendWithMessageQueueSelectorIT.java | 1 -
.../rocketmq/test/delay/NormalMsgDelayIT.java | 3 +-
9 files changed, 53 insertions(+), 34 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index feb8b14..6fd59ac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -461,10 +461,6 @@
<argLine>@{failsafeArgLine}</argLine>
<excludes>
<exclude>**/NormalMsgDelayIT.java</exclude>
- <exclude>**/BroadCastNormalMsgNotRecvIT.java</exclude>
- <exclude>**/TagMessageWithSameGroupConsumerIT.java</exclude>
- <exclude>**/AsyncSendWithMessageQueueSelectorIT.java</exclude>
- <exclude>**/AsyncSendWithMessageQueueIT.java</exclude>
</excludes>
</configuration>
<executions>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
index 42d4b62..7ccf92a 100644
--- a/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
+++ b/test/src/main/java/org/apache/rocketmq/test/clientinterface/MQCollector.java
@@ -91,11 +91,21 @@ public abstract class MQCollector {
}
public void clearMsg() {
- msgBodys.resetData();
- originMsgs.resetData();
- errorMsgs.resetData();
- originMsgIndex.clear();
- msgRTs.resetData();
+ if (msgBodys != null) {
+ msgBodys.resetData();
+ }
+ if (originMsgs != null) {
+ originMsgs.resetData();
+ }
+ if (originMsgs != null) {
+ errorMsgs.resetData();
+ }
+ if (originMsgIndex != null) {
+ originMsgIndex.clear();
+ }
+ if (msgRTs != null) {
+ msgRTs.resetData();
+ }
}
public void lockCollectors() {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
index 0d40881..471fb48 100644
--- a/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/rmq/concurrent/RMQNormalListner.java
@@ -63,7 +63,9 @@ public class RMQNormalListner extends AbstractListener implements MessageListene
msgBodys.addData(new String(msg.getBody()));
originMsgs.addData(msg);
- originMsgIndex.put(new String(msg.getBody()), msg);
+ if (originMsgIndex != null) {
+ originMsgIndex.put(new String(msg.getBody()), msg);
+ }
}
return consumeStatus;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java b/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
index 680780a..bd151d0 100644
--- a/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
+++ b/test/src/main/java/org/apache/rocketmq/test/util/MQAdmin.java
@@ -45,7 +45,6 @@ public class MQAdmin {
mqAdminExt.start();
mqAdminExt.createTopic(clusterName, topic, queueNum);
} catch (Exception e) {
- e.printStackTrace();
}
long startTime = System.currentTimeMillis();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
index 5329991..9805eba 100644
--- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
+++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
@@ -46,6 +46,8 @@ public class IntegrationTestBase {
protected static final List<BrokerController> BROKER_CONTROLLERS = new ArrayList<>();
protected static final List<NamesrvController> NAMESRV_CONTROLLERS = new ArrayList<>();
protected static int topicCreateTime = 30 * 1000;
+ protected static final int COMMIT_LOG_SIZE = 1024 * 1024 * 256;
+ protected static final int INDEX_NUM = 1000;
protected static Random random = new Random();
@@ -53,18 +55,30 @@ public class IntegrationTestBase {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override public void run() {
- for (NamesrvController namesrvController : NAMESRV_CONTROLLERS) {
- if (namesrvController != null) {
- namesrvController.shutdown();
+ try {
+ for (BrokerController brokerController : BROKER_CONTROLLERS) {
+ if (brokerController != null) {
+ brokerController.shutdown();
+ }
}
- }
- for (BrokerController brokerController : BROKER_CONTROLLERS) {
- if (brokerController != null) {
- brokerController.shutdown();
+
+ // should destroy message store, otherwise could not delete the temp files.
+ for (BrokerController brokerController : BROKER_CONTROLLERS) {
+ if (brokerController != null) {
+ brokerController.getMessageStore().destroy();
+ }
}
- }
- for (File file : TMPE_FILES) {
- deleteFile(file);
+
+ for (NamesrvController namesrvController : NAMESRV_CONTROLLERS) {
+ if (namesrvController != null) {
+ namesrvController.shutdown();
+ }
+ }
+ for (File file : TMPE_FILES) {
+ deleteFile(file);
+ }
+ } catch (Exception e){
+ logger.error("Shutdown error", e);
}
}
});
@@ -75,7 +89,7 @@ public class IntegrationTestBase {
String baseDir = System.getProperty("user.home") + SEP + "unitteststore-" + UUID.randomUUID();
final File file = new File(baseDir);
if (file.exists()) {
- logger.info(String.format("[%s] has already existed, please bake up and remove it for integration tests", baseDir));
+ logger.info(String.format("[%s] has already existed, please back up and remove it for integration tests", baseDir));
System.exit(1);
}
TMPE_FILES.add(file);
@@ -116,6 +130,9 @@ public class IntegrationTestBase {
storeConfig.setStorePathRootDir(baseDir);
storeConfig.setStorePathCommitLog(baseDir + SEP + "commitlog");
storeConfig.setHaListenPort(8000 + random.nextInt(1000));
+ storeConfig.setMapedFileSizeCommitLog(COMMIT_LOG_SIZE);
+ storeConfig.setMaxIndexNum(INDEX_NUM);
+ storeConfig.setMaxHashSlotNum(INDEX_NUM * 4);
nettyServerConfig.setListenPort(10000 + random.nextInt(1000));
BrokerController brokerController = new BrokerController(brokerConfig, nettyServerConfig, nettyClientConfig, storeConfig);
try {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
index 4cf8161..135cbec 100644
--- a/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/tag/TagMessageWithSameGroupConsumerIT.java
@@ -36,6 +36,7 @@ public class TagMessageWithSameGroupConsumerIT extends BaseConf {
private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
private RMQNormalProducer producer = null;
private String topic = null;
+ private String tag = "tag";
@Before
public void setUp() {
@@ -51,13 +52,12 @@ public class TagMessageWithSameGroupConsumerIT extends BaseConf {
@Test
public void testTwoConsumerWithSameGroup() {
- String tag = "jueyin";
int msgSize = 20;
String originMsgDCName = RandomUtils.getStringByUUID();
String msgBodyDCName = RandomUtils.getStringByUUID();
RMQNormalConsumer consumer1 = getConsumer(nsAddr, topic, tag,
new RMQNormalListner(originMsgDCName, msgBodyDCName));
- RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
+ getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
new RMQNormalListner(originMsgDCName, msgBodyDCName));
producer.send(tag, msgSize);
Assert.assertEquals("Not all are sent", msgSize, producer.getAllUndupMsgBody().size());
@@ -70,7 +70,6 @@ public class TagMessageWithSameGroupConsumerIT extends BaseConf {
@Test
public void testConsumerStartWithInterval() {
- String tag = "jueyin";
int msgSize = 100;
String originMsgDCName = RandomUtils.getStringByUUID();
String msgBodyDCName = RandomUtils.getStringByUUID();
@@ -79,7 +78,7 @@ public class TagMessageWithSameGroupConsumerIT extends BaseConf {
new RMQNormalListner(originMsgDCName, msgBodyDCName));
producer.send(tag, msgSize, 100);
TestUtils.waitForMoment(5);
- RMQNormalConsumer consumer2 = getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
+ getConsumer(nsAddr, consumer1.getConsumerGroup(), tag,
new RMQNormalListner(originMsgDCName, msgBodyDCName));
TestUtils.waitForMoment(5);
@@ -90,8 +89,7 @@ public class TagMessageWithSameGroupConsumerIT extends BaseConf {
}
@Test
- public void testConsumerStartTwoAndCrashOnsAfterWhile() {
- String tag = "jueyin";
+ public void testConsumerStartTwoAndCrashOneAfterWhile() {
int msgSize = 100;
String originMsgDCName = RandomUtils.getStringByUUID();
String msgBodyDCName = RandomUtils.getStringByUUID();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
index 53a992c..24a7547 100644
--- a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueIT.java
@@ -33,7 +33,6 @@ import static com.google.common.truth.Truth.assertThat;
public class AsyncSendWithMessageQueueIT extends BaseConf {
private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
- private static boolean sendFail = false;
private RMQAsyncSendProducer producer = null;
private String topic = null;
@@ -57,7 +56,7 @@ public class AsyncSendWithMessageQueueIT extends BaseConf {
MessageQueue mq = new MessageQueue(topic, broker1Name, queueId);
producer.asyncSend(msgSize, mq);
- producer.waitForResponse(5 * 1000);
+ producer.waitForResponse(10 * 1000);
assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
@@ -72,7 +71,7 @@ public class AsyncSendWithMessageQueueIT extends BaseConf {
mq = new MessageQueue(topic, broker2Name, queueId);
producer.asyncSend(msgSize, mq);
- producer.waitForResponse(5 * 1000);
+ producer.waitForResponse(10 * 1000);
assertThat(producer.getSuccessMsgCount()).isEqualTo(msgSize);
consumer.getListner().waitForMessageConsume(producer.getAllMsgBody(), consumeTime);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
index 68c2b0e..843441d 100644
--- a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
@@ -36,7 +36,6 @@ import static com.google.common.truth.Truth.assertThat;
public class AsyncSendWithMessageQueueSelectorIT extends BaseConf {
private static Logger logger = Logger.getLogger(TagMessageWith1ConsumerIT.class);
- private static boolean sendFail = false;
private RMQAsyncSendProducer producer = null;
private String topic = null;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6a9628b3/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java b/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
index 5206dcb..dc5f230 100644
--- a/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/delay/NormalMsgDelayIT.java
@@ -24,7 +24,6 @@ import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
import org.apache.rocketmq.test.factory.MQMessageFactory;
import org.apache.rocketmq.test.listener.rmq.concurrent.RMQDelayListner;
-import org.apache.rocketmq.test.listener.rmq.order.RMQOrderListener;
import org.apache.rocketmq.test.util.VerifyUtils;
import org.junit.After;
import org.junit.Assert;
@@ -43,7 +42,7 @@ public class NormalMsgDelayIT extends DelayConf {
topic = initTopic();
logger.info(String.format("use topic: %s;", topic));
producer = getProducer(nsAddr, topic);
- consumer = getConsumer(nsAddr, topic, "*", new RMQOrderListener());
+ consumer = getConsumer(nsAddr, topic, "*", new RMQDelayListner());
}
@After
[14/50] [abbrv] incubator-rocketmq git commit: Removed unnecessary
semicolon.
Posted by do...@apache.org.
Removed unnecessary semicolon.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/8feb88d1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/8feb88d1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/8feb88d1
Branch: refs/heads/release-4.1.0-incubating
Commit: 8feb88d1481a86793846b38aa69c66ace860694e
Parents: 6609c86
Author: shroman <rs...@yahoo.com>
Authored: Thu May 4 20:07:10 2017 +0900
Committer: shroman <rs...@yahoo.com>
Committed: Thu May 4 20:07:10 2017 +0900
----------------------------------------------------------------------
.../org/apache/rocketmq/filter/expression/UnaryInExpression.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8feb88d1/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
index 7d9083c..a6cf173 100644
--- a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
@@ -58,4 +58,4 @@ abstract public class UnaryInExpression extends UnaryExpression implements Boole
public void setInList(Collection inList) {
this.inList = inList;
}
-};
+}
[46/50] [abbrv] incubator-rocketmq git commit: Release zip too
Posted by do...@apache.org.
Release zip too
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/7374914b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/7374914b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/7374914b
Branch: refs/heads/release-4.1.0-incubating
Commit: 7374914bac077d5de433fe9491d2eb1ed0d38825
Parents: e068ec1
Author: dongeforever <do...@apache.org>
Authored: Tue Jun 6 17:02:15 2017 +0800
Committer: dongeforever <do...@apache.org>
Committed: Tue Jun 6 20:41:41 2017 +0800
----------------------------------------------------------------------
distribution/release.xml | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/7374914b/distribution/release.xml
----------------------------------------------------------------------
diff --git a/distribution/release.xml b/distribution/release.xml
index c67d23e..d87ad5d 100644
--- a/distribution/release.xml
+++ b/distribution/release.xml
@@ -21,6 +21,7 @@
<formats>
<format>dir</format>
<format>tar.gz</format>
+ <format>zip</format>
</formats>
<fileSets>
<fileSet>
[36/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-67]
Consistent Hash allocate strategy closes apache/incubator-rocketmq#67
Posted by do...@apache.org.
[ROCKETMQ-67] Consistent Hash allocate strategy closes apache/incubator-rocketmq#67
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/adae1624
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/adae1624
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/adae1624
Branch: refs/heads/release-4.1.0-incubating
Commit: adae1624d05346cd3632c778a656e4055de6bff3
Parents: c796140
Author: Jaskey <li...@gmail.com>
Authored: Sat May 27 11:42:03 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 11:42:03 2017 +0800
----------------------------------------------------------------------
.../AllocateMessageQueueConsistentHash.java | 124 ++++++++++
.../AllocateMessageQueueConsitentHashTest.java | 243 +++++++++++++++++++
.../consistenthash/ConsistentHashRouter.java | 140 +++++++++++
.../common/consistenthash/HashFunction.java | 24 ++
.../rocketmq/common/consistenthash/Node.java | 28 +++
.../common/consistenthash/VirtualNode.java | 41 ++++
6 files changed, 600 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
new file mode 100644
index 0000000..77198b7
--- /dev/null
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
@@ -0,0 +1,124 @@
+/*
+ * 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.client.consumer.rebalance;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy;
+import org.apache.rocketmq.client.log.ClientLogger;
+import org.apache.rocketmq.common.consistenthash.ConsistentHashRouter;
+import org.apache.rocketmq.common.consistenthash.HashFunction;
+import org.apache.rocketmq.common.consistenthash.Node;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.slf4j.Logger;
+
+/**
+ * Consistent Hashing queue algorithm
+ */
+public class AllocateMessageQueueConsistentHash implements AllocateMessageQueueStrategy {
+ private final Logger log = ClientLogger.getLog();
+
+ private final int virtualNodeCnt;
+ private final HashFunction customHashFunction;
+
+ public AllocateMessageQueueConsistentHash() {
+ this(10);
+ }
+
+ public AllocateMessageQueueConsistentHash(int virtualNodeCnt) {
+ this(virtualNodeCnt,null);
+ }
+
+ public AllocateMessageQueueConsistentHash(int virtualNodeCnt, HashFunction customHashFunction) {
+ if (virtualNodeCnt < 0) {
+ throw new IllegalArgumentException("illegal virtualNodeCnt :" + virtualNodeCnt);
+ }
+ this.virtualNodeCnt = virtualNodeCnt;
+ this.customHashFunction = customHashFunction;
+ }
+
+ @Override
+ public List<MessageQueue> allocate(String consumerGroup, String currentCID, List<MessageQueue> mqAll,
+ List<String> cidAll) {
+
+ if (currentCID == null || currentCID.length() < 1) {
+ throw new IllegalArgumentException("currentCID is empty");
+ }
+ if (mqAll == null || mqAll.isEmpty()) {
+ throw new IllegalArgumentException("mqAll is null or mqAll empty");
+ }
+ if (cidAll == null || cidAll.isEmpty()) {
+ throw new IllegalArgumentException("cidAll is null or cidAll empty");
+ }
+
+ List<MessageQueue> result = new ArrayList<MessageQueue>();
+ if (!cidAll.contains(currentCID)) {
+ log.info("[BUG] ConsumerGroup: {} The consumerId: {} not in cidAll: {}",
+ consumerGroup,
+ currentCID,
+ cidAll);
+ return result;
+ }
+
+
+ Collection<ClientNode> cidNodes = new ArrayList<>();
+ for (String cid : cidAll) {
+ cidNodes.add(new ClientNode(cid));
+ }
+
+ final ConsistentHashRouter<ClientNode> router; //for building hash ring
+ if (customHashFunction != null) {
+ router = new ConsistentHashRouter<>(cidNodes, virtualNodeCnt, customHashFunction);
+ } else {
+ router = new ConsistentHashRouter<>(cidNodes, virtualNodeCnt);
+ }
+
+ List<MessageQueue> results = new ArrayList<>();
+ for (MessageQueue mq : mqAll) {
+ ClientNode clientNode = router.routeNode(mq.toString());
+ if (clientNode != null && currentCID.equals(clientNode.getKey())) {
+ results.add(mq);
+ }
+ }
+
+ return results;
+
+ }
+
+ @Override
+ public String getName() {
+ return "CONSISTENT_HASH";
+ }
+
+
+ private static class ClientNode implements Node {
+ private final String clientID;
+
+ public ClientNode(String clientID) {
+ this.clientID = clientID;
+ }
+
+ @Override
+ public String getKey() {
+ return clientID;
+ }
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java b/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
new file mode 100644
index 0000000..fc7ab9f
--- /dev/null
+++ b/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.client.consumer.rebalance;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
+import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class AllocateMessageQueueConsitentHashTest {
+
+ private String topic;
+ private static final String CID_PREFIX = "CID-";
+
+ @Before
+ public void init() {
+ topic = "topic_test";
+ }
+
+
+
+ public void printMessageQueue(List<MessageQueue> messageQueueList, String name) {
+ if (messageQueueList == null || messageQueueList.size() < 1)
+ return;
+ System.out.println(name + ".......................................start");
+ for (MessageQueue messageQueue : messageQueueList) {
+ System.out.println(messageQueue);
+ }
+ System.out.println(name + ".......................................end");
+ }
+
+ @Test
+ public void testCurrentCIDNotExists() {
+ String currentCID = String.valueOf(Integer.MAX_VALUE);
+ List<String> consumerIdList = createConsumerIdList(2);
+ List<MessageQueue> messageQueueList = createMessageQueueList(6);
+ List<MessageQueue> result = new AllocateMessageQueueConsistentHash().allocate("", currentCID, messageQueueList, consumerIdList);
+ printMessageQueue(result, "testCurrentCIDNotExists");
+ Assert.assertEquals(result.size(), 0);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCurrentCIDIllegalArgument() {
+ List<String> consumerIdList = createConsumerIdList(2);
+ List<MessageQueue> messageQueueList = createMessageQueueList(6);
+ new AllocateMessageQueueConsistentHash().allocate("", "", messageQueueList, consumerIdList);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testMessageQueueIllegalArgument() {
+ String currentCID = "0";
+ List<String> consumerIdList = createConsumerIdList(2);
+ new AllocateMessageQueueConsistentHash().allocate("", currentCID, null, consumerIdList);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConsumerIdIllegalArgument() {
+ String currentCID = "0";
+ List<MessageQueue> messageQueueList = createMessageQueueList(6);
+ new AllocateMessageQueueConsistentHash().allocate("", currentCID, messageQueueList, null);
+ }
+
+ @Test
+ public void testAllocate1() {
+ testAllocate(20,10);
+ }
+
+ @Test
+ public void testAllocate2() {
+ testAllocate(10,20);
+ }
+
+
+ @Test
+ public void testRun100RandomCase(){
+ for(int i=0;i<100;i++){
+ int consumerSize = new Random().nextInt(200)+1;//1-200
+ int queueSize = new Random().nextInt(100)+1;//1-100
+ testAllocate(queueSize,consumerSize);
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+
+ public void testAllocate(int queueSize, int consumerSize) {
+ AllocateMessageQueueStrategy allocateMessageQueueConsistentHash = new AllocateMessageQueueConsistentHash(3);
+
+ List<MessageQueue> mqAll = createMessageQueueList(queueSize);
+ //System.out.println("mqAll:" + mqAll.toString());
+
+ List<String> cidAll = createConsumerIdList(consumerSize);
+ List<MessageQueue> allocatedResAll = new ArrayList<>();
+
+ Map<MessageQueue, String> allocateToAllOrigin = new TreeMap<>();
+ //test allocate all
+ {
+
+ List<String> cidBegin = new ArrayList<>(cidAll);
+
+ //System.out.println("cidAll:" + cidBegin.toString());
+ for (String cid : cidBegin) {
+ List<MessageQueue> rs = allocateMessageQueueConsistentHash.allocate("testConsumerGroup", cid, mqAll, cidBegin);
+ for (MessageQueue mq : rs) {
+ allocateToAllOrigin.put(mq, cid);
+ }
+ allocatedResAll.addAll(rs);
+ //System.out.println("rs[" + cid + "]:" + rs.toString());
+ }
+
+ Assert.assertTrue(
+ verifyAllocateAll(cidBegin,mqAll, allocatedResAll));
+ }
+
+ Map<MessageQueue, String> allocateToAllAfterRemoveOne = new TreeMap<>();
+ List<String> cidAfterRemoveOne = new ArrayList<>(cidAll);
+ //test allocate remove one cid
+ {
+ String removeCID = cidAfterRemoveOne.remove(0);
+ //System.out.println("removing one cid "+removeCID);
+ List<MessageQueue> mqShouldOnlyChanged = new ArrayList<>();
+ Iterator<Map.Entry<MessageQueue, String>> it = allocateToAllOrigin.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<MessageQueue, String> entry = it.next();
+ if (entry.getValue().equals(removeCID)) {
+ mqShouldOnlyChanged.add(entry.getKey());
+ }
+ }
+
+ //System.out.println("cidAll:" + cidAfterRemoveOne.toString());
+ List<MessageQueue> allocatedResAllAfterRemove = new ArrayList<>();
+ for (String cid : cidAfterRemoveOne) {
+ List<MessageQueue> rs = allocateMessageQueueConsistentHash.allocate("testConsumerGroup", cid, mqAll, cidAfterRemoveOne);
+ allocatedResAllAfterRemove.addAll(rs);
+ for (MessageQueue mq : rs) {
+ allocateToAllAfterRemoveOne.put(mq, cid);
+ }
+ //System.out.println("rs[" + cid + "]:" + "[" + rs.size() + "]" + rs.toString());
+ }
+
+ Assert.assertTrue("queueSize"+queueSize+"consumerSize:"+consumerSize+"\nmqAll:"+mqAll+"\nallocatedResAllAfterRemove"+allocatedResAllAfterRemove,
+ verifyAllocateAll(cidAfterRemoveOne, mqAll, allocatedResAllAfterRemove));
+ verifyAfterRemove(allocateToAllOrigin, allocateToAllAfterRemoveOne, removeCID);
+ }
+
+ List<String> cidAfterAdd = new ArrayList<>(cidAfterRemoveOne);
+ //test allocate add one more cid
+ {
+ String newCid = CID_PREFIX+"NEW";
+ //System.out.println("add one more cid "+newCid);
+ cidAfterAdd.add(newCid);
+ List<MessageQueue> mqShouldOnlyChanged = new ArrayList<>();
+ //System.out.println("cidAll:" + cidAfterAdd.toString());
+ List<MessageQueue> allocatedResAllAfterAdd = new ArrayList<>();
+ Map<MessageQueue, String> allocateToAll3 = new TreeMap<>();
+ for (String cid : cidAfterAdd) {
+ List<MessageQueue> rs = allocateMessageQueueConsistentHash.allocate("testConsumerGroup", cid, mqAll, cidAfterAdd);
+ allocatedResAllAfterAdd.addAll(rs);
+ for (MessageQueue mq : rs) {
+ allocateToAll3.put(mq, cid);
+ if (cid.equals(newCid)){
+ mqShouldOnlyChanged.add(mq);
+ }
+ }
+ //System.out.println("rs[" + cid + "]:" + "[" + rs.size() + "]" + rs.toString());
+ }
+
+ Assert.assertTrue(
+ verifyAllocateAll(cidAfterAdd,mqAll, allocatedResAllAfterAdd));
+ verifyAfterAdd(allocateToAllAfterRemoveOne, allocateToAll3, newCid);
+ }
+ }
+
+ private boolean verifyAllocateAll(List<String> cidAll,List<MessageQueue> mqAll, List<MessageQueue> allocatedResAll) {
+ if (cidAll.isEmpty()){
+ return allocatedResAll.isEmpty();
+ }
+ return mqAll.containsAll(allocatedResAll) && allocatedResAll.containsAll(mqAll);
+ }
+
+ private void verifyAfterRemove(Map<MessageQueue, String> allocateToBefore, Map<MessageQueue, String> allocateAfter, String removeCID) {
+ for (MessageQueue mq : allocateToBefore.keySet()) {
+ String allocateToOrigin = allocateToBefore.get(mq);
+ if (allocateToOrigin.equals(removeCID)) {
+
+ } else {//the rest queue should be the same
+ Assert.assertTrue(allocateAfter.get(mq).equals(allocateToOrigin));//should be the same
+ }
+ }
+ }
+
+ private void verifyAfterAdd(Map<MessageQueue, String> allocateBefore, Map<MessageQueue, String> allocateAfter, String newCID) {
+ for (MessageQueue mq : allocateAfter.keySet()) {
+ String allocateToOrigin = allocateBefore.get(mq);
+ String allocateToAfter = allocateAfter.get(mq);
+ if (allocateToAfter.equals(newCID)) {
+
+ } else {//the rest queue should be the same
+ Assert.assertTrue("it was allocated to "+allocateToOrigin+". Now, it is to "+allocateAfter.get(mq)+" mq:"+mq,allocateAfter.get(mq).equals(allocateToOrigin));//should be the same
+ }
+ }
+ }
+
+ private List<String> createConsumerIdList(int size) {
+ List<String> consumerIdList = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ consumerIdList.add(CID_PREFIX + String.valueOf(i));
+ }
+ return consumerIdList;
+ }
+
+ private List<MessageQueue> createMessageQueueList(int size) {
+ List<MessageQueue> messageQueueList = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ MessageQueue mq = new MessageQueue(topic, "brokerName", i);
+ messageQueueList.add(mq);
+ }
+ return messageQueueList;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java b/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
new file mode 100644
index 0000000..8606c43
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
@@ -0,0 +1,140 @@
+/*
+ * 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.common.consistenthash;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * To hash Node objects to a hash ring with a certain amount of virtual node.
+ * Method routeNode will return a Node instance which the object key should be allocated to according to consistent hash algorithm
+ *
+ * @param <T>
+ */
+public class ConsistentHashRouter<T extends Node> {
+ private final SortedMap<Long, VirtualNode<T>> ring = new TreeMap<>();
+ private final HashFunction hashFunction;
+
+ public ConsistentHashRouter(Collection<T> pNodes, int vNodeCount) {
+ this(pNodes,vNodeCount, new MD5Hash());
+ }
+
+ /**
+ *
+ * @param pNodes collections of physical nodes
+ * @param vNodeCount amounts of virtual nodes
+ * @param hashFunction hash Function to hash Node instances
+ */
+ public ConsistentHashRouter(Collection<T> pNodes, int vNodeCount, HashFunction hashFunction) {
+ if (hashFunction == null) {
+ throw new NullPointerException("Hash Function is null");
+ }
+ this.hashFunction = hashFunction;
+ if (pNodes != null) {
+ for (T pNode : pNodes) {
+ addNode(pNode, vNodeCount);
+ }
+ }
+ }
+
+ /**
+ * add physic node to the hash ring with some virtual nodes
+ * @param pNode physical node needs added to hash ring
+ * @param vNodeCount the number of virtual node of the physical node. Value should be greater than or equals to 0
+ */
+ public void addNode(T pNode, int vNodeCount) {
+ if (vNodeCount < 0) throw new IllegalArgumentException("illegal virtual node counts :" + vNodeCount);
+ int existingReplicas = getExistingReplicas(pNode);
+ for (int i = 0; i < vNodeCount; i++) {
+ VirtualNode<T> vNode = new VirtualNode<>(pNode, i + existingReplicas);
+ ring.put(hashFunction.hash(vNode.getKey()), vNode);
+ }
+ }
+
+ /**
+ * remove the physical node from the hash ring
+ * @param pNode
+ */
+ public void removeNode(T pNode) {
+ Iterator<Long> it = ring.keySet().iterator();
+ while (it.hasNext()) {
+ Long key = it.next();
+ VirtualNode<T> virtualNode = ring.get(key);
+ if (virtualNode.isVirtualNodeOf(pNode)) {
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * with a specified key, route the nearest Node instance in the current hash ring
+ * @param objectKey the object key to find a nearest Node
+ * @return
+ */
+ public T routeNode(String objectKey) {
+ if (ring.isEmpty()) {
+ return null;
+ }
+ Long hashVal = hashFunction.hash(objectKey);
+ SortedMap<Long,VirtualNode<T>> tailMap = ring.tailMap(hashVal);
+ Long nodeHashVal = !tailMap.isEmpty() ? tailMap.firstKey() : ring.firstKey();
+ return ring.get(nodeHashVal).getPhysicalNode();
+ }
+
+
+ public int getExistingReplicas(T pNode) {
+ int replicas = 0;
+ for (VirtualNode<T> vNode : ring.values()) {
+ if (vNode.isVirtualNodeOf(pNode)) {
+ replicas++;
+ }
+ }
+ return replicas;
+ }
+
+
+ //default hash function
+ private static class MD5Hash implements HashFunction {
+ MessageDigest instance;
+
+ public MD5Hash() {
+ try {
+ instance = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ }
+ }
+
+ @Override
+ public long hash(String key) {
+ instance.reset();
+ instance.update(key.getBytes());
+ byte[] digest = instance.digest();
+
+ long h = 0;
+ for (int i = 0; i < 4; i++) {
+ h <<= 8;
+ h |= ((int) digest[i]) & 0xFF;
+ }
+ return h;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/common/src/main/java/org/apache/rocketmq/common/consistenthash/HashFunction.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/consistenthash/HashFunction.java b/common/src/main/java/org/apache/rocketmq/common/consistenthash/HashFunction.java
new file mode 100644
index 0000000..58fd777
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/consistenthash/HashFunction.java
@@ -0,0 +1,24 @@
+/*
+ * 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.common.consistenthash;
+
+/**
+ * Hash String to long value
+ */
+public interface HashFunction {
+ long hash(String key);
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/common/src/main/java/org/apache/rocketmq/common/consistenthash/Node.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/consistenthash/Node.java b/common/src/main/java/org/apache/rocketmq/common/consistenthash/Node.java
new file mode 100644
index 0000000..0ece210
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/consistenthash/Node.java
@@ -0,0 +1,28 @@
+/*
+ * 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.common.consistenthash;
+
+/**
+ * Represent a node which should be mapped to a hash ring
+ */
+public interface Node {
+ /**
+ *
+ * @return the key which will be used for hash mapping
+ */
+ String getKey();
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/adae1624/common/src/main/java/org/apache/rocketmq/common/consistenthash/VirtualNode.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/consistenthash/VirtualNode.java b/common/src/main/java/org/apache/rocketmq/common/consistenthash/VirtualNode.java
new file mode 100644
index 0000000..c8b72d9
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/consistenthash/VirtualNode.java
@@ -0,0 +1,41 @@
+/*
+ * 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.common.consistenthash;
+
+
+public class VirtualNode<T extends Node> implements Node {
+ final T physicalNode;
+ final int replicaIndex;
+
+ public VirtualNode(T physicalNode, int replicaIndex) {
+ this.replicaIndex = replicaIndex;
+ this.physicalNode = physicalNode;
+ }
+
+ @Override
+ public String getKey() {
+ return physicalNode.getKey() + "-" + replicaIndex;
+ }
+
+ public boolean isVirtualNodeOf(T pNode) {
+ return physicalNode.getKey().equals(pNode.getKey());
+ }
+
+ public T getPhysicalNode() {
+ return physicalNode;
+ }
+}
[41/50] [abbrv] incubator-rocketmq git commit: Polish github links
Posted by do...@apache.org.
Polish github links
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/0fe94717
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/0fe94717
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/0fe94717
Branch: refs/heads/release-4.1.0-incubating
Commit: 0fe947173a85d8931b1068805713e89dbba4125a
Parents: de4c948
Author: dongeforever <zh...@yeah.net>
Authored: Sat May 27 14:39:30 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 14:39:30 2017 +0800
----------------------------------------------------------------------
pom.xml | 3 ---
.../src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java | 1 -
2 files changed, 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/0fe94717/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index a77f21d..75dbf5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -101,7 +101,6 @@
<id>stevenschew</id>
<name>Wei Zhou</name>
<email>stevenschew@@apache.org</email>
- <url>https://github.com/stevenschew</url>
<roles>
<role>committer</role>
</roles>
@@ -111,7 +110,6 @@
<id>lollipop</id>
<name>Jixiang Jin</name>
<email>lollipop@apache.org</email>
- <url>https://github.com/lollipopjin</url>
<roles>
<role>committer</role>
</roles>
@@ -121,7 +119,6 @@
<id>lizhanhui</id>
<name>Zhanhui Li</name>
<email>lizhanhui@apache.org</email>
- <url>https://github.com/lizhanhui</url>
<roles>
<role>committer</role>
</roles>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/0fe94717/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java b/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java
index 2b36fe7..5484dce 100644
--- a/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java
+++ b/store/src/main/java/org/apache/rocketmq/store/StoreCheckpoint.java
@@ -105,7 +105,6 @@ public class StoreCheckpoint {
public long getMinTimestamp() {
long min = Math.min(this.physicMsgTimestamp, this.logicsMsgTimestamp);
- // fixed https://github.org/apache/rocketmqissues/467
min -= 1000 * 3;
if (min < 0)
min = 0;
[32/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-98]Fix risk
of unable to release putMessage Lock forever closes
apache/incubator-rocketmq#61
Posted by do...@apache.org.
[ROCKETMQ-98]Fix risk of unable to release putMessage Lock forever closes apache/incubator-rocketmq#61
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/b1fcf1b8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/b1fcf1b8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/b1fcf1b8
Branch: refs/heads/release-4.1.0-incubating
Commit: b1fcf1b83b659bd03bcebf651d9e88c294a89e07
Parents: 0adad6f
Author: Jaskey <li...@gmail.com>
Authored: Sat May 27 11:21:09 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 11:21:09 2017 +0800
----------------------------------------------------------------------
.../apache/rocketmq/common/BrokerConfig.java | 3 ++
.../org/apache/rocketmq/store/CommitLog.java | 40 ++++--------------
.../apache/rocketmq/store/PutMessageLock.java | 25 ++++++++++++
.../rocketmq/store/PutMessageReentrantLock.java | 37 +++++++++++++++++
.../rocketmq/store/PutMessageSpinLock.java | 43 ++++++++++++++++++++
.../store/config/MessageStoreConfig.java | 4 ++
6 files changed, 119 insertions(+), 33 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
index f0a73bd..5bce013 100644
--- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
@@ -47,6 +47,9 @@ public class BrokerConfig {
private boolean autoCreateSubscriptionGroup = true;
private String messageStorePlugIn = "";
+ /**
+ * thread numbers for send message thread pool, since spin lock will be used by default since 4.0.x, the default value is 1.
+ */
private int sendMessageThreadPoolNums = 1; //16 + Runtime.getRuntime().availableProcessors() * 4;
private int pullMessageThreadPoolNums = 16 + Runtime.getRuntime().availableProcessors() * 2;
private int adminBrokerThreadPoolNums = 16;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
index 7841feb..7b29263 100644
--- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
+++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
@@ -23,8 +23,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.rocketmq.common.ServiceThread;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -63,12 +61,7 @@ public class CommitLog {
private volatile long confirmOffset = -1L;
private volatile long beginTimeInLock = 0;
-
- //true: Can lock, false : in lock.
- private AtomicBoolean putMessageSpinLock = new AtomicBoolean(true);
-
- private ReentrantLock putMessageNormalLock = new ReentrantLock(); // NonfairSync
-
+ private final PutMessageLock putMessageLock;
public CommitLog(final DefaultMessageStore defaultMessageStore) {
this.mappedFileQueue = new MappedFileQueue(defaultMessageStore.getMessageStoreConfig().getStorePathCommitLog(),
defaultMessageStore.getMessageStoreConfig().getMapedFileSizeCommitLog(), defaultMessageStore.getAllocateMappedFileService());
@@ -88,6 +81,8 @@ public class CommitLog {
return new MessageExtBatchEncoder(defaultMessageStore.getMessageStoreConfig().getMaxMessageSize());
}
};
+ this.putMessageLock = defaultMessageStore.getMessageStoreConfig().isUseReentrantLockWhenPutMessage() ? new PutMessageReentrantLock() : new PutMessageSpinLock();
+
}
public boolean load() {
@@ -577,7 +572,7 @@ public class CommitLog {
MappedFile unlockMappedFile = null;
MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile();
- lockForPutMessage(); //spin...
+ putMessageLock.lock(); //spin or ReentrantLock ,depending on store config
try {
long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now();
this.beginTimeInLock = beginLockTimestamp;
@@ -626,7 +621,7 @@ public class CommitLog {
eclipseTimeInLock = this.defaultMessageStore.getSystemClock().now() - beginLockTimestamp;
beginTimeInLock = 0;
} finally {
- releasePutMessageLock();
+ putMessageLock.unlock();
}
if (eclipseTimeInLock > 500) {
@@ -861,7 +856,7 @@ public class CommitLog {
}
public boolean appendData(long startOffset, byte[] data) {
- lockForPutMessage(); //spin...
+ putMessageLock.lock();
try {
MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile(startOffset);
if (null == mappedFile) {
@@ -871,7 +866,7 @@ public class CommitLog {
return mappedFile.appendMessage(data);
} finally {
- releasePutMessageLock();
+ putMessageLock.unlock();
}
}
@@ -906,28 +901,7 @@ public class CommitLog {
return diff;
}
- /**
- * Spin util acquired the lock.
- */
- private void lockForPutMessage() {
- if (this.defaultMessageStore.getMessageStoreConfig().isUseReentrantLockWhenPutMessage()) {
- putMessageNormalLock.lock();
- } else {
- boolean flag;
- do {
- flag = this.putMessageSpinLock.compareAndSet(true, false);
- }
- while (!flag);
- }
- }
- private void releasePutMessageLock() {
- if (this.defaultMessageStore.getMessageStoreConfig().isUseReentrantLockWhenPutMessage()) {
- putMessageNormalLock.unlock();
- } else {
- this.putMessageSpinLock.compareAndSet(false, true);
- }
- }
public static class GroupCommitRequest {
private final long nextOffset;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/store/src/main/java/org/apache/rocketmq/store/PutMessageLock.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/PutMessageLock.java b/store/src/main/java/org/apache/rocketmq/store/PutMessageLock.java
new file mode 100644
index 0000000..a03e41a
--- /dev/null
+++ b/store/src/main/java/org/apache/rocketmq/store/PutMessageLock.java
@@ -0,0 +1,25 @@
+/*
+ * 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.store;
+
+/**
+ * Used when trying to put message
+ */
+public interface PutMessageLock {
+ void lock();
+ void unlock();
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/store/src/main/java/org/apache/rocketmq/store/PutMessageReentrantLock.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/PutMessageReentrantLock.java b/store/src/main/java/org/apache/rocketmq/store/PutMessageReentrantLock.java
new file mode 100644
index 0000000..9198f1c
--- /dev/null
+++ b/store/src/main/java/org/apache/rocketmq/store/PutMessageReentrantLock.java
@@ -0,0 +1,37 @@
+/*
+ * 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.store;
+
+
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Exclusive lock implementation to put message
+ */
+public class PutMessageReentrantLock implements PutMessageLock {
+ private ReentrantLock putMessageNormalLock = new ReentrantLock(); // NonfairSync
+
+ @Override
+ public void lock() {
+ putMessageNormalLock.lock();
+ }
+
+ @Override
+ public void unlock() {
+ putMessageNormalLock.unlock();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/store/src/main/java/org/apache/rocketmq/store/PutMessageSpinLock.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/PutMessageSpinLock.java b/store/src/main/java/org/apache/rocketmq/store/PutMessageSpinLock.java
new file mode 100644
index 0000000..baa809d
--- /dev/null
+++ b/store/src/main/java/org/apache/rocketmq/store/PutMessageSpinLock.java
@@ -0,0 +1,43 @@
+/*
+ * 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.store;
+
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Spin lock Implementation to put message, suggest using this witb low race conditions
+ *
+ */
+public class PutMessageSpinLock implements PutMessageLock {
+ //true: Can lock, false : in lock.
+ private AtomicBoolean putMessageSpinLock = new AtomicBoolean(true);
+
+ @Override
+ public void lock() {
+ boolean flag;
+ do {
+ flag = this.putMessageSpinLock.compareAndSet(true, false);
+ }
+ while (!flag);
+ }
+
+ @Override
+ public void unlock() {
+ this.putMessageSpinLock.compareAndSet(false, true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/b1fcf1b8/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
index 29f800c..19ed211 100644
--- a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
+++ b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
@@ -52,6 +52,10 @@ public class MessageStoreConfig {
@ImportantField
private int commitIntervalCommitLog = 200;
+ /**
+ * introduced since 4.0.x. Determine whether to use mutex reentrantLock when putting message.<br/>
+ * By default it is set to false indicating using spin lock when putting message.
+ */
private boolean useReentrantLockWhenPutMessage = false;
// Whether schedule flush,default is real-time
[04/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-168] Polish
the BUILDING guide.
Posted by do...@apache.org.
[ROCKETMQ-168] Polish the BUILDING guide.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/42f78c28
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/42f78c28
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/42f78c28
Branch: refs/heads/release-4.1.0-incubating
Commit: 42f78c281cbeb5072b04eaf03b1a8059b8d281a7
Parents: deb0820
Author: yukon <yu...@apache.org>
Authored: Thu Apr 20 14:11:37 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu Apr 20 14:11:37 2017 +0800
----------------------------------------------------------------------
BUILDING | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/42f78c28/BUILDING
----------------------------------------------------------------------
diff --git a/BUILDING b/BUILDING
index 8a30495..c6e23f5 100644
--- a/BUILDING
+++ b/BUILDING
@@ -34,4 +34,4 @@ Build Instructions for Apache RocketMQ
Execute the following command in order to build the tar.gz packages and install JAR into local repository:
- $ mvn -Prelease-all -DskipTests clean package install -U
\ No newline at end of file
+ $ mvn -Prelease-all -DskipTests clean install -U
\ No newline at end of file
[08/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java
new file mode 100644
index 0000000..3e6d9b3
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/Expression.java
@@ -0,0 +1,38 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * Interface of expression.
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.Expression,
+ * but the parameter is changed to an interface.
+ * </p>
+ *
+ * @see org.apache.rocketmq.filter.expression.EvaluationContext
+ */
+public interface Expression {
+
+ /**
+ * Calculate express result with context.
+ *
+ * @param context context of evaluation
+ * @return the value of this expression
+ */
+ Object evaluate(EvaluationContext context) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java
new file mode 100644
index 0000000..1062bb8
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/LogicExpression.java
@@ -0,0 +1,94 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * A filter performing a comparison of two objects
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.LogicExpression,
+ * </p>
+ */
+public abstract class LogicExpression extends BinaryExpression implements BooleanExpression {
+
+ /**
+ * @param left
+ * @param right
+ */
+ public LogicExpression(BooleanExpression left, BooleanExpression right) {
+ super(left, right);
+ }
+
+ public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue) {
+ return new LogicExpression(lvalue, rvalue) {
+
+ public Object evaluate(EvaluationContext context) throws Exception {
+
+ Boolean lv = (Boolean) left.evaluate(context);
+ if (lv != null && lv.booleanValue()) {
+ return Boolean.TRUE;
+ }
+ Boolean rv = (Boolean) right.evaluate(context);
+ if (rv != null && rv.booleanValue()) {
+ return Boolean.TRUE;
+ }
+ if (lv == null || rv == null) {
+ return null;
+ }
+ return Boolean.FALSE;
+ }
+
+ public String getExpressionSymbol() {
+ return "||";
+ }
+ };
+ }
+
+ public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue) {
+ return new LogicExpression(lvalue, rvalue) {
+
+ public Object evaluate(EvaluationContext context) throws Exception {
+
+ Boolean lv = (Boolean) left.evaluate(context);
+
+ if (lv != null && !lv.booleanValue()) {
+ return Boolean.FALSE;
+ }
+ Boolean rv = (Boolean) right.evaluate(context);
+ if (rv != null && !rv.booleanValue()) {
+ return Boolean.FALSE;
+ }
+ if (lv == null || rv == null) {
+ return null;
+ }
+ return Boolean.TRUE;
+ }
+
+ public String getExpressionSymbol() {
+ return "&&";
+ }
+ };
+ }
+
+ public abstract Object evaluate(EvaluationContext context) throws Exception;
+
+ public boolean matches(EvaluationContext context) throws Exception {
+ Object object = evaluate(context);
+ return object != null && object == Boolean.TRUE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java
new file mode 100644
index 0000000..676a17b
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/MQFilterException.java
@@ -0,0 +1,46 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * Exception.
+ */
+public class MQFilterException extends Exception {
+ private static final long serialVersionUID = 1L;
+ private final int responseCode;
+ private final String errorMessage;
+
+ public MQFilterException(String errorMessage, Throwable cause) {
+ super(cause);
+ this.responseCode = -1;
+ this.errorMessage = errorMessage;
+ }
+
+ public MQFilterException(int responseCode, String errorMessage) {
+ this.responseCode = responseCode;
+ this.errorMessage = errorMessage;
+ }
+
+ public int getResponseCode() {
+ return responseCode;
+ }
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java
new file mode 100644
index 0000000..d76caca
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/NowExpression.java
@@ -0,0 +1,36 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * Current time expression.Just for test.
+ */
+public class NowExpression extends ConstantExpression {
+ public NowExpression() {
+ super("now");
+ }
+
+ @Override
+ public Object evaluate(EvaluationContext context) throws Exception {
+ return new Long(System.currentTimeMillis());
+ }
+
+ public Object getValue() {
+ return new Long(System.currentTimeMillis());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java
new file mode 100644
index 0000000..b9657b0
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/PropertyExpression.java
@@ -0,0 +1,70 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * Represents a property expression
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.PropertyExpression,
+ * but more simple and no transfer between expression and message property.
+ * </p>
+ */
+public class PropertyExpression implements Expression {
+ private final String name;
+
+ public PropertyExpression(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public Object evaluate(EvaluationContext context) throws Exception {
+ return context.get(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ /**
+ * @see Object#equals(Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+
+ if (o == null || !this.getClass().equals(o.getClass())) {
+ return false;
+ }
+ return name.equals(((PropertyExpression) o).name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java
new file mode 100644
index 0000000..0519f4d
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryExpression.java
@@ -0,0 +1,267 @@
+/*
+ * 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.filter.expression;
+
+import org.apache.rocketmq.filter.constant.UnaryType;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An expression which performs an operation on two expression values
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.UnaryExpression,
+ * but:
+ * 1. remove XPath and XQuery expression;
+ * 2. Add constant UnaryType to distinguish different unary expression;
+ * 3. Extract UnaryInExpression to an independent class.
+ * </p>
+ */
+public abstract class UnaryExpression implements Expression {
+
+ private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
+ protected Expression right;
+
+ public UnaryType unaryType;
+
+ public UnaryExpression(Expression left) {
+ this.right = left;
+ }
+
+ public UnaryExpression(Expression left, UnaryType unaryType) {
+ this.setUnaryType(unaryType);
+ this.right = left;
+ }
+
+ public static Expression createNegate(Expression left) {
+ return new UnaryExpression(left, UnaryType.NEGATE) {
+ public Object evaluate(EvaluationContext context) throws Exception {
+ Object rvalue = right.evaluate(context);
+ if (rvalue == null) {
+ return null;
+ }
+ if (rvalue instanceof Number) {
+ return negate((Number) rvalue);
+ }
+ return null;
+ }
+
+ public String getExpressionSymbol() {
+ return "-";
+ }
+ };
+ }
+
+ public static BooleanExpression createInExpression(PropertyExpression right, List<Object> elements,
+ final boolean not) {
+
+ // Use a HashSet if there are many elements.
+ Collection<Object> t;
+ if (elements.size() == 0) {
+ t = null;
+ } else if (elements.size() < 5) {
+ t = elements;
+ } else {
+ t = new HashSet<Object>(elements);
+ }
+ final Collection inList = t;
+
+ return new UnaryInExpression(right, UnaryType.IN, inList, not) {
+ public Object evaluate(EvaluationContext context) throws Exception {
+
+ Object rvalue = right.evaluate(context);
+ if (rvalue == null) {
+ return null;
+ }
+ if (rvalue.getClass() != String.class) {
+ return null;
+ }
+
+ if ((inList != null && inList.contains(rvalue)) ^ not) {
+ return Boolean.TRUE;
+ } else {
+ return Boolean.FALSE;
+ }
+
+ }
+
+ public String toString() {
+ StringBuffer answer = new StringBuffer();
+ answer.append(right);
+ answer.append(" ");
+ answer.append(getExpressionSymbol());
+ answer.append(" ( ");
+
+ int count = 0;
+ for (Iterator i = inList.iterator(); i.hasNext(); ) {
+ Object o = (Object) i.next();
+ if (count != 0) {
+ answer.append(", ");
+ }
+ answer.append(o);
+ count++;
+ }
+
+ answer.append(" )");
+ return answer.toString();
+ }
+
+ public String getExpressionSymbol() {
+ if (not) {
+ return "NOT IN";
+ } else {
+ return "IN";
+ }
+ }
+ };
+ }
+
+ abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression {
+ public BooleanUnaryExpression(Expression left, UnaryType unaryType) {
+ super(left, unaryType);
+ }
+
+ public boolean matches(EvaluationContext context) throws Exception {
+ Object object = evaluate(context);
+ return object != null && object == Boolean.TRUE;
+ }
+ }
+
+ public static BooleanExpression createNOT(BooleanExpression left) {
+ return new BooleanUnaryExpression(left, UnaryType.NOT) {
+ public Object evaluate(EvaluationContext context) throws Exception {
+ Boolean lvalue = (Boolean) right.evaluate(context);
+ if (lvalue == null) {
+ return null;
+ }
+ return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ public String getExpressionSymbol() {
+ return "NOT";
+ }
+ };
+ }
+
+ public static BooleanExpression createBooleanCast(Expression left) {
+ return new BooleanUnaryExpression(left, UnaryType.BOOLEANCAST) {
+ public Object evaluate(EvaluationContext context) throws Exception {
+ Object rvalue = right.evaluate(context);
+ if (rvalue == null) {
+ return null;
+ }
+ if (!rvalue.getClass().equals(Boolean.class)) {
+ return Boolean.FALSE;
+ }
+ return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public String toString() {
+ return right.toString();
+ }
+
+ public String getExpressionSymbol() {
+ return "";
+ }
+ };
+ }
+
+ private static Number negate(Number left) {
+ Class clazz = left.getClass();
+ if (clazz == Integer.class) {
+ return new Integer(-left.intValue());
+ } else if (clazz == Long.class) {
+ return new Long(-left.longValue());
+ } else if (clazz == Float.class) {
+ return new Float(-left.floatValue());
+ } else if (clazz == Double.class) {
+ return new Double(-left.doubleValue());
+ } else if (clazz == BigDecimal.class) {
+ // We ussually get a big deciamal when we have Long.MIN_VALUE
+ // constant in the
+ // Selector. Long.MIN_VALUE is too big to store in a Long as a
+ // positive so we store it
+ // as a Big decimal. But it gets Negated right away.. to here we try
+ // to covert it back
+ // to a Long.
+ BigDecimal bd = (BigDecimal) left;
+ bd = bd.negate();
+
+ if (BD_LONG_MIN_VALUE.compareTo(bd) == 0) {
+ return Long.valueOf(Long.MIN_VALUE);
+ }
+ return bd;
+ } else {
+ throw new RuntimeException("Don't know how to negate: " + left);
+ }
+ }
+
+ public Expression getRight() {
+ return right;
+ }
+
+ public void setRight(Expression expression) {
+ right = expression;
+ }
+
+ public UnaryType getUnaryType() {
+ return unaryType;
+ }
+
+ public void setUnaryType(UnaryType unaryType) {
+ this.unaryType = unaryType;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ return "(" + getExpressionSymbol() + " " + right.toString() + ")";
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ /**
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object o) {
+
+ if (o == null || !this.getClass().equals(o.getClass())) {
+ return false;
+ }
+ return toString().equals(o.toString());
+
+ }
+
+ /**
+ * Returns the symbol that represents this binary expression. For example,
+ * addition is represented by "+"
+ *
+ * @return
+ */
+ public abstract String getExpressionSymbol();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
new file mode 100644
index 0000000..7d9083c
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/UnaryInExpression.java
@@ -0,0 +1,61 @@
+/*
+ * 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.filter.expression;
+
+import org.apache.rocketmq.filter.constant.UnaryType;
+
+import java.util.Collection;
+
+/**
+ * In expression.
+ */
+abstract public class UnaryInExpression extends UnaryExpression implements BooleanExpression {
+
+ private boolean not;
+
+ private Collection inList;
+
+ public UnaryInExpression(Expression left, UnaryType unaryType,
+ Collection inList, boolean not) {
+ super(left, unaryType);
+ this.setInList(inList);
+ this.setNot(not);
+
+ }
+
+ public boolean matches(EvaluationContext context) throws Exception {
+ Object object = evaluate(context);
+ return object != null && object == Boolean.TRUE;
+ }
+
+ public boolean isNot() {
+ return not;
+ }
+
+ public void setNot(boolean not) {
+ this.not = not;
+ }
+
+ public Collection getInList() {
+ return inList;
+ }
+
+ public void setInList(Collection inList) {
+ this.inList = inList;
+ }
+};
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java
new file mode 100644
index 0000000..2ccccaf
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/ParseException.java
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 5.0 */
+/* JavaCCOptions:KEEP_LINE_COL=null */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ * <p/>
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+public class ParseException extends Exception {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the <i>serialized</i> form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * This constructor is used by the method "generateParseException"
+ * in the generated parser. Calling this constructor generates
+ * a new object of this type with the fields "currentToken",
+ * "expectedTokenSequences", and "TOKEN_IMAGE" set.
+ */
+ public ParseException(Token currentTokenVal,
+ int[][] expectedTokenSequencesVal,
+ String[] tokenImageVal
+ ) {
+ super(initialise(currentTokenVal, expectedTokenSequencesVal, tokenImageVal));
+ currentToken = currentTokenVal;
+ expectedTokenSequences = expectedTokenSequencesVal;
+ tokenImage = tokenImageVal;
+ }
+
+ /**
+ * The following constructors are for use by you for whatever
+ * purpose you can think of. Constructing the exception in this
+ * manner makes the exception behave in the normal way - i.e., as
+ * documented in the class "Throwable". The fields "errorToken",
+ * "expectedTokenSequences", and "TOKEN_IMAGE" do not contain
+ * relevant information. The JavaCC generated code does not use
+ * these constructors.
+ */
+
+ public ParseException() {
+ super();
+ }
+
+ /**
+ * Constructor with message.
+ */
+ public ParseException(String message) {
+ super(message);
+ }
+
+ /**
+ * This is the last token that has been consumed successfully. If
+ * this object has been created due to a parse error, the token
+ * followng this token will (therefore) be the first error token.
+ */
+ public Token currentToken;
+
+ /**
+ * Each entry in this array is an array of integers. Each array
+ * of integers represents a sequence of tokens (by their ordinal
+ * values) that is expected at this point of the parse.
+ */
+ public int[][] expectedTokenSequences;
+
+ /**
+ * This is a reference to the "TOKEN_IMAGE" array of the generated
+ * parser within which the parse error occurred. This array is
+ * defined in the generated ...Constants interface.
+ */
+ public String[] tokenImage;
+
+ /**
+ * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+ * error message and returns it. If this object has been created
+ * due to a parse error, and you do not catch it (it gets thrown
+ * from the parser) the correct error message
+ * gets displayed.
+ */
+ private static String initialise(Token currentToken,
+ int[][] expectedTokenSequences,
+ String[] tokenImage) {
+ String eol = System.getProperty("line.separator", "\n");
+ StringBuffer expected = new StringBuffer();
+ int maxSize = 0;
+ for (int i = 0; i < expectedTokenSequences.length; i++) {
+ if (maxSize < expectedTokenSequences[i].length) {
+ maxSize = expectedTokenSequences[i].length;
+ }
+ for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+ expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+ }
+ if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
+ expected.append("...");
+ }
+ expected.append(eol).append(" ");
+ }
+ String retval = "Encountered \"";
+ Token tok = currentToken.next;
+ for (int i = 0; i < maxSize; i++) {
+ if (i != 0)
+ retval += " ";
+ if (tok.kind == 0) {
+ retval += tokenImage[0];
+ break;
+ }
+ retval += " " + tokenImage[tok.kind];
+ retval += " \"";
+ retval += add_escapes(tok.image);
+ retval += " \"";
+ tok = tok.next;
+ }
+ retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
+ retval += "." + eol;
+ if (expectedTokenSequences.length == 1) {
+ retval += "Was expecting:" + eol + " ";
+ } else {
+ retval += "Was expecting one of:" + eol + " ";
+ }
+ retval += expected.toString();
+ return retval;
+ }
+
+ /**
+ * The end of line string for this machine.
+ */
+ protected String eol = System.getProperty("line.separator", "\n");
+
+ /**
+ * Used to convert raw characters to their escaped version
+ * when these raw version cannot be used as part of an ASCII
+ * string literal.
+ */
+ static String add_escapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i)) {
+ case 0:
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+}
+/* JavaCC - OriginalChecksum=4c829b0daa2c9af00ddafe2441eb9097 (do not edit this line) */
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java
new file mode 100644
index 0000000..74e5501
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.java
@@ -0,0 +1,1354 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. SelectorParser.java */
+package org.apache.rocketmq.filter.parser;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import org.apache.rocketmq.filter.expression.BooleanExpression;
+import org.apache.rocketmq.filter.expression.ComparisonExpression;
+import org.apache.rocketmq.filter.expression.ConstantExpression;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.LogicExpression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.apache.rocketmq.filter.expression.PropertyExpression;
+import org.apache.rocketmq.filter.expression.UnaryExpression;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+
+/**
+ * JMS Selector Parser generated by JavaCC
+ * <p/>
+ * Do not edit this .java file directly - it is autogenerated from SelectorParser.jj
+ */
+public class SelectorParser implements SelectorParserConstants {
+
+ private static final Cache<String, Object> PARSE_CACHE = CacheBuilder.newBuilder().maximumSize(100).build();
+ // private static final String CONVERT_STRING_EXPRESSIONS_PREFIX = "convert_string_expressions:";
+
+ public static BooleanExpression parse(String sql) throws MQFilterException {
+ // sql = "("+sql+")";
+ Object result = PARSE_CACHE.getIfPresent(sql);
+ if (result instanceof MQFilterException) {
+ throw (MQFilterException) result;
+ } else if (result instanceof BooleanExpression) {
+ return (BooleanExpression) result;
+ } else {
+
+ // boolean convertStringExpressions = false;
+ // if( sql.startsWith(CONVERT_STRING_EXPRESSIONS_PREFIX)) {
+ // convertStringExpressions = true;
+ // sql = sql.substring(CONVERT_STRING_EXPRESSIONS_PREFIX.length());
+ // }
+ //
+ // if( convertStringExpressions ) {
+ // ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true);
+ // }
+ ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true);
+ try {
+
+ BooleanExpression e = new SelectorParser(sql).parse();
+ PARSE_CACHE.put(sql, e);
+ return e;
+ } catch (MQFilterException t) {
+ PARSE_CACHE.put(sql, t);
+ throw t;
+ } finally {
+ ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove();
+ // if( convertStringExpressions ) {
+ // ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove();
+ // }
+ }
+ }
+ }
+
+ public static void clearCache() {
+ PARSE_CACHE.cleanUp();
+ }
+
+ private String sql;
+
+ protected SelectorParser(String sql) {
+ this(new StringReader(sql));
+ this.sql = sql;
+ }
+
+ protected BooleanExpression parse() throws MQFilterException {
+ try {
+ return this.JmsSelector();
+ } catch (Throwable e) {
+ throw new MQFilterException("Invalid MessageSelector. ", e);
+ }
+ }
+
+ private BooleanExpression asBooleanExpression(Expression value) throws ParseException {
+ if (value instanceof BooleanExpression) {
+ return (BooleanExpression) value;
+ }
+ if (value instanceof PropertyExpression) {
+ return UnaryExpression.createBooleanCast(value);
+ }
+ throw new ParseException("Expression will not result in a boolean value: " + value);
+ }
+
+ // ----------------------------------------------------------------------------
+ // Grammer
+ // ----------------------------------------------------------------------------
+ final public BooleanExpression JmsSelector() throws ParseException {
+ Expression left = null;
+ left = orExpression();
+ {
+ if (true)
+ return asBooleanExpression(left);
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression orExpression() throws ParseException {
+ Expression left;
+ Expression right;
+ left = andExpression();
+ label_1:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case OR:
+ break;
+ default:
+ jjLa1[0] = jjGen;
+ break label_1;
+ }
+ jj_consume_token(OR);
+ right = andExpression();
+ left = LogicExpression.createOR(asBooleanExpression(left), asBooleanExpression(right));
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression andExpression() throws ParseException {
+ Expression left;
+ Expression right;
+ left = equalityExpression();
+ label_2:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case AND:
+ break;
+ default:
+ jjLa1[1] = jjGen;
+ break label_2;
+ }
+ jj_consume_token(AND);
+ right = equalityExpression();
+ left = LogicExpression.createAND(asBooleanExpression(left), asBooleanExpression(right));
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression equalityExpression() throws ParseException {
+ Expression left;
+ Expression right;
+ left = comparisonExpression();
+ label_3:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case IS:
+ case 22:
+ case 23:
+ break;
+ default:
+ jjLa1[2] = jjGen;
+ break label_3;
+ }
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case 22:
+ jj_consume_token(22);
+ right = comparisonExpression();
+ left = ComparisonExpression.createEqual(left, right);
+ break;
+ case 23:
+ jj_consume_token(23);
+ right = comparisonExpression();
+ left = ComparisonExpression.createNotEqual(left, right);
+ break;
+ default:
+ jjLa1[3] = jjGen;
+ if (jj_2_1(2)) {
+ jj_consume_token(IS);
+ jj_consume_token(NULL);
+ left = ComparisonExpression.createIsNull(left);
+ } else {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case IS:
+ jj_consume_token(IS);
+ jj_consume_token(NOT);
+ jj_consume_token(NULL);
+ left = ComparisonExpression.createIsNotNull(left);
+ break;
+ default:
+ jjLa1[4] = jjGen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ }
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression comparisonExpression() throws ParseException {
+ Expression left;
+ Expression right;
+ Expression low;
+ Expression high;
+ String t, u;
+ boolean not;
+ ArrayList list;
+ left = unaryExpr();
+ label_4:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case NOT:
+ case BETWEEN:
+ case IN:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ break;
+ default:
+ jjLa1[5] = jjGen;
+ break label_4;
+ }
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case 24:
+ jj_consume_token(24);
+ right = unaryExpr();
+ left = ComparisonExpression.createGreaterThan(left, right);
+ break;
+ case 25:
+ jj_consume_token(25);
+ right = unaryExpr();
+ left = ComparisonExpression.createGreaterThanEqual(left, right);
+ break;
+ case 26:
+ jj_consume_token(26);
+ right = unaryExpr();
+ left = ComparisonExpression.createLessThan(left, right);
+ break;
+ case 27:
+ jj_consume_token(27);
+ right = unaryExpr();
+ left = ComparisonExpression.createLessThanEqual(left, right);
+ break;
+ case BETWEEN:
+ jj_consume_token(BETWEEN);
+ low = unaryExpr();
+ jj_consume_token(AND);
+ high = unaryExpr();
+ left = ComparisonExpression.createBetween(left, low, high);
+ break;
+ default:
+ jjLa1[8] = jjGen;
+ if (jj_2_2(2)) {
+ jj_consume_token(NOT);
+ jj_consume_token(BETWEEN);
+ low = unaryExpr();
+ jj_consume_token(AND);
+ high = unaryExpr();
+ left = ComparisonExpression.createNotBetween(left, low, high);
+ } else {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case IN:
+ jj_consume_token(IN);
+ jj_consume_token(28);
+ t = stringLitteral();
+ list = new ArrayList();
+ list.add(t);
+ label_5:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case 29:
+ break;
+ default:
+ jjLa1[6] = jjGen;
+ break label_5;
+ }
+ jj_consume_token(29);
+ t = stringLitteral();
+ list.add(t);
+ }
+ jj_consume_token(30);
+ left = ComparisonExpression.createInFilter(left, list);
+ break;
+ default:
+ jjLa1[9] = jjGen;
+ if (jj_2_3(2)) {
+ jj_consume_token(NOT);
+ jj_consume_token(IN);
+ jj_consume_token(28);
+ t = stringLitteral();
+ list = new ArrayList();
+ list.add(t);
+ label_6:
+ while (true) {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case 29:
+ break;
+ default:
+ jjLa1[7] = jjGen;
+ break label_6;
+ }
+ jj_consume_token(29);
+ t = stringLitteral();
+ list.add(t);
+ }
+ jj_consume_token(30);
+ left = ComparisonExpression.createNotInFilter(left, list);
+ } else {
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ }
+ }
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression unaryExpr() throws ParseException {
+ String s = null;
+ Expression left = null;
+ if (jj_2_4(2147483647)) {
+ jj_consume_token(31);
+ left = unaryExpr();
+ } else {
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case 32:
+ jj_consume_token(32);
+ left = unaryExpr();
+ left = UnaryExpression.createNegate(left);
+ break;
+ case NOT:
+ jj_consume_token(NOT);
+ left = unaryExpr();
+ left = UnaryExpression.createNOT(asBooleanExpression(left));
+ break;
+ case TRUE:
+ case FALSE:
+ case NULL:
+ case DECIMAL_LITERAL:
+ case FLOATING_POINT_LITERAL:
+ case STRING_LITERAL:
+ case ID:
+ case 28:
+ left = primaryExpr();
+ break;
+ default:
+ jjLa1[10] = jjGen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Expression primaryExpr() throws ParseException {
+ Expression left = null;
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case TRUE:
+ case FALSE:
+ case NULL:
+ case DECIMAL_LITERAL:
+ case FLOATING_POINT_LITERAL:
+ case STRING_LITERAL:
+ left = literal();
+ break;
+ case ID:
+ left = variable();
+ break;
+ case 28:
+ jj_consume_token(28);
+ left = orExpression();
+ jj_consume_token(30);
+ break;
+ default:
+ jjLa1[11] = jjGen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public ConstantExpression literal() throws ParseException {
+ Token t;
+ String s;
+ ConstantExpression left = null;
+ switch ((jjNtk == -1) ? jj_ntk() : jjNtk) {
+ case STRING_LITERAL:
+ s = stringLitteral();
+ left = new ConstantExpression(s);
+ break;
+ case DECIMAL_LITERAL:
+ t = jj_consume_token(DECIMAL_LITERAL);
+ left = ConstantExpression.createFromDecimal(t.image);
+ break;
+ case FLOATING_POINT_LITERAL:
+ t = jj_consume_token(FLOATING_POINT_LITERAL);
+ left = ConstantExpression.createFloat(t.image);
+ break;
+ case TRUE:
+ jj_consume_token(TRUE);
+ left = ConstantExpression.TRUE;
+ break;
+ case FALSE:
+ jj_consume_token(FALSE);
+ left = ConstantExpression.FALSE;
+ break;
+ case NULL:
+ jj_consume_token(NULL);
+ left = ConstantExpression.NULL;
+ break;
+ default:
+ jjLa1[12] = jjGen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public String stringLitteral() throws ParseException {
+ Token t;
+ StringBuffer rc = new StringBuffer();
+ boolean first = true;
+ t = jj_consume_token(STRING_LITERAL);
+ // Decode the sting value.
+ String image = t.image;
+ for (int i = 1; i < image.length() - 1; i++) {
+ char c = image.charAt(i);
+ if (c == '\'')
+ i++;
+ rc.append(c);
+ }
+ {
+ if (true)
+ return rc.toString();
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public PropertyExpression variable() throws ParseException {
+ Token t;
+ PropertyExpression left = null;
+ t = jj_consume_token(ID);
+ left = new PropertyExpression(t.image);
+ {
+ if (true)
+ return left;
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ private boolean jj_2_1(int xla) {
+ jjLa = xla;
+ jjLastpos = jjScanpos = token;
+ try {
+ return !jj_3_1();
+ } catch (LookaheadSuccess ls) {
+ return true;
+ } finally {
+ jj_save(0, xla);
+ }
+ }
+
+ private boolean jj_2_2(int xla) {
+ jjLa = xla;
+ jjLastpos = jjScanpos = token;
+ try {
+ return !jj_3_2();
+ } catch (LookaheadSuccess ls) {
+ return true;
+ } finally {
+ jj_save(1, xla);
+ }
+ }
+
+ private boolean jj_2_3(int xla) {
+ jjLa = xla;
+ jjLastpos = jjScanpos = token;
+ try {
+ return !jj_3_3();
+ } catch (LookaheadSuccess ls) {
+ return true;
+ } finally {
+ jj_save(2, xla);
+ }
+ }
+
+ private boolean jj_2_4(int xla) {
+ jjLa = xla;
+ jjLastpos = jjScanpos = token;
+ try {
+ return !jj_3_4();
+ } catch (LookaheadSuccess ls) {
+ return true;
+ } finally {
+ jj_save(3, xla);
+ }
+ }
+
+ private boolean jj_3R_7() {
+ Token xsp;
+ xsp = jjScanpos;
+ if (jj_3R_8()) {
+ jjScanpos = xsp;
+ if (jj_3R_9()) {
+ jjScanpos = xsp;
+ if (jj_3R_10()) {
+ jjScanpos = xsp;
+ if (jj_3R_11())
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_43() {
+ if (jj_scan_token(29))
+ return true;
+ if (jj_3R_27())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_24() {
+ if (jj_scan_token(NULL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_35() {
+ if (jj_scan_token(IS))
+ return true;
+ if (jj_scan_token(NOT))
+ return true;
+ if (jj_scan_token(NULL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3_1() {
+ if (jj_scan_token(IS))
+ return true;
+ if (jj_scan_token(NULL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_23() {
+ if (jj_scan_token(FALSE))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_34() {
+ if (jj_scan_token(23))
+ return true;
+ if (jj_3R_30())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_22() {
+ if (jj_scan_token(TRUE))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3_3() {
+ if (jj_scan_token(NOT))
+ return true;
+ if (jj_scan_token(IN))
+ return true;
+ if (jj_scan_token(28))
+ return true;
+ if (jj_3R_27())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_43()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ if (jj_scan_token(30))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_31() {
+ Token xsp;
+ xsp = jjScanpos;
+ if (jj_3R_33()) {
+ jjScanpos = xsp;
+ if (jj_3R_34()) {
+ jjScanpos = xsp;
+ if (jj_3_1()) {
+ jjScanpos = xsp;
+ if (jj_3R_35())
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_33() {
+ if (jj_scan_token(22))
+ return true;
+ if (jj_3R_30())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_42() {
+ if (jj_scan_token(29))
+ return true;
+ if (jj_3R_27())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_21() {
+ if (jj_scan_token(FLOATING_POINT_LITERAL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_20() {
+ if (jj_scan_token(DECIMAL_LITERAL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_28() {
+ if (jj_3R_30())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_31()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_41() {
+ if (jj_scan_token(IN))
+ return true;
+ if (jj_scan_token(28))
+ return true;
+ if (jj_3R_27())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_42()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ if (jj_scan_token(30))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_19() {
+ if (jj_3R_27())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_29() {
+ if (jj_scan_token(AND))
+ return true;
+ if (jj_3R_28())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_16() {
+ Token xsp;
+ xsp = jjScanpos;
+ if (jj_3R_19()) {
+ jjScanpos = xsp;
+ if (jj_3R_20()) {
+ jjScanpos = xsp;
+ if (jj_3R_21()) {
+ jjScanpos = xsp;
+ if (jj_3R_22()) {
+ jjScanpos = xsp;
+ if (jj_3R_23()) {
+ jjScanpos = xsp;
+ if (jj_3R_24())
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3_2() {
+ if (jj_scan_token(NOT))
+ return true;
+ if (jj_scan_token(BETWEEN))
+ return true;
+ if (jj_3R_7())
+ return true;
+ if (jj_scan_token(AND))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_40() {
+ if (jj_scan_token(BETWEEN))
+ return true;
+ if (jj_3R_7())
+ return true;
+ if (jj_scan_token(AND))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_25() {
+ if (jj_3R_28())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_29()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_39() {
+ if (jj_scan_token(27))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_15() {
+ if (jj_scan_token(28))
+ return true;
+ if (jj_3R_18())
+ return true;
+ if (jj_scan_token(30))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_14() {
+ if (jj_3R_17())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_38() {
+ if (jj_scan_token(26))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_13() {
+ if (jj_3R_16())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_26() {
+ if (jj_scan_token(OR))
+ return true;
+ if (jj_3R_25())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_17() {
+ if (jj_scan_token(ID))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_37() {
+ if (jj_scan_token(25))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_12() {
+ Token xsp;
+ xsp = jjScanpos;
+ if (jj_3R_13()) {
+ jjScanpos = xsp;
+ if (jj_3R_14()) {
+ jjScanpos = xsp;
+ if (jj_3R_15())
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_32() {
+ Token xsp;
+ xsp = jjScanpos;
+ if (jj_3R_36()) {
+ jjScanpos = xsp;
+ if (jj_3R_37()) {
+ jjScanpos = xsp;
+ if (jj_3R_38()) {
+ jjScanpos = xsp;
+ if (jj_3R_39()) {
+ jjScanpos = xsp;
+ if (jj_3R_40()) {
+ jjScanpos = xsp;
+ if (jj_3_2()) {
+ jjScanpos = xsp;
+ if (jj_3R_41()) {
+ jjScanpos = xsp;
+ if (jj_3_3())
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_36() {
+ if (jj_scan_token(24))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_11() {
+ if (jj_3R_12())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_18() {
+ if (jj_3R_25())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_26()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3_4() {
+ if (jj_scan_token(31))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_10() {
+ if (jj_scan_token(NOT))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_9() {
+ if (jj_scan_token(32))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_27() {
+ if (jj_scan_token(STRING_LITERAL))
+ return true;
+ return false;
+ }
+
+ private boolean jj_3R_30() {
+ if (jj_3R_7())
+ return true;
+ Token xsp;
+ while (true) {
+ xsp = jjScanpos;
+ if (jj_3R_32()) {
+ jjScanpos = xsp;
+ break;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_8() {
+ if (jj_scan_token(31))
+ return true;
+ if (jj_3R_7())
+ return true;
+ return false;
+ }
+
+ /**
+ * Generated Token Manager.
+ */
+ public SelectorParserTokenManager tokenSource;
+ SimpleCharStream jjInputStream;
+ /**
+ * Current token.
+ */
+ public Token token;
+ /**
+ * Next token.
+ */
+ public Token jjNt;
+ private int jjNtk;
+ private Token jjScanpos, jjLastpos;
+ private int jjLa;
+ private int jjGen;
+ final private int[] jjLa1 = new int[13];
+ static private int[] jjLa10;
+ static private int[] jjLa11;
+
+ static {
+ jj_la1_init_0();
+ jj_la1_init_1();
+ }
+
+ private static void jj_la1_init_0() {
+ jjLa10 = new int[]{0x400, 0x200, 0xc10000, 0xc00000, 0x10000, 0xf001900, 0x20000000, 0x20000000, 0xf000800,
+ 0x1000, 0x1036e100, 0x1036e000, 0x16e000};
+ }
+
+ private static void jj_la1_init_1() {
+ jjLa11 = new int[]{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0};
+ }
+
+ final private JJCalls[] jj2Rtns = new JJCalls[4];
+ private boolean jjRescan = false;
+ private int jjGc = 0;
+
+ /**
+ * Constructor with InputStream.
+ */
+ public SelectorParser(java.io.InputStream stream) {
+ this(stream, null);
+ }
+
+ /**
+ * Constructor with InputStream and supplied encoding
+ */
+ public SelectorParser(java.io.InputStream stream, String encoding) {
+ try {
+ jjInputStream = new SimpleCharStream(stream, encoding, 1, 1);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ tokenSource = new SelectorParserTokenManager(jjInputStream);
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream stream) {
+ ReInit(stream, null);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream stream, String encoding) {
+ try {
+ jjInputStream.ReInit(stream, encoding, 1, 1);
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ tokenSource.ReInit(jjInputStream);
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ /**
+ * Constructor.
+ */
+ public SelectorParser(java.io.Reader stream) {
+ jjInputStream = new SimpleCharStream(stream, 1, 1);
+ tokenSource = new SelectorParserTokenManager(jjInputStream);
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.Reader stream) {
+ jjInputStream.ReInit(stream, 1, 1);
+ tokenSource.ReInit(jjInputStream);
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ /**
+ * Constructor with generated Token Manager.
+ */
+ public SelectorParser(SelectorParserTokenManager tm) {
+ tokenSource = tm;
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(SelectorParserTokenManager tm) {
+ tokenSource = tm;
+ token = new Token();
+ jjNtk = -1;
+ jjGen = 0;
+ for (int i = 0; i < 13; i++)
+ jjLa1[i] = -1;
+ for (int i = 0; i < jj2Rtns.length; i++)
+ jj2Rtns[i] = new JJCalls();
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null)
+ token = token.next;
+ else
+ token = token.next = tokenSource.getNextToken();
+ jjNtk = -1;
+ if (token.kind == kind) {
+ jjGen++;
+ if (++jjGc > 100) {
+ jjGc = 0;
+ for (int i = 0; i < jj2Rtns.length; i++) {
+ JJCalls c = jj2Rtns[i];
+ while (c != null) {
+ if (c.gen < jjGen)
+ c.first = null;
+ c = c.next;
+ }
+ }
+ }
+ return token;
+ }
+ token = oldToken;
+ jjKind = kind;
+ throw generateParseException();
+ }
+
+ static private final class LookaheadSuccess extends java.lang.Error {
+ }
+
+ final private LookaheadSuccess jjLs = new LookaheadSuccess();
+
+ private boolean jj_scan_token(int kind) {
+ if (jjScanpos == jjLastpos) {
+ jjLa--;
+ if (jjScanpos.next == null) {
+ jjLastpos = jjScanpos = jjScanpos.next = tokenSource.getNextToken();
+ } else {
+ jjLastpos = jjScanpos = jjScanpos.next;
+ }
+ } else {
+ jjScanpos = jjScanpos.next;
+ }
+ if (jjRescan) {
+ int i = 0;
+ Token tok = token;
+ while (tok != null && tok != jjScanpos) {
+ i++;
+ tok = tok.next;
+ }
+ if (tok != null)
+ jj_add_error_token(kind, i);
+ }
+ if (jjScanpos.kind != kind)
+ return true;
+ if (jjLa == 0 && jjScanpos == jjLastpos)
+ throw jjLs;
+ return false;
+ }
+
+ /**
+ * Get the next Token.
+ */
+ final public Token getNextToken() {
+ if (token.next != null)
+ token = token.next;
+ else
+ token = token.next = tokenSource.getNextToken();
+ jjNtk = -1;
+ jjGen++;
+ return token;
+ }
+
+ /**
+ * Get the specific Token.
+ */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null)
+ t = t.next;
+ else
+ t = t.next = tokenSource.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jjNt = token.next) == null)
+ return jjNtk = (token.next = tokenSource.getNextToken()).kind;
+ else
+ return jjNtk = jjNt.kind;
+ }
+
+ private java.util.List<int[]> jjExpentries = new java.util.ArrayList<int[]>();
+ private int[] jjExpentry;
+ private int jjKind = -1;
+ private int[] jjLasttokens = new int[100];
+ private int jjEndpos;
+
+ private void jj_add_error_token(int kind, int pos) {
+ if (pos >= 100)
+ return;
+ if (pos == jjEndpos + 1) {
+ jjLasttokens[jjEndpos++] = kind;
+ } else if (jjEndpos != 0) {
+ jjExpentry = new int[jjEndpos];
+ for (int i = 0; i < jjEndpos; i++) {
+ jjExpentry[i] = jjLasttokens[i];
+ }
+ jj_entries_loop:
+ for (java.util.Iterator<?> it = jjExpentries.iterator(); it.hasNext(); ) {
+ int[] oldentry = (int[]) (it.next());
+ if (oldentry.length == jjExpentry.length) {
+ for (int i = 0; i < jjExpentry.length; i++) {
+ if (oldentry[i] != jjExpentry[i]) {
+ continue jj_entries_loop;
+ }
+ }
+ jjExpentries.add(jjExpentry);
+ break jj_entries_loop;
+ }
+ }
+ if (pos != 0)
+ jjLasttokens[(jjEndpos = pos) - 1] = kind;
+ }
+ }
+
+ /**
+ * Generate ParseException.
+ */
+ public ParseException generateParseException() {
+ jjExpentries.clear();
+ boolean[] la1tokens = new boolean[33];
+ if (jjKind >= 0) {
+ la1tokens[jjKind] = true;
+ jjKind = -1;
+ }
+ for (int i = 0; i < 13; i++) {
+ if (jjLa1[i] == jjGen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jjLa10[i] & (1 << j)) != 0) {
+ la1tokens[j] = true;
+ }
+ if ((jjLa11[i] & (1 << j)) != 0) {
+ la1tokens[32 + j] = true;
+ }
+ }
+ }
+ }
+ for (int i = 0; i < 33; i++) {
+ if (la1tokens[i]) {
+ jjExpentry = new int[1];
+ jjExpentry[0] = i;
+ jjExpentries.add(jjExpentry);
+ }
+ }
+ jjEndpos = 0;
+ jj_rescan_token();
+ jj_add_error_token(0, 0);
+ int[][] exptokseq = new int[jjExpentries.size()][];
+ for (int i = 0; i < jjExpentries.size(); i++) {
+ exptokseq[i] = jjExpentries.get(i);
+ }
+ return new ParseException(token, exptokseq, TOKEN_IMAGE);
+ }
+
+ /**
+ * Enable tracing.
+ */
+ final public void enable_tracing() {
+ }
+
+ /**
+ * Disable tracing.
+ */
+ final public void disable_tracing() {
+ }
+
+ private void jj_rescan_token() {
+ jjRescan = true;
+ for (int i = 0; i < 4; i++) {
+ try {
+ JJCalls p = jj2Rtns[i];
+ do {
+ if (p.gen > jjGen) {
+ jjLa = p.arg;
+ jjLastpos = jjScanpos = p.first;
+ switch (i) {
+ case 0:
+ jj_3_1();
+ break;
+ case 1:
+ jj_3_2();
+ break;
+ case 2:
+ jj_3_3();
+ break;
+ case 3:
+ jj_3_4();
+ break;
+ }
+ }
+ p = p.next;
+ } while (p != null);
+ } catch (LookaheadSuccess ls) {
+ }
+ }
+ jjRescan = false;
+ }
+
+ private void jj_save(int index, int xla) {
+ JJCalls p = jj2Rtns[index];
+ while (p.gen > jjGen) {
+ if (p.next == null) {
+ p = p.next = new JJCalls();
+ break;
+ }
+ p = p.next;
+ }
+ p.gen = jjGen + xla - jjLa;
+ p.first = token;
+ p.arg = xla;
+ }
+
+ static final class JJCalls {
+ int gen;
+ Token first;
+ int arg;
+ JJCalls next;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj
new file mode 100644
index 0000000..5d1a4a7
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParser.jj
@@ -0,0 +1,524 @@
+/*
+ * 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.
+ */
+
+/*
+ * This file was taken from ActiveMQ activemq-client/src/main/grammar/SelectorParser.jj.
+ *
+ * There are some modifications:
+ * 1. Convert string expressions default;
+ * 2. HEX_LITERAL and OCTAL_LITERAL were removed;
+ * 3. LIKE, ESCAPE, XPATH and XQUERY were removed;
+ * 4. Computation expressions were removed;
+ */
+
+// ----------------------------------------------------------------------------
+// OPTIONS
+// ----------------------------------------------------------------------------
+options {
+ STATIC = false;
+ UNICODE_INPUT = true;
+
+ //ERROR_REPORTING = false;
+}
+
+// ----------------------------------------------------------------------------
+// PARSER
+// ----------------------------------------------------------------------------
+
+PARSER_BEGIN(SelectorParser)
+
+package org.apache.rocketmq.filter.parser;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import org.apache.rocketmq.filter.expression.BooleanExpression;
+import org.apache.rocketmq.filter.expression.ComparisonExpression;
+import org.apache.rocketmq.filter.expression.ConstantExpression;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.LogicExpression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.apache.rocketmq.filter.expression.PropertyExpression;
+import org.apache.rocketmq.filter.expression.UnaryExpression;
+import org.apache.rocketmq.filter.util.LRUCache;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+
+/**
+ * JMS Selector Parser generated by JavaCC
+ *
+ * Do not edit this .java file directly - it is autogenerated from SelectorParser.jj
+ */
+public class SelectorParser {
+
+ private static final Cache<String, Object> PARSE_CACHE = CacheBuilder.newBuilder().maximumSize(100).build();
+// private static final String CONVERT_STRING_EXPRESSIONS_PREFIX = "convert_string_expressions:";
+
+ public static BooleanExpression parse(String sql) throws MQFilterException {
+// sql = "("+sql+")";
+ Object result = PARSE_CACHE.getIfPresent(sql);
+ if (result instanceof MQFilterException) {
+ throw (MQFilterException) result;
+ } else if (result instanceof BooleanExpression) {
+ return (BooleanExpression) result;
+ } else {
+
+// boolean convertStringExpressions = false;
+// if( sql.startsWith(CONVERT_STRING_EXPRESSIONS_PREFIX)) {
+// convertStringExpressions = true;
+// sql = sql.substring(CONVERT_STRING_EXPRESSIONS_PREFIX.length());
+// }
+//
+// if( convertStringExpressions ) {
+// ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true);
+// }
+ ComparisonExpression.CONVERT_STRING_EXPRESSIONS.set(true);
+ try {
+
+ BooleanExpression e = new SelectorParser(sql).parse();
+ PARSE_CACHE.put(sql, e);
+ return e;
+ } catch (MQFilterException t) {
+ PARSE_CACHE.put(sql, t);
+ throw t;
+ } finally {
+ ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove();
+// if( convertStringExpressions ) {
+// ComparisonExpression.CONVERT_STRING_EXPRESSIONS.remove();
+// }
+ }
+ }
+ }
+
+ public static void clearCache() {
+ PARSE_CACHE.cleanUp();
+ }
+
+ private String sql;
+
+ protected SelectorParser(String sql) {
+ this(new StringReader(sql));
+ this.sql = sql;
+ }
+
+ protected BooleanExpression parse() throws MQFilterException {
+ try {
+ return this.JmsSelector();
+ }
+ catch (Throwable e) {
+ throw new MQFilterException("Invalid MessageSelector. ", e);
+ }
+ }
+
+ private BooleanExpression asBooleanExpression(Expression value) throws ParseException {
+ if (value instanceof BooleanExpression) {
+ return (BooleanExpression) value;
+ }
+ if (value instanceof PropertyExpression) {
+ return UnaryExpression.createBooleanCast( value );
+ }
+ throw new ParseException("Expression will not result in a boolean value: " + value);
+ }
+
+}
+
+PARSER_END(SelectorParser)
+
+// ----------------------------------------------------------------------------
+// Tokens
+// ----------------------------------------------------------------------------
+
+/* White Space */
+SPECIAL_TOKEN :
+{
+ " " | "\t" | "\n" | "\r" | "\f"
+}
+
+/* Comments */
+SKIP:
+{
+ <LINE_COMMENT: "--" (~["\n","\r"])* ("\n"|"\r"|"\r\n") >
+}
+
+SKIP:
+{
+ <BLOCK_COMMENT: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/">
+}
+
+/* Reserved Words */
+TOKEN [IGNORE_CASE] :
+{
+ < NOT : "NOT">
+ | < AND : "AND">
+ | < OR : "OR">
+ | < BETWEEN : "BETWEEN">
+ | < IN : "IN">
+ | < TRUE : "TRUE" >
+ | < FALSE : "FALSE" >
+ | < NULL : "NULL" >
+ | < IS : "IS" >
+}
+
+/* Literals */
+TOKEN [IGNORE_CASE] :
+
+{
+
+ < DECIMAL_LITERAL: "0" | ["1"-"9"] (["0"-"9"])* (["l","L"])? >
+ | < FLOATING_POINT_LITERAL:
+ (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? // matches: 5.5 or 5. or 5.5E10 or 5.E10
+ | "." (["0"-"9"])+ (<EXPONENT>)? // matches: .5 or .5E10
+ | (["0"-"9"])+ <EXPONENT> // matches: 5E10
+ >
+ | < #EXPONENT: "E" (["+","-"])? (["0"-"9"])+ >
+ | < STRING_LITERAL: "'" ( ("''") | ~["'"] )* "'" >
+}
+
+TOKEN [IGNORE_CASE] :
+{
+ < ID : ["a"-"z", "_", "$"] (["a"-"z","0"-"9","_", "$"])* >
+}
+
+// ----------------------------------------------------------------------------
+// Grammer
+// ----------------------------------------------------------------------------
+BooleanExpression JmsSelector() :
+{
+ Expression left=null;
+}
+{
+ (
+ left = orExpression()
+ )
+ {
+ return asBooleanExpression(left);
+ }
+
+}
+
+Expression orExpression() :
+{
+ Expression left;
+ Expression right;
+}
+{
+ (
+ left = andExpression()
+ (
+ <OR> right = andExpression()
+ {
+ left = LogicExpression.createOR(asBooleanExpression(left), asBooleanExpression(right));
+ }
+ )*
+ )
+ {
+ return left;
+ }
+
+}
+
+
+Expression andExpression() :
+{
+ Expression left;
+ Expression right;
+}
+{
+ (
+ left = equalityExpression()
+ (
+ <AND> right = equalityExpression()
+ {
+ left = LogicExpression.createAND(asBooleanExpression(left), asBooleanExpression(right));
+ }
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+Expression equalityExpression() :
+{
+ Expression left;
+ Expression right;
+}
+{
+ (
+ left = comparisonExpression()
+ (
+
+ "=" right = comparisonExpression()
+ {
+ left = ComparisonExpression.createEqual(left, right);
+ }
+ |
+ "<>" right = comparisonExpression()
+ {
+ left = ComparisonExpression.createNotEqual(left, right);
+ }
+ |
+ LOOKAHEAD(2)
+ <IS> <NULL>
+ {
+ left = ComparisonExpression.createIsNull(left);
+ }
+ |
+ <IS> <NOT> <NULL>
+ {
+ left = ComparisonExpression.createIsNotNull(left);
+ }
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+Expression comparisonExpression() :
+{
+ Expression left;
+ Expression right;
+ Expression low;
+ Expression high;
+ String t, u;
+ boolean not;
+ ArrayList list;
+}
+{
+ (
+ left = unaryExpr()
+ (
+
+ ">" right = unaryExpr()
+ {
+ left = ComparisonExpression.createGreaterThan(left, right);
+ }
+ |
+ ">=" right = unaryExpr()
+ {
+ left = ComparisonExpression.createGreaterThanEqual(left, right);
+ }
+ |
+ "<" right = unaryExpr()
+ {
+ left = ComparisonExpression.createLessThan(left, right);
+ }
+ |
+ "<=" right = unaryExpr()
+ {
+ left = ComparisonExpression.createLessThanEqual(left, right);
+ }
+ |
+ <BETWEEN> low = unaryExpr() <AND> high = unaryExpr()
+ {
+ left = ComparisonExpression.createBetween(left, low, high);
+ }
+ |
+ LOOKAHEAD(2)
+ <NOT> <BETWEEN> low = unaryExpr() <AND> high = unaryExpr()
+ {
+ left = ComparisonExpression.createNotBetween(left, low, high);
+ }
+ |
+ <IN>
+ "("
+ t = stringLitteral()
+ {
+ list = new ArrayList();
+ list.add( t );
+ }
+ (
+ ","
+ t = stringLitteral()
+ {
+ list.add( t );
+ }
+
+ )*
+ ")"
+ {
+ left = ComparisonExpression.createInFilter(left, list);
+ }
+ |
+ LOOKAHEAD(2)
+ <NOT> <IN>
+ "("
+ t = stringLitteral()
+ {
+ list = new ArrayList();
+ list.add( t );
+ }
+ (
+ ","
+ t = stringLitteral()
+ {
+ list.add( t );
+ }
+
+ )*
+ ")"
+ {
+ left = ComparisonExpression.createNotInFilter(left, list);
+ }
+
+ )*
+ )
+ {
+ return left;
+ }
+}
+
+Expression unaryExpr() :
+{
+ String s=null;
+ Expression left=null;
+}
+{
+ (
+ LOOKAHEAD( "+" unaryExpr() )
+ "+" left=unaryExpr()
+ |
+ "-" left=unaryExpr()
+ {
+ left = UnaryExpression.createNegate(left);
+ }
+ |
+ <NOT> left=unaryExpr()
+ {
+ left = UnaryExpression.createNOT( asBooleanExpression(left) );
+ }
+ |
+ left = primaryExpr()
+ )
+ {
+ return left;
+ }
+
+}
+
+Expression primaryExpr() :
+{
+ Expression left=null;
+}
+{
+ (
+ left = literal()
+ |
+ left = variable()
+ |
+ "(" left = orExpression() ")"
+ )
+ {
+ return left;
+ }
+}
+
+
+
+ConstantExpression literal() :
+{
+ Token t;
+ String s;
+ ConstantExpression left=null;
+}
+{
+ (
+ (
+ s = stringLitteral()
+ {
+ left = new ConstantExpression(s);
+ }
+ )
+ |
+ (
+ t = <DECIMAL_LITERAL>
+ {
+ left = ConstantExpression.createFromDecimal(t.image);
+ }
+ )
+ |
+ (
+ t = <FLOATING_POINT_LITERAL>
+ {
+ left = ConstantExpression.createFloat(t.image);
+ }
+ )
+ |
+ (
+ <TRUE>
+ {
+ left = ConstantExpression.TRUE;
+ }
+ )
+ |
+ (
+ <FALSE>
+ {
+ left = ConstantExpression.FALSE;
+ }
+ )
+ |
+ (
+ <NULL>
+ {
+ left = ConstantExpression.NULL;
+ }
+ )
+ )
+ {
+ return left;
+ }
+}
+
+String stringLitteral() :
+{
+ Token t;
+ StringBuffer rc = new StringBuffer();
+ boolean first=true;
+}
+{
+ t = <STRING_LITERAL>
+ {
+ // Decode the sting value.
+ String image = t.image;
+ for( int i=1; i < image.length()-1; i++ ) {
+ char c = image.charAt(i);
+ if( c == '\'' )
+ i++;
+ rc.append(c);
+ }
+ return rc.toString();
+ }
+}
+
+PropertyExpression variable() :
+{
+ Token t;
+ PropertyExpression left=null;
+}
+{
+ (
+ t = <ID>
+ {
+ left = new PropertyExpression(t.image);
+ }
+ )
+ {
+ return left;
+ }
+}
[02/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-107] Fix
possible concurrency problem on ServiceState when consumer start/shutdown,
closes apache/incubator-rocketmq#68
Posted by do...@apache.org.
[ROCKETMQ-107] Fix possible concurrency problem on ServiceState when consumer start/shutdown, closes apache/incubator-rocketmq#68
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/f508f131
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/f508f131
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/f508f131
Branch: refs/heads/release-4.1.0-incubating
Commit: f508f131f7dee2bcb86e66a6beb7bbdedbe31bc6
Parents: c183e0d
Author: Jaskey <li...@gmail.com>
Authored: Wed Apr 19 11:58:48 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Wed Apr 19 11:58:48 2017 +0800
----------------------------------------------------------------------
.../consumer/DefaultMQPullConsumerImpl.java | 21 +++++++++++++-------
.../consumer/DefaultMQPushConsumerImpl.java | 15 +++++++-------
2 files changed, 22 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f508f131/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
index b26d062..7d43b37 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
@@ -70,7 +70,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
private final RPCHook rpcHook;
private final ArrayList<ConsumeMessageHook> consumeMessageHookList = new ArrayList<ConsumeMessageHook>();
private final ArrayList<FilterMessageHook> filterMessageHookList = new ArrayList<FilterMessageHook>();
- private ServiceState serviceState = ServiceState.CREATE_JUST;
+ private volatile ServiceState serviceState = ServiceState.CREATE_JUST;
private MQClientInstance mQClientFactory;
private PullAPIWrapper pullAPIWrapper;
private OffsetStore offsetStore;
@@ -161,7 +161,8 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
return this.pullSyncImpl(mq, subExpression, offset, maxNums, false, timeout);
}
- private PullResult pullSyncImpl(MessageQueue mq, String subExpression, long offset, int maxNums, boolean block, long timeout)
+ private PullResult pullSyncImpl(MessageQueue mq, String subExpression, long offset, int maxNums, boolean block,
+ long timeout)
throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
this.makeSureStateOK();
@@ -365,7 +366,8 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
pull(mq, subExpression, offset, maxNums, pullCallback, this.defaultMQPullConsumer.getConsumerPullTimeoutMillis());
}
- public void pull(MessageQueue mq, String subExpression, long offset, int maxNums, PullCallback pullCallback, long timeout)
+ public void pull(MessageQueue mq, String subExpression, long offset, int maxNums, PullCallback pullCallback,
+ long timeout)
throws MQClientException, RemotingException, InterruptedException {
this.pullAsyncImpl(mq, subExpression, offset, maxNums, pullCallback, false, timeout);
}
@@ -449,7 +451,8 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
return defaultMQPullConsumer;
}
- public void pullBlockIfNotFound(MessageQueue mq, String subExpression, long offset, int maxNums, PullCallback pullCallback)
+ public void pullBlockIfNotFound(MessageQueue mq, String subExpression, long offset, int maxNums,
+ PullCallback pullCallback)
throws MQClientException, RemotingException, InterruptedException {
this.pullAsyncImpl(mq, subExpression, offset, maxNums, pullCallback, true,
this.getDefaultMQPullConsumer().getConsumerPullTimeoutMillis());
@@ -510,7 +513,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
}
}
- public void shutdown() {
+ public synchronized void shutdown() {
switch (this.serviceState) {
case CREATE_JUST:
break;
@@ -528,7 +531,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
}
}
- public void start() throws MQClientException {
+ public synchronized void start() throws MQClientException {
switch (this.serviceState) {
case CREATE_JUST:
this.serviceState = ServiceState.START_FAILED;
@@ -593,6 +596,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
default:
break;
}
+
}
private void checkConfig() throws MQClientException {
@@ -662,7 +666,8 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
this.offsetStore.updateOffset(mq, offset, false);
}
- public MessageExt viewMessage(String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ public MessageExt viewMessage(String msgId)
+ throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
this.makeSureStateOK();
return this.mQClientFactory.getMQAdminImpl().viewMessage(msgId);
}
@@ -692,6 +697,8 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
return serviceState;
}
+ //Don't use this deprecated setter, which will be removed soon.
+ @Deprecated
public void setServiceState(ServiceState serviceState) {
this.serviceState = serviceState;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f508f131/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
index 4f33732..67f3ebe 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
@@ -97,7 +97,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
private final long consumerStartTimestamp = System.currentTimeMillis();
private final ArrayList<ConsumeMessageHook> consumeMessageHookList = new ArrayList<ConsumeMessageHook>();
private final RPCHook rpcHook;
- private ServiceState serviceState = ServiceState.CREATE_JUST;
+ private volatile ServiceState serviceState = ServiceState.CREATE_JUST;
private MQClientInstance mQClientFactory;
private PullAPIWrapper pullAPIWrapper;
private volatile boolean pause = false;
@@ -515,7 +515,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
}
- public void shutdown() {
+ public synchronized void shutdown() {
switch (this.serviceState) {
case CREATE_JUST:
break;
@@ -535,7 +535,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
}
- public void start() throws MQClientException {
+ public synchronized void start() throws MQClientException {
switch (this.serviceState) {
case CREATE_JUST:
log.info("the consumer [{}] start beginning. messageModel={}, isUnitMode={}", this.defaultMQPushConsumer.getConsumerGroup(),
@@ -615,9 +615,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
this.updateTopicSubscribeInfoWhenSubscriptionChanged();
-
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
-
this.mQClientFactory.rebalanceImmediately();
}
@@ -855,7 +853,8 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
this.consumeMessageService.updateCorePoolSize(corePoolSize);
}
- public MessageExt viewMessage(String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
+ public MessageExt viewMessage(String msgId)
+ throws RemotingException, MQBrokerException, InterruptedException, MQClientException {
return this.mQClientFactory.getMQAdminImpl().viewMessage(msgId);
}
@@ -1014,7 +1013,9 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
return serviceState;
}
- public void setServiceState(ServiceState serviceState) {
+ //Don't use this deprecated setter, which will be removed soon.
+ @Deprecated
+ public synchronized void setServiceState(ServiceState serviceState) {
this.serviceState = serviceState;
}
[33/50] [abbrv] incubator-rocketmq git commit:
[ROCKETMQ-188]RemotingExecption is not consistent between invoke async and
invoke oneway closes apache/incubator-rocketmq#98
Posted by do...@apache.org.
[ROCKETMQ-188]RemotingExecption is not consistent between invoke async and invoke oneway closes apache/incubator-rocketmq#98
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/8c8610f9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/8c8610f9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/8c8610f9
Branch: refs/heads/release-4.1.0-incubating
Commit: 8c8610f9121d19bf7108903e41276d5f6afaa81a
Parents: b1fcf1b
Author: Jaskey <li...@gmail.com>
Authored: Sat May 27 11:22:46 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 11:22:46 2017 +0800
----------------------------------------------------------------------
.../remoting/netty/NettyRemotingAbstract.java | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8c8610f9/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index cddab3d..15586cb 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -417,14 +417,18 @@ public abstract class NettyRemotingAbstract {
throw new RemotingSendRequestException(RemotingHelper.parseChannelRemoteAddr(channel), e);
}
} else {
- String info =
- String.format("invokeAsyncImpl tryAcquire semaphore timeout, %dms, waiting thread nums: %d semaphoreAsyncValue: %d", //
- timeoutMillis, //
- this.semaphoreAsync.getQueueLength(), //
- this.semaphoreAsync.availablePermits()//
- );
- PLOG.warn(info);
- throw new RemotingTooMuchRequestException(info);
+ if (timeoutMillis <= 0) {
+ throw new RemotingTooMuchRequestException("invokeAsyncImpl invoke too fast");
+ } else {
+ String info =
+ String.format("invokeAsyncImpl tryAcquire semaphore timeout, %dms, waiting thread nums: %d semaphoreAsyncValue: %d", //
+ timeoutMillis, //
+ this.semaphoreAsync.getQueueLength(), //
+ this.semaphoreAsync.availablePermits()//
+ );
+ PLOG.warn(info);
+ throw new RemotingTimeoutException(info);
+ }
}
}
[31/50] [abbrv] incubator-rocketmq git commit: Add test case for
LocalFileOffsetStore closes apache/incubator-rocketmq#59
Posted by do...@apache.org.
Add test case for LocalFileOffsetStore closes apache/incubator-rocketmq#59
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/0adad6f0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/0adad6f0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/0adad6f0
Branch: refs/heads/release-4.1.0-incubating
Commit: 0adad6f0025483647e760c1145f7736462c0ec79
Parents: e5d01b4
Author: djKooks <in...@gmail.com>
Authored: Sat May 27 11:06:37 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 11:06:37 2017 +0800
----------------------------------------------------------------------
.../consumer/store/LocalFileOffsetStoreTest.java | 13 +++++++++++++
1 file changed, 13 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/0adad6f0/client/src/test/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStoreTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStoreTest.java b/client/src/test/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStoreTest.java
index 22e212b..a705b30 100644
--- a/client/src/test/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStoreTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStoreTest.java
@@ -19,6 +19,8 @@ package org.apache.rocketmq.client.consumer.store;
import java.io.File;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Map;
+
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
import org.apache.rocketmq.common.message.MessageQueue;
@@ -72,4 +74,15 @@ public class LocalFileOffsetStoreTest {
offsetStore.persistAll(new HashSet<MessageQueue>(Collections.singletonList(messageQueue)));
assertThat(offsetStore.readOffset(messageQueue, ReadOffsetType.READ_FROM_STORE)).isEqualTo(1024);
}
+
+ @Test
+ public void testCloneOffset() throws Exception {
+ OffsetStore offsetStore = new LocalFileOffsetStore(mQClientFactory, group);
+ MessageQueue messageQueue = new MessageQueue(topic, brokerName, 3);
+ offsetStore.updateOffset(messageQueue, 1024, false);
+ Map<MessageQueue, Long> cloneOffsetTable = offsetStore.cloneOffsetTable(topic);
+
+ assertThat(cloneOffsetTable.size()).isEqualTo(1);
+ assertThat(cloneOffsetTable.get(messageQueue)).isEqualTo(1024);
+ }
}
\ No newline at end of file
[35/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-206] Catch
the IOException when call the file2String method.
Posted by do...@apache.org.
[ROCKETMQ-206] Catch the IOException when call the file2String method.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/aced0de7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/aced0de7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/aced0de7
Branch: refs/heads/release-4.1.0-incubating
Commit: aced0de7d8f98a01d9d109dd592a6cb31fd174d9
Parents: ceeef8e
Author: yukon <yu...@apache.org>
Authored: Sat May 27 11:34:44 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Sat May 27 11:34:44 2017 +0800
----------------------------------------------------------------------
.../client/consumer/store/LocalFileOffsetStore.java | 14 ++++++++++++--
.../apache/rocketmq/example/benchmark/Consumer.java | 3 ++-
.../org/apache/rocketmq/example/filter/Consumer.java | 3 ++-
.../rocketmq/namesrv/kvconfig/KVConfigManager.java | 7 ++++++-
4 files changed, 22 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/aced0de7/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
index 2cde5f8..6c81516 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
@@ -180,7 +180,12 @@ public class LocalFileOffsetStore implements OffsetStore {
}
private OffsetSerializeWrapper readLocalOffset() throws MQClientException {
- String content = MixAll.file2String(this.storePath);
+ String content = null;
+ try {
+ content = MixAll.file2String(this.storePath);
+ } catch (IOException e) {
+ log.warn("Load local offset store file exception", e);
+ }
if (null == content || content.length() == 0) {
return this.readLocalOffsetBak();
} else {
@@ -198,7 +203,12 @@ public class LocalFileOffsetStore implements OffsetStore {
}
private OffsetSerializeWrapper readLocalOffsetBak() throws MQClientException {
- String content = MixAll.file2String(this.storePath + ".bak");
+ String content = null;
+ try {
+ content = MixAll.file2String(this.storePath + ".bak");
+ } catch (IOException e) {
+ log.warn("Load local offset store bak file exception", e);
+ }
if (content != null && content.length() > 0) {
OffsetSerializeWrapper offsetSerializeWrapper = null;
try {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/aced0de7/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
index 3e1b79b..d431d3e 100644
--- a/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.example.benchmark;
+import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
@@ -39,7 +40,7 @@ import org.apache.rocketmq.srvutil.ServerUtil;
public class Consumer {
- public static void main(String[] args) throws MQClientException {
+ public static void main(String[] args) throws MQClientException, IOException {
Options options = ServerUtil.buildCommandlineOptions(new Options());
CommandLine commandLine = ServerUtil.parseCmdLine("benchmarkConsumer", args, buildCommandlineOptions(options), new PosixParser());
if (null == commandLine) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/aced0de7/example/src/main/java/org/apache/rocketmq/example/filter/Consumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/filter/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/filter/Consumer.java
index d63435b..0be8e1d 100644
--- a/example/src/main/java/org/apache/rocketmq/example/filter/Consumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/filter/Consumer.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.example.filter;
import java.io.File;
+import java.io.IOException;
import java.util.List;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
@@ -28,7 +29,7 @@ import org.apache.rocketmq.common.message.MessageExt;
public class Consumer {
- public static void main(String[] args) throws InterruptedException, MQClientException {
+ public static void main(String[] args) throws InterruptedException, MQClientException, IOException {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupNamecc4");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/aced0de7/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigManager.java
----------------------------------------------------------------------
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigManager.java
index 69afcad..be13bd6 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigManager.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/kvconfig/KVConfigManager.java
@@ -43,7 +43,12 @@ public class KVConfigManager {
}
public void load() {
- String content = MixAll.file2String(this.namesrvController.getNamesrvConfig().getKvConfigPath());
+ String content = null;
+ try {
+ content = MixAll.file2String(this.namesrvController.getNamesrvConfig().getKvConfigPath());
+ } catch (IOException e) {
+ log.warn("Load KV config table exception", e);
+ }
if (content != null) {
KVConfigSerializeWrapper kvConfigSerializeWrapper =
KVConfigSerializeWrapper.fromJson(content, KVConfigSerializeWrapper.class);
[10/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
index 6349ffc..67807a8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ClientManageProcessor.java
@@ -22,15 +22,19 @@ import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.filter.ExpressionType;
import org.apache.rocketmq.common.protocol.RequestCode;
import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.common.protocol.body.CheckClientRequestBody;
import org.apache.rocketmq.common.protocol.header.UnregisterClientRequestHeader;
import org.apache.rocketmq.common.protocol.header.UnregisterClientResponseHeader;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumerData;
import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
import org.apache.rocketmq.common.protocol.heartbeat.ProducerData;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.common.sysflag.TopicSysFlag;
+import org.apache.rocketmq.filter.FilterFactory;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
@@ -54,6 +58,8 @@ public class ClientManageProcessor implements NettyRequestProcessor {
return this.heartBeat(ctx, request);
case RequestCode.UNREGISTER_CLIENT:
return this.unregisterClient(ctx, request);
+ case RequestCode.CHECK_CLIENT_CONFIG:
+ return this.checkClientConfig(ctx, request);
default:
break;
}
@@ -157,4 +163,42 @@ public class ClientManageProcessor implements NettyRequestProcessor {
response.setRemark(null);
return response;
}
+
+ public RemotingCommand checkClientConfig(ChannelHandlerContext ctx, RemotingCommand request)
+ throws RemotingCommandException {
+ final RemotingCommand response = RemotingCommand.createResponseCommand(null);
+
+ CheckClientRequestBody requestBody = CheckClientRequestBody.decode(request.getBody(),
+ CheckClientRequestBody.class);
+
+ if (requestBody != null && requestBody.getSubscriptionData() != null) {
+ SubscriptionData subscriptionData = requestBody.getSubscriptionData();
+
+ if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ response.setCode(ResponseCode.SUCCESS);
+ response.setRemark(null);
+ return response;
+ }
+
+ if (!this.brokerController.getBrokerConfig().isEnablePropertyFilter()) {
+ response.setCode(ResponseCode.SYSTEM_ERROR);
+ response.setRemark("The broker does not support consumer to filter message by " + subscriptionData.getExpressionType());
+ return response;
+ }
+
+ try {
+ FilterFactory.INSTANCE.get(subscriptionData.getExpressionType()).compile(subscriptionData.getSubString());
+ } catch (Exception e) {
+ log.warn("Client {}@{} filter message, but failed to compile expression! sub={}, error={}",
+ requestBody.getClientId(), requestBody.getGroup(), requestBody.getSubscriptionData(), e.getMessage());
+ response.setCode(ResponseCode.SUBSCRIPTION_PARSE_FAILED);
+ response.setRemark(e.getMessage());
+ return response;
+ }
+ }
+
+ response.setCode(ResponseCode.SUCCESS);
+ response.setRemark(null);
+ return response;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
index 89967d8..10945da 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/PullMessageProcessor.java
@@ -25,6 +25,10 @@ import java.nio.ByteBuffer;
import java.util.List;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
+import org.apache.rocketmq.broker.filter.ConsumerFilterData;
+import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
+import org.apache.rocketmq.broker.filter.ExpressionForRetryMessageFilter;
+import org.apache.rocketmq.broker.filter.ExpressionMessageFilter;
import org.apache.rocketmq.broker.longpolling.PullRequest;
import org.apache.rocketmq.broker.mqtrace.ConsumeMessageContext;
import org.apache.rocketmq.broker.mqtrace.ConsumeMessageHook;
@@ -34,6 +38,7 @@ import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.common.TopicFilterType;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.filter.ExpressionType;
import org.apache.rocketmq.common.filter.FilterAPI;
import org.apache.rocketmq.common.help.FAQUrl;
import org.apache.rocketmq.common.message.MessageDecoder;
@@ -54,6 +59,7 @@ import org.apache.rocketmq.remoting.netty.RequestTask;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.store.GetMessageResult;
import org.apache.rocketmq.store.MessageExtBrokerInner;
+import org.apache.rocketmq.store.MessageFilter;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.config.BrokerRole;
import org.apache.rocketmq.store.stats.BrokerStatsManager;
@@ -142,13 +148,22 @@ public class PullMessageProcessor implements NettyRequestProcessor {
}
SubscriptionData subscriptionData = null;
+ ConsumerFilterData consumerFilterData = null;
if (hasSubscriptionFlag) {
try {
- subscriptionData = FilterAPI.buildSubscriptionData(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
- requestHeader.getSubscription());
+ subscriptionData = FilterAPI.build(
+ requestHeader.getTopic(), requestHeader.getSubscription(), requestHeader.getExpressionType()
+ );
+ if (!ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ consumerFilterData = ConsumerFilterManager.build(
+ requestHeader.getTopic(), requestHeader.getConsumerGroup(), requestHeader.getSubscription(),
+ requestHeader.getExpressionType(), requestHeader.getSubVersion()
+ );
+ assert consumerFilterData != null;
+ }
} catch (Exception e) {
LOG.warn("Parse the consumer's subscription[{}] failed, group: {}", requestHeader.getSubscription(), //
- requestHeader.getConsumerGroup());
+ requestHeader.getConsumerGroup());
response.setCode(ResponseCode.SUBSCRIPTION_PARSE_FAILED);
response.setRemark("parse the consumer's subscription failed");
return response;
@@ -180,16 +195,48 @@ public class PullMessageProcessor implements NettyRequestProcessor {
if (subscriptionData.getSubVersion() < requestHeader.getSubVersion()) {
LOG.warn("The broker's subscription is not latest, group: {} {}", requestHeader.getConsumerGroup(),
- subscriptionData.getSubString());
+ subscriptionData.getSubString());
response.setCode(ResponseCode.SUBSCRIPTION_NOT_LATEST);
response.setRemark("the consumer's subscription not latest");
return response;
}
+ if (!ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ consumerFilterData = this.brokerController.getConsumerFilterManager().get(requestHeader.getTopic(),
+ requestHeader.getConsumerGroup());
+ if (consumerFilterData == null) {
+ response.setCode(ResponseCode.FILTER_DATA_NOT_EXIST);
+ response.setRemark("The broker's consumer filter data is not exist!Your expression may be wrong!");
+ return response;
+ }
+ if (consumerFilterData.getClientVersion() < requestHeader.getSubVersion()) {
+ LOG.warn("The broker's consumer filter data is not latest, group: {}, topic: {}, serverV: {}, clientV: {}",
+ requestHeader.getConsumerGroup(), requestHeader.getTopic(), consumerFilterData.getClientVersion(), requestHeader.getSubVersion());
+ response.setCode(ResponseCode.FILTER_DATA_NOT_LATEST);
+ response.setRemark("the consumer's consumer filter data not latest");
+ return response;
+ }
+ }
+ }
+
+ if (!ExpressionType.isTagType(subscriptionData.getExpressionType())
+ && !this.brokerController.getBrokerConfig().isEnablePropertyFilter()) {
+ response.setCode(ResponseCode.SYSTEM_ERROR);
+ response.setRemark("The broker does not support consumer to filter message by " + subscriptionData.getExpressionType());
+ return response;
+ }
+
+ MessageFilter messageFilter;
+ if (this.brokerController.getBrokerConfig().isFilterSupportRetry()) {
+ messageFilter = new ExpressionForRetryMessageFilter(subscriptionData, consumerFilterData,
+ this.brokerController.getConsumerFilterManager());
+ } else {
+ messageFilter = new ExpressionMessageFilter(subscriptionData, consumerFilterData,
+ this.brokerController.getConsumerFilterManager());
}
final GetMessageResult getMessageResult =
this.brokerController.getMessageStore().getMessage(requestHeader.getConsumerGroup(), requestHeader.getTopic(),
- requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), subscriptionData);
+ requestHeader.getQueueId(), requestHeader.getQueueOffset(), requestHeader.getMaxMsgNums(), messageFilter);
if (getMessageResult != null) {
response.setRemark(getMessageResult.getStatus().name());
responseHeader.setNextBeginOffset(getMessageResult.getNextBeginOffset());
@@ -368,7 +415,7 @@ public class PullMessageProcessor implements NettyRequestProcessor {
long offset = requestHeader.getQueueOffset();
int queueId = requestHeader.getQueueId();
PullRequest pullRequest = new PullRequest(request, channel, pollingTimeMills,
- this.brokerController.getMessageStore().now(), offset, subscriptionData);
+ this.brokerController.getMessageStore().now(), offset, subscriptionData, messageFilter);
this.brokerController.getPullRequestHoldService().suspendPullRequest(topic, queueId, pullRequest);
response = null;
break;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/test/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMapTest.java
----------------------------------------------------------------------
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMapTest.java b/broker/src/test/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMapTest.java
new file mode 100644
index 0000000..87f6256
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMapTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.filter.util.BitsArray;
+import org.apache.rocketmq.store.DispatchRequest;
+import org.junit.Test;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CommitLogDispatcherCalcBitMapTest {
+
+ @Test
+ public void testDispatch_filterDataIllegal() {
+ BrokerConfig brokerConfig = new BrokerConfig();
+ brokerConfig.setEnableCalcFilterBitMap(true);
+
+ ConsumerFilterManager filterManager = new ConsumerFilterManager();
+
+ filterManager.register("topic0", "CID_0", "a is not null and a >= 5",
+ ExpressionType.SQL92, System.currentTimeMillis());
+
+ filterManager.register("topic0", "CID_1", "a is not null and a >= 15",
+ ExpressionType.SQL92, System.currentTimeMillis());
+
+ ConsumerFilterData nullExpression = filterManager.get("topic0", "CID_0");
+ nullExpression.setExpression(null);
+ nullExpression.setCompiledExpression(null);
+ ConsumerFilterData nullBloomData = filterManager.get("topic0", "CID_1");
+ nullBloomData.setBloomFilterData(null);
+
+
+ CommitLogDispatcherCalcBitMap calcBitMap = new CommitLogDispatcherCalcBitMap(brokerConfig,
+ filterManager);
+
+ for (int i = 0; i < 1; i++) {
+ Map<String, String> properties = new HashMap<String, String>(4);
+ properties.put("a", String.valueOf(i * 10 + 5));
+
+ String topic = "topic" + i;
+
+ DispatchRequest dispatchRequest = new DispatchRequest(
+ topic,
+ 0,
+ i * 100 + 123,
+ 100,
+ (long) ("tags" + i).hashCode(),
+ System.currentTimeMillis(),
+ i,
+ null,
+ UUID.randomUUID().toString(),
+ 0,
+ 0,
+ properties
+ );
+
+ calcBitMap.dispatch(dispatchRequest);
+
+ assertThat(dispatchRequest.getBitMap()).isNotNull();
+
+ BitsArray bitsArray = BitsArray.create(dispatchRequest.getBitMap(),
+ filterManager.getBloomFilter().getM());
+
+ for (int j = 0; j < bitsArray.bitLength(); j++) {
+ assertThat(bitsArray.getBit(j)).isFalse();
+ }
+ }
+ }
+
+ @Test
+ public void testDispatch_blankFilterData() {
+ BrokerConfig brokerConfig = new BrokerConfig();
+ brokerConfig.setEnableCalcFilterBitMap(true);
+
+ ConsumerFilterManager filterManager = new ConsumerFilterManager();
+
+ CommitLogDispatcherCalcBitMap calcBitMap = new CommitLogDispatcherCalcBitMap(brokerConfig,
+ filterManager);
+
+ for (int i = 0; i < 10; i++) {
+ Map<String, String> properties = new HashMap<String, String>(4);
+ properties.put("a", String.valueOf(i * 10 + 5));
+
+ String topic = "topic" + i;
+
+ DispatchRequest dispatchRequest = new DispatchRequest(
+ topic,
+ 0,
+ i * 100 + 123,
+ 100,
+ (long) ("tags" + i).hashCode(),
+ System.currentTimeMillis(),
+ i,
+ null,
+ UUID.randomUUID().toString(),
+ 0,
+ 0,
+ properties
+ );
+
+ calcBitMap.dispatch(dispatchRequest);
+
+ assertThat(dispatchRequest.getBitMap()).isNull();
+ }
+ }
+
+ @Test
+ public void testDispatch() {
+ BrokerConfig brokerConfig = new BrokerConfig();
+ brokerConfig.setEnableCalcFilterBitMap(true);
+
+ ConsumerFilterManager filterManager = ConsumerFilterManagerTest.gen(10, 10);
+
+ CommitLogDispatcherCalcBitMap calcBitMap = new CommitLogDispatcherCalcBitMap(brokerConfig,
+ filterManager);
+
+ for (int i = 0; i < 10; i++) {
+ Map<String, String> properties = new HashMap<String, String>(4);
+ properties.put("a", String.valueOf(i * 10 + 5));
+
+ String topic = "topic" + i;
+
+ DispatchRequest dispatchRequest = new DispatchRequest(
+ topic,
+ 0,
+ i * 100 + 123,
+ 100,
+ (long) ("tags" + i).hashCode(),
+ System.currentTimeMillis(),
+ i,
+ null,
+ UUID.randomUUID().toString(),
+ 0,
+ 0,
+ properties
+ );
+
+ calcBitMap.dispatch(dispatchRequest);
+
+ assertThat(dispatchRequest.getBitMap()).isNotNull();
+
+ BitsArray bits = BitsArray.create(dispatchRequest.getBitMap());
+
+ Collection<ConsumerFilterData> filterDatas = filterManager.get(topic);
+
+ for (ConsumerFilterData filterData : filterDatas) {
+
+ if (filterManager.getBloomFilter().isHit(filterData.getBloomFilterData(), bits)) {
+ try {
+ assertThat((Boolean) filterData.getCompiledExpression().evaluate(
+ new MessageEvaluationContext(properties)
+ )).isTrue();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+ } else {
+ try {
+ assertThat((Boolean) filterData.getCompiledExpression().evaluate(
+ new MessageEvaluationContext(properties)
+ )).isFalse();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/test/java/org/apache/rocketmq/broker/filter/ConsumerFilterManagerTest.java
----------------------------------------------------------------------
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/filter/ConsumerFilterManagerTest.java b/broker/src/test/java/org/apache/rocketmq/broker/filter/ConsumerFilterManagerTest.java
new file mode 100644
index 0000000..c8412a8
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/filter/ConsumerFilterManagerTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.common.filter.FilterAPI;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConsumerFilterManagerTest {
+
+ public static ConsumerFilterManager gen(int topicCount, int consumerCount) {
+ ConsumerFilterManager filterManager = new ConsumerFilterManager();
+
+ for (int i = 0; i < topicCount; i++) {
+ String topic = "topic" + i;
+
+ for (int j = 0; j < consumerCount; j++) {
+
+ String consumer = "CID_" + j;
+
+ filterManager.register(topic, consumer, expr(j), ExpressionType.SQL92, System.currentTimeMillis());
+ }
+ }
+
+ return filterManager;
+ }
+
+ public static String expr(int i) {
+ return "a is not null and a > " + ((i - 1) * 10) + " and a < " + ((i + 1) * 10);
+ }
+
+ @Test
+ public void testRegister_newExpressionCompileErrorAndRemoveOld() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ assertThat(filterManager.get("topic9", "CID_9")).isNotNull();
+
+ String newExpr = "a between 10,20";
+
+ assertThat(filterManager.register("topic9", "CID_9", newExpr, ExpressionType.SQL92, System.currentTimeMillis() + 1))
+ .isFalse();
+ assertThat(filterManager.get("topic9", "CID_9")).isNull();
+
+ newExpr = "a between 10 AND 20";
+
+ assertThat(filterManager.register("topic9", "CID_9", newExpr, ExpressionType.SQL92, System.currentTimeMillis() + 1))
+ .isTrue();
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(newExpr).isEqualTo(filterData.getExpression());
+ }
+
+ @Test
+ public void testRegister_change() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ System.out.println(filterData.getCompiledExpression());
+
+ String newExpr = "a > 0 and a < 10";
+
+ filterManager.register("topic9", "CID_9", newExpr, ExpressionType.SQL92, System.currentTimeMillis() + 1);
+
+ filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(newExpr).isEqualTo(filterData.getExpression());
+
+ System.out.println(filterData.toString());
+ }
+
+ @Test
+ public void testRegister() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isFalse();
+
+ // new version
+ assertThat(filterManager.register(
+ "topic9", "CID_9", "a is not null", ExpressionType.SQL92, System.currentTimeMillis() + 1000
+ )).isTrue();
+
+ ConsumerFilterData newFilter = filterManager.get("topic9", "CID_9");
+
+ assertThat(newFilter).isNotEqualTo(filterData);
+
+ // same version
+ assertThat(filterManager.register(
+ "topic9", "CID_9", "a is null", ExpressionType.SQL92, newFilter.getClientVersion()
+ )).isFalse();
+
+ ConsumerFilterData filterData1 = filterManager.get("topic9", "CID_9");
+
+ assertThat(newFilter).isEqualTo(filterData1);
+ }
+
+ @Test
+ public void testRegister_reAlive() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isFalse();
+
+ //make dead
+ filterManager.unRegister("CID_9");
+
+ //reAlive
+ filterManager.register(
+ filterData.getTopic(),
+ filterData.getConsumerGroup(),
+ filterData.getExpression(),
+ filterData.getExpressionType(),
+ System.currentTimeMillis()
+ );
+
+ ConsumerFilterData newFilterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(newFilterData).isNotNull();
+ assertThat(newFilterData.isDead()).isFalse();
+ }
+
+ @Test
+ public void testRegister_bySubscriptionData() {
+ ConsumerFilterManager filterManager = new ConsumerFilterManager();
+ List<SubscriptionData> subscriptionDatas = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ try {
+ subscriptionDatas.add(
+ FilterAPI.build(
+ "topic" + i,
+ "a is not null and a > " + i,
+ ExpressionType.SQL92
+ )
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+ }
+
+ filterManager.register("CID_0", subscriptionDatas);
+
+ Collection<ConsumerFilterData> filterDatas = filterManager.getByGroup("CID_0");
+
+ assertThat(filterDatas).isNotNull();
+ assertThat(filterDatas.size()).isEqualTo(10);
+
+ Iterator<ConsumerFilterData> iterator = filterDatas.iterator();
+ while (iterator.hasNext()) {
+ ConsumerFilterData filterData = iterator.next();
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterManager.getBloomFilter().isValid(filterData.getBloomFilterData())).isTrue();
+ }
+ }
+
+ @Test
+ public void testRegister_tag() {
+ ConsumerFilterManager filterManager = new ConsumerFilterManager();
+
+ assertThat(filterManager.register("topic0", "CID_0", "*", null, System.currentTimeMillis())).isFalse();
+
+ Collection<ConsumerFilterData> filterDatas = filterManager.getByGroup("CID_0");
+
+ assertThat(filterDatas).isNullOrEmpty();
+ }
+
+ @Test
+ public void testUnregister() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isFalse();
+
+ filterManager.unRegister("CID_9");
+
+ assertThat(filterData.isDead()).isTrue();
+ }
+
+ @Test
+ public void testPersist() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ try {
+ filterManager.persist();
+
+ ConsumerFilterData filterData = filterManager.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isFalse();
+
+ ConsumerFilterManager loadFilter = new ConsumerFilterManager();
+
+ assertThat(loadFilter.load()).isTrue();
+
+ filterData = loadFilter.get("topic9", "CID_9");
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isTrue();
+ assertThat(filterData.getCompiledExpression()).isNotNull();
+ } finally {
+ deleteDirectory("./unit_test");
+ }
+ }
+
+ @Test
+ public void testPersist_clean() {
+ ConsumerFilterManager filterManager = gen(10, 10);
+
+ String topic = "topic9";
+ for (int i = 0; i < 10; i++) {
+ String cid = "CID_" + i;
+
+ ConsumerFilterData filterData = filterManager.get(topic, cid);
+
+ assertThat(filterData).isNotNull();
+ assertThat(filterData.isDead()).isFalse();
+
+ //make dead more than 24h
+ filterData.setBornTime(System.currentTimeMillis() - 26 * 60 * 60 * 1000);
+ filterData.setDeadTime(System.currentTimeMillis() - 25 * 60 * 60 * 1000);
+ }
+
+ try {
+ filterManager.persist();
+
+ ConsumerFilterManager loadFilter = new ConsumerFilterManager();
+
+ assertThat(loadFilter.load()).isTrue();
+
+ ConsumerFilterData filterData = loadFilter.get(topic, "CID_9");
+
+ assertThat(filterData).isNull();
+
+ Collection<ConsumerFilterData> topicData = loadFilter.get(topic);
+
+ assertThat(topicData).isNullOrEmpty();
+ } finally {
+ deleteDirectory("./unit_test");
+ }
+ }
+
+ protected void deleteDirectory(String rootPath) {
+ File file = new File(rootPath);
+ deleteFile(file);
+ }
+
+ protected void deleteFile(File file) {
+ File[] subFiles = file.listFiles();
+ if (subFiles != null) {
+ for (File sub : subFiles) {
+ deleteFile(sub);
+ }
+ }
+
+ file.delete();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/test/java/org/apache/rocketmq/broker/filter/MessageStoreWithFilterTest.java
----------------------------------------------------------------------
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/filter/MessageStoreWithFilterTest.java b/broker/src/test/java/org/apache/rocketmq/broker/filter/MessageStoreWithFilterTest.java
new file mode 100644
index 0000000..53e563e
--- /dev/null
+++ b/broker/src/test/java/org/apache/rocketmq/broker/filter/MessageStoreWithFilterTest.java
@@ -0,0 +1,392 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.store.CommitLogDispatcher;
+import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.DispatchRequest;
+import org.apache.rocketmq.store.GetMessageResult;
+import org.apache.rocketmq.store.GetMessageStatus;
+import org.apache.rocketmq.store.MessageArrivingListener;
+import org.apache.rocketmq.store.MessageExtBrokerInner;
+import org.apache.rocketmq.store.PutMessageResult;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.apache.rocketmq.store.stats.BrokerStatsManager;
+import org.junit.Test;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MessageStoreWithFilterTest {
+
+ private static final String msg = "Once, there was a chance for me!";
+ private static final byte[] msgBody = msg.getBytes();
+
+ private static final String topic = "topic";
+ private static final int queueId = 0;
+ private static final String storePath = "." + File.separator + "unit_test_store";
+ private static final int commitLogFileSize = 1024 * 1024 * 256;
+ private static final int cqFileSize = 300000 * 20;
+ private static final int cqExtFileSize = 300000 * 128;
+
+ private static SocketAddress BornHost;
+
+ private static SocketAddress StoreHost;
+
+ static {
+ try {
+ StoreHost = new InetSocketAddress(InetAddress.getLocalHost(), 8123);
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ try {
+ BornHost = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0);
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public MessageExtBrokerInner buildMessage() {
+ MessageExtBrokerInner msg = new MessageExtBrokerInner();
+ msg.setTopic(topic);
+ msg.setTags("TAG1");
+ msg.setKeys("Hello");
+ msg.setBody(msgBody);
+ msg.setKeys(String.valueOf(System.currentTimeMillis()));
+ msg.setQueueId(queueId);
+ msg.setSysFlag(0);
+ msg.setBornTimestamp(System.currentTimeMillis());
+ msg.setStoreHost(StoreHost);
+ msg.setBornHost(BornHost);
+ for (int i = 1; i < 3; i++) {
+ msg.putUserProperty(String.valueOf(i), "imagoodperson" + i);
+ }
+ msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));
+
+ return msg;
+ }
+
+ public MessageStoreConfig buildStoreConfig(int commitLogFileSize, int cqFileSize,
+ boolean enableCqExt, int cqExtFileSize) {
+ MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
+ messageStoreConfig.setMapedFileSizeCommitLog(commitLogFileSize);
+ messageStoreConfig.setMapedFileSizeConsumeQueue(cqFileSize);
+ messageStoreConfig.setMappedFileSizeConsumeQueueExt(cqExtFileSize);
+ messageStoreConfig.setMessageIndexEnable(false);
+ messageStoreConfig.setEnableConsumeQueueExt(enableCqExt);
+
+ messageStoreConfig.setStorePathRootDir(storePath);
+ messageStoreConfig.setStorePathCommitLog(storePath + File.separator + "commitlog");
+
+ return messageStoreConfig;
+ }
+
+ protected DefaultMessageStore gen(ConsumerFilterManager filterManager) throws Exception {
+ MessageStoreConfig messageStoreConfig = buildStoreConfig(
+ commitLogFileSize, cqFileSize, true, cqExtFileSize
+ );
+
+ BrokerConfig brokerConfig = new BrokerConfig();
+ brokerConfig.setEnableCalcFilterBitMap(true);
+ brokerConfig.setMaxErrorRateOfBloomFilter(20);
+ brokerConfig.setExpectConsumerNumUseFilter(64);
+
+ DefaultMessageStore master = new DefaultMessageStore(
+ messageStoreConfig,
+ new BrokerStatsManager(brokerConfig.getBrokerClusterName()),
+ new MessageArrivingListener() {
+ @Override
+ public void arriving(String topic, int queueId, long logicOffset, long tagsCode,
+ long msgStoreTime, byte[] filterBitMap, Map<String, String> properties) {
+// System.out.println(String.format("Msg coming: %s, %d, %d, %d",
+// topic, queueId, logicOffset, tagsCode));
+ }
+ }
+ , brokerConfig);
+
+ master.getDispatcherList().addFirst(new CommitLogDispatcher() {
+ @Override
+ public void dispatch(DispatchRequest request) {
+ try {
+// System.out.println(String.format("offset:%d, bitMap:%s", request.getCommitLogOffset(),
+// BitsArray.create(request.getBitMap()).toString()));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ master.getDispatcherList().addFirst(new CommitLogDispatcherCalcBitMap(brokerConfig, filterManager));
+
+ assertThat(master.load()).isTrue();
+
+ master.start();
+
+ return master;
+ }
+
+ protected List<MessageExtBrokerInner> putMsg(DefaultMessageStore master, int topicCount, int msgCountPerTopic) throws Exception {
+ List<MessageExtBrokerInner> msgs = new ArrayList<MessageExtBrokerInner>();
+ for (int i = 0; i < topicCount; i++) {
+ String realTopic = topic + i;
+ for (int j = 0; j < msgCountPerTopic; j++) {
+ MessageExtBrokerInner msg = buildMessage();
+ msg.setTopic(realTopic);
+ msg.putUserProperty("a", String.valueOf(j * 10 + 5));
+ msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));
+
+ PutMessageResult result = master.putMessage(msg);
+
+ msg.setMsgId(result.getAppendMessageResult().getMsgId());
+
+ msgs.add(msg);
+ }
+ }
+
+ return msgs;
+ }
+
+ protected void deleteDirectory(String rootPath) {
+ File file = new File(rootPath);
+ deleteFile(file);
+ }
+
+ protected void deleteFile(File file) {
+ File[] subFiles = file.listFiles();
+ if (subFiles != null) {
+ for (File sub : subFiles) {
+ deleteFile(sub);
+ }
+ }
+
+ file.delete();
+ }
+
+ protected List<MessageExtBrokerInner> filtered(List<MessageExtBrokerInner> msgs, ConsumerFilterData filterData) {
+ List<MessageExtBrokerInner> filteredMsgs = new ArrayList<MessageExtBrokerInner>();
+
+ for (MessageExtBrokerInner messageExtBrokerInner : msgs) {
+
+ if (!messageExtBrokerInner.getTopic().equals(filterData.getTopic())) {
+ continue;
+ }
+
+ try {
+ Object evlRet = filterData.getCompiledExpression().evaluate(new MessageEvaluationContext(messageExtBrokerInner.getProperties()));
+
+ if (evlRet == null || !(evlRet instanceof Boolean) || (Boolean) evlRet) {
+ filteredMsgs.add(messageExtBrokerInner);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+ }
+
+ return filteredMsgs;
+ }
+
+ @Test
+ public void testGetMessage_withFilterBitMapAndConsumerChanged() {
+ int topicCount = 10, msgPerTopic = 10;
+ ConsumerFilterManager filterManager = ConsumerFilterManagerTest.gen(topicCount, msgPerTopic);
+
+ DefaultMessageStore master = null;
+ try {
+ master = gen(filterManager);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ try {
+ List<MessageExtBrokerInner> msgs = null;
+ try {
+ msgs = putMsg(master, topicCount, msgPerTopic);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ // sleep to wait for consume queue has been constructed.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ // reset consumer;
+ String topic = "topic" + 0;
+ String resetGroup = "CID_" + 2;
+ String normalGroup = "CID_" + 3;
+
+ {
+ // reset CID_2@topic0 to get all messages.
+ SubscriptionData resetSubData = new SubscriptionData();
+ resetSubData.setExpressionType(ExpressionType.SQL92);
+ resetSubData.setTopic(topic);
+ resetSubData.setClassFilterMode(false);
+ resetSubData.setSubString("a is not null OR a is null");
+
+ ConsumerFilterData resetFilterData = ConsumerFilterManager.build(topic,
+ resetGroup, resetSubData.getSubString(), resetSubData.getExpressionType(),
+ System.currentTimeMillis());
+
+ GetMessageResult resetGetResult = master.getMessage(resetGroup, topic, queueId, 0, 1000,
+ new ExpressionMessageFilter(resetSubData, resetFilterData, filterManager));
+
+ try {
+ assertThat(resetGetResult).isNotNull();
+
+ List<MessageExtBrokerInner> filteredMsgs = filtered(msgs, resetFilterData);
+
+ assertThat(resetGetResult.getMessageBufferList().size()).isEqualTo(filteredMsgs.size());
+ } finally {
+ resetGetResult.release();
+ }
+ }
+
+ {
+ ConsumerFilterData normalFilterData = filterManager.get(topic, normalGroup);
+ assertThat(normalFilterData).isNotNull();
+ assertThat(normalFilterData.getBornTime()).isLessThan(System.currentTimeMillis());
+
+ SubscriptionData normalSubData = new SubscriptionData();
+ normalSubData.setExpressionType(normalFilterData.getExpressionType());
+ normalSubData.setTopic(topic);
+ normalSubData.setClassFilterMode(false);
+ normalSubData.setSubString(normalFilterData.getExpression());
+
+ List<MessageExtBrokerInner> filteredMsgs = filtered(msgs, normalFilterData);
+
+ GetMessageResult normalGetResult = master.getMessage(normalGroup, topic, queueId, 0, 1000,
+ new ExpressionMessageFilter(normalSubData, normalFilterData, filterManager));
+
+ try {
+ assertThat(normalGetResult).isNotNull();
+ assertThat(normalGetResult.getMessageBufferList().size()).isEqualTo(filteredMsgs.size());
+ } finally {
+ normalGetResult.release();
+ }
+ }
+ } finally {
+ master.shutdown();
+ master.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testGetMessage_withFilterBitMap() {
+ int topicCount = 10, msgPerTopic = 500;
+ ConsumerFilterManager filterManager = ConsumerFilterManagerTest.gen(topicCount, msgPerTopic);
+
+ DefaultMessageStore master = null;
+ try {
+ master = gen(filterManager);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ try {
+ List<MessageExtBrokerInner> msgs = null;
+ try {
+ msgs = putMsg(master, topicCount, msgPerTopic);
+ // sleep to wait for consume queue has been constructed.
+ Thread.sleep(1000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ for (int i = 0; i < topicCount; i++) {
+ String realTopic = topic + i;
+
+ for (int j = 0; j < msgPerTopic; j++) {
+ String group = "CID_" + j;
+
+ ConsumerFilterData filterData = filterManager.get(realTopic, group);
+ assertThat(filterData).isNotNull();
+
+ List<MessageExtBrokerInner> filteredMsgs = filtered(msgs, filterData);
+
+ SubscriptionData subscriptionData = new SubscriptionData();
+ subscriptionData.setExpressionType(filterData.getExpressionType());
+ subscriptionData.setTopic(filterData.getTopic());
+ subscriptionData.setClassFilterMode(false);
+ subscriptionData.setSubString(filterData.getExpression());
+
+ GetMessageResult getMessageResult = master.getMessage(group, realTopic, queueId, 0, 10000,
+ new ExpressionMessageFilter(subscriptionData, filterData, filterManager));
+ String assertMsg = group + "-" + realTopic;
+ try {
+ assertThat(getMessageResult).isNotNull();
+ assertThat(GetMessageStatus.FOUND).isEqualTo(getMessageResult.getStatus());
+ assertThat(getMessageResult.getMessageBufferList()).isNotNull().isNotEmpty();
+ assertThat(getMessageResult.getMessageBufferList().size()).isEqualTo(filteredMsgs.size());
+
+ for (ByteBuffer buffer : getMessageResult.getMessageBufferList()) {
+ MessageExt messageExt = MessageDecoder.decode(buffer.slice(), false);
+ assertThat(messageExt).isNotNull();
+
+ Object evlRet = null;
+ try {
+ evlRet = filterData.getCompiledExpression().evaluate(new MessageEvaluationContext(messageExt.getProperties()));
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(true).isFalse();
+ }
+
+ assertThat(evlRet).isNotNull().isEqualTo(Boolean.TRUE);
+
+ // check
+ boolean find = false;
+ for (MessageExtBrokerInner messageExtBrokerInner : filteredMsgs) {
+ if (messageExtBrokerInner.getMsgId().equals(messageExt.getMsgId())) {
+ find = true;
+ }
+ }
+ assertThat(find).isTrue();
+ }
+ } finally {
+ getMessageResult.release();
+ }
+ }
+ }
+ } finally {
+ master.shutdown();
+ master.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
----------------------------------------------------------------------
diff --git a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
index d3d9812..941d4a7 100644
--- a/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
+++ b/broker/src/test/java/org/apache/rocketmq/broker/processor/PullMessageProcessorTest.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Set;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
+import org.apache.rocketmq.broker.filter.ExpressionMessageFilter;
import org.apache.rocketmq.broker.mqtrace.ConsumeMessageContext;
import org.apache.rocketmq.broker.mqtrace.ConsumeMessageHook;
import org.apache.rocketmq.common.BrokerConfig;
@@ -126,7 +127,7 @@ public class PullMessageProcessorTest {
@Test
public void testProcessRequest_Found() throws RemotingCommandException {
GetMessageResult getMessageResult = createGetMessageResult();
- when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(SubscriptionData.class))).thenReturn(getMessageResult);
+ when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
@@ -137,7 +138,7 @@ public class PullMessageProcessorTest {
@Test
public void testProcessRequest_FoundWithHook() throws RemotingCommandException {
GetMessageResult getMessageResult = createGetMessageResult();
- when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(SubscriptionData.class))).thenReturn(getMessageResult);
+ when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
List<ConsumeMessageHook> consumeMessageHookList = new ArrayList<>();
final ConsumeMessageContext[] messageContext = new ConsumeMessageContext[1];
ConsumeMessageHook consumeMessageHook = new ConsumeMessageHook() {
@@ -168,7 +169,7 @@ public class PullMessageProcessorTest {
public void testProcessRequest_MsgWasRemoving() throws RemotingCommandException {
GetMessageResult getMessageResult = createGetMessageResult();
getMessageResult.setStatus(GetMessageStatus.MESSAGE_WAS_REMOVING);
- when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(SubscriptionData.class))).thenReturn(getMessageResult);
+ when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
@@ -180,7 +181,7 @@ public class PullMessageProcessorTest {
public void testProcessRequest_NoMsgInQueue() throws RemotingCommandException {
GetMessageResult getMessageResult = createGetMessageResult();
getMessageResult.setStatus(GetMessageStatus.NO_MESSAGE_IN_QUEUE);
- when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(SubscriptionData.class))).thenReturn(getMessageResult);
+ when(messageStore.getMessage(anyString(), anyString(), anyInt(), anyLong(), anyInt(), any(ExpressionMessageFilter.class))).thenReturn(getMessageResult);
final RemotingCommand request = createPullMsgCommand(RequestCode.PULL_MESSAGE);
RemotingCommand response = pullMessageProcessor.processRequest(handlerContext, request);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java
index 3903fe2..9c9b59e 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/DefaultMQPushConsumer.java
@@ -519,6 +519,21 @@ public class DefaultMQPushConsumer extends ClientConfig implements MQPushConsume
}
/**
+ * Subscribe a topic by message selector.
+ *
+ * @see org.apache.rocketmq.client.consumer.MessageSelector#bySql
+ * @see org.apache.rocketmq.client.consumer.MessageSelector#byTag
+ *
+ * @param topic topic to consume.
+ * @param messageSelector {@link org.apache.rocketmq.client.consumer.MessageSelector}
+ * @throws MQClientException
+ */
+ @Override
+ public void subscribe(final String topic, final MessageSelector messageSelector) throws MQClientException {
+ this.defaultMQPushConsumerImpl.subscribe(topic, messageSelector);
+ }
+
+ /**
* Un-subscribe the specified topic from subscription.
* @param topic message topic
*/
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java
index 9255281..9c6c1f1 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPushConsumer.java
@@ -70,6 +70,27 @@ public interface MQPushConsumer extends MQConsumer {
void subscribe(final String topic, final String fullClassName, final String filterClassSource) throws MQClientException;
/**
+ * Subscribe some topic with selector.
+ * <p>
+ * This interface also has the ability of {@link #subscribe(String, String)},
+ * and, support other message selection, such as {@link org.apache.rocketmq.common.filter.ExpressionType#SQL92}.
+ * </p>
+ * <p/>
+ * <p>
+ * Choose Tag: {@link MessageSelector#byTag(java.lang.String)}
+ * </p>
+ * <p/>
+ * <p>
+ * Choose SQL92: {@link MessageSelector#bySql(java.lang.String)}
+ * </p>
+ *
+ * @param topic
+ * @param selector message selector({@link MessageSelector}), can be null.
+ * @throws MQClientException
+ */
+ void subscribe(final String topic, final MessageSelector selector) throws MQClientException;
+
+ /**
* Unsubscribe consumption some topic
*
* @param topic message topic
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/consumer/MessageSelector.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/MessageSelector.java b/client/src/main/java/org/apache/rocketmq/client/consumer/MessageSelector.java
new file mode 100644
index 0000000..35a5181
--- /dev/null
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/MessageSelector.java
@@ -0,0 +1,77 @@
+/*
+ * 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.client.consumer;
+
+import org.apache.rocketmq.common.filter.ExpressionType;
+
+/**
+ *
+ * Message selector: select message at server.
+ * <p>
+ * Now, support:
+ * <li>Tag: {@link org.apache.rocketmq.common.filter.ExpressionType#TAG}
+ * </li>
+ * <li>SQL92: {@link org.apache.rocketmq.common.filter.ExpressionType#SQL92}
+ * </li>
+ * </p>
+ */
+public class MessageSelector {
+
+ /**
+ * @see org.apache.rocketmq.common.filter.ExpressionType
+ */
+ private String type;
+
+ /**
+ * expression content.
+ */
+ private String expression;
+
+ private MessageSelector(String type, String expression) {
+ this.type = type;
+ this.expression = expression;
+ }
+
+ /**
+ * Use SLQ92 to select message.
+ *
+ * @param sql if null or empty, will be treated as select all message.
+ * @return
+ */
+ public static MessageSelector bySql(String sql) {
+ return new MessageSelector(ExpressionType.SQL92, sql);
+ }
+
+ /**
+ * Use tag to select message.
+ *
+ * @param tag if null or empty or "*", will be treated as select all message.
+ * @return
+ */
+ public static MessageSelector byTag(String tag) {
+ return new MessageSelector(ExpressionType.TAG, tag);
+ }
+
+ public String getExpressionType() {
+ return type;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java b/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java
index 295060e..4367a4c 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/FindBrokerResult.java
@@ -19,10 +19,18 @@ package org.apache.rocketmq.client.impl;
public class FindBrokerResult {
private final String brokerAddr;
private final boolean slave;
+ private final int brokerVersion;
public FindBrokerResult(String brokerAddr, boolean slave) {
this.brokerAddr = brokerAddr;
this.slave = slave;
+ this.brokerVersion = 0;
+ }
+
+ public FindBrokerResult(String brokerAddr, boolean slave, int brokerVersion) {
+ this.brokerAddr = brokerAddr;
+ this.slave = slave;
+ this.brokerVersion = brokerVersion;
}
public String getBrokerAddr() {
@@ -32,4 +40,8 @@ public class FindBrokerResult {
public boolean isSlave() {
return slave;
}
+
+ public int getBrokerVersion() {
+ return brokerVersion;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
index ff25334..4244bdd 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientAPIImpl.java
@@ -59,6 +59,7 @@ import org.apache.rocketmq.common.namesrv.TopAddressing;
import org.apache.rocketmq.common.protocol.RequestCode;
import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
+import org.apache.rocketmq.common.protocol.body.CheckClientRequestBody;
import org.apache.rocketmq.common.protocol.body.ClusterInfo;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
@@ -70,6 +71,7 @@ import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody;
import org.apache.rocketmq.common.protocol.body.LockBatchResponseBody;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
import org.apache.rocketmq.common.protocol.body.QueryConsumeTimeSpanBody;
import org.apache.rocketmq.common.protocol.body.QueryCorrectionOffsetBody;
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
@@ -103,6 +105,7 @@ import org.apache.rocketmq.common.protocol.header.GetTopicStatsInfoRequestHeader
import org.apache.rocketmq.common.protocol.header.GetTopicsByClusterRequestHeader;
import org.apache.rocketmq.common.protocol.header.PullMessageRequestHeader;
import org.apache.rocketmq.common.protocol.header.PullMessageResponseHeader;
+import org.apache.rocketmq.common.protocol.header.QueryConsumeQueueRequestHeader;
import org.apache.rocketmq.common.protocol.header.QueryConsumeTimeSpanRequestHeader;
import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetRequestHeader;
import org.apache.rocketmq.common.protocol.header.QueryConsumerOffsetResponseHeader;
@@ -129,6 +132,7 @@ import org.apache.rocketmq.common.protocol.header.namesrv.PutKVConfigRequestHead
import org.apache.rocketmq.common.protocol.header.namesrv.WipeWritePermOfBrokerRequestHeader;
import org.apache.rocketmq.common.protocol.header.namesrv.WipeWritePermOfBrokerResponseHeader;
import org.apache.rocketmq.common.protocol.heartbeat.HeartbeatData;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.common.protocol.route.TopicRouteData;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.remoting.InvokeCallback;
@@ -168,7 +172,7 @@ public class MQClientAPIImpl {
public MQClientAPIImpl(final NettyClientConfig nettyClientConfig, final ClientRemotingProcessor clientRemotingProcessor,
RPCHook rpcHook, final ClientConfig clientConfig) {
this.clientConfig = clientConfig;
- topAddressing = new TopAddressing(MixAll.WS_ADDR, clientConfig.getUnitName());
+ topAddressing = new TopAddressing(MixAll.getWSAddr(), clientConfig.getUnitName());
this.remotingClient = new NettyRemotingClient(nettyClientConfig, null);
this.clientRemotingProcessor = clientRemotingProcessor;
@@ -843,7 +847,7 @@ public class MQClientAPIImpl {
this.remotingClient.invokeOneway(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), addr), request, timeoutMillis);
}
- public void sendHearbeat(//
+ public int sendHearbeat(//
final String addr, //
final HeartbeatData heartbeatData, //
final long timeoutMillis//
@@ -855,7 +859,7 @@ public class MQClientAPIImpl {
assert response != null;
switch (response.getCode()) {
case ResponseCode.SUCCESS: {
- return;
+ return response.getVersion();
}
default:
break;
@@ -2024,4 +2028,51 @@ public class MQClientAPIImpl {
return configMap;
}
+ public QueryConsumeQueueResponseBody queryConsumeQueue(final String brokerAddr, final String topic, final int queueId,
+ final long index, final int count, final String consumerGroup,
+ final long timeoutMillis) throws InterruptedException,
+ RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
+
+ QueryConsumeQueueRequestHeader requestHeader = new QueryConsumeQueueRequestHeader();
+ requestHeader.setTopic(topic);
+ requestHeader.setQueueId(queueId);
+ requestHeader.setIndex(index);
+ requestHeader.setCount(count);
+ requestHeader.setConsumerGroup(consumerGroup);
+
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.QUERY_CONSUME_QUEUE, requestHeader);
+
+ RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), brokerAddr), request, timeoutMillis);
+
+ assert response != null;
+
+ if (ResponseCode.SUCCESS == response.getCode()) {
+ return QueryConsumeQueueResponseBody.decode(response.getBody(), QueryConsumeQueueResponseBody.class);
+ }
+
+ throw new MQClientException(response.getCode(), response.getRemark());
+ }
+
+ public void checkClientInBroker(final String brokerAddr, final String consumerGroup,
+ final String clientId, final SubscriptionData subscriptionData,
+ final long timeoutMillis)
+ throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException,
+ RemotingConnectException, MQClientException {
+ RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.CHECK_CLIENT_CONFIG, null);
+
+ CheckClientRequestBody requestBody = new CheckClientRequestBody();
+ requestBody.setClientId(clientId);
+ requestBody.setGroup(consumerGroup);
+ requestBody.setSubscriptionData(subscriptionData);
+
+ request.setBody(requestBody.encode());
+
+ RemotingCommand response = this.remotingClient.invokeSync(MixAll.brokerVIPChannel(this.clientConfig.isVipChannelEnabled(), brokerAddr), request, timeoutMillis);
+
+ assert response != null;
+
+ if (ResponseCode.SUCCESS != response.getCode()) {
+ throw new MQClientException(response.getCode(), response.getRemark());
+ }
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
index 67f3ebe..2cafe29 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
@@ -30,6 +30,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.Validators;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.MessageSelector;
import org.apache.rocketmq.client.consumer.PullCallback;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.listener.MessageListener;
@@ -405,15 +406,16 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
this.pullAPIWrapper.pullKernelImpl(//
pullRequest.getMessageQueue(), // 1
subExpression, // 2
- subscriptionData.getSubVersion(), // 3
- pullRequest.getNextOffset(), // 4
- this.defaultMQPushConsumer.getPullBatchSize(), // 5
- sysFlag, // 6
- commitOffsetValue, // 7
- BROKER_SUSPEND_MAX_TIME_MILLIS, // 8
- CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND, // 9
- CommunicationMode.ASYNC, // 10
- pullCallback// 11
+ subscriptionData.getExpressionType(), // 3
+ subscriptionData.getSubVersion(), // 4
+ pullRequest.getNextOffset(), // 5
+ this.defaultMQPushConsumer.getPullBatchSize(), // 6
+ sysFlag, // 7
+ commitOffsetValue, // 8
+ BROKER_SUSPEND_MAX_TIME_MILLIS, // 9
+ CONSUMER_TIMEOUT_MILLIS_WHEN_SUSPEND, // 10
+ CommunicationMode.ASYNC, // 11
+ pullCallback // 12
);
} catch (Exception e) {
log.error("pullKernelImpl exception", e);
@@ -615,6 +617,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
this.updateTopicSubscribeInfoWhenSubscriptionChanged();
+ this.mQClientFactory.checkClientInBroker();
this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
this.mQClientFactory.rebalanceImmediately();
}
@@ -836,6 +839,25 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
}
+ public void subscribe(final String topic, final MessageSelector messageSelector) throws MQClientException {
+ try {
+ if (messageSelector == null) {
+ subscribe(topic, SubscriptionData.SUB_ALL);
+ return;
+ }
+
+ SubscriptionData subscriptionData = FilterAPI.build(topic,
+ messageSelector.getExpression(), messageSelector.getExpressionType());
+
+ this.rebalanceImpl.getSubscriptionInner().put(topic, subscriptionData);
+ if (this.mQClientFactory != null) {
+ this.mQClientFactory.sendHeartbeatToAllBrokerWithLock();
+ }
+ } catch (Exception e) {
+ throw new MQClientException("subscription exception", e);
+ }
+ }
+
public void suspend() {
this.pause = true;
log.info("suspend this consumer, {}", this.defaultMQPushConsumer.getConsumerGroup());
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
index 96e21e1..304a44a 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
@@ -33,7 +33,9 @@ import org.apache.rocketmq.client.impl.CommunicationMode;
import org.apache.rocketmq.client.impl.FindBrokerResult;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
import org.apache.rocketmq.client.log.ClientLogger;
+import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.filter.ExpressionType;
import org.apache.rocketmq.common.message.MessageAccessor;
import org.apache.rocketmq.common.message.MessageConst;
import org.apache.rocketmq.common.message.MessageDecoder;
@@ -135,6 +137,7 @@ public class PullAPIWrapper {
public PullResult pullKernelImpl(
final MessageQueue mq,
final String subExpression,
+ final String expressionType,
final long subVersion,
final long offset,
final int maxNums,
@@ -156,6 +159,14 @@ public class PullAPIWrapper {
}
if (findBrokerResult != null) {
+ {
+ // check version
+ if (!ExpressionType.isTagType(expressionType)
+ && findBrokerResult.getBrokerVersion() < MQVersion.Version.V4_1_0_SNAPSHOT.ordinal()) {
+ throw new MQClientException("The broker[" + mq.getBrokerName() + ", "
+ + findBrokerResult.getBrokerVersion() + "] does not upgrade to support for filter message by " + expressionType, null);
+ }
+ }
int sysFlagInner = sysFlag;
if (findBrokerResult.isSlave()) {
@@ -173,6 +184,7 @@ public class PullAPIWrapper {
requestHeader.setSuspendTimeoutMillis(brokerSuspendMaxTimeMillis);
requestHeader.setSubscription(subExpression);
requestHeader.setSubVersion(subVersion);
+ requestHeader.setExpressionType(expressionType);
String brokerAddr = findBrokerResult.getBrokerAddr();
if (PullSysFlag.hasClassFilterFlag(sysFlagInner)) {
@@ -192,6 +204,34 @@ public class PullAPIWrapper {
throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null);
}
+ public PullResult pullKernelImpl(
+ final MessageQueue mq,
+ final String subExpression,
+ final long subVersion,
+ final long offset,
+ final int maxNums,
+ final int sysFlag,
+ final long commitOffset,
+ final long brokerSuspendMaxTimeMillis,
+ final long timeoutMillis,
+ final CommunicationMode communicationMode,
+ final PullCallback pullCallback
+ ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
+ return pullKernelImpl(
+ mq,
+ subExpression,
+ ExpressionType.TAG,
+ subVersion, offset,
+ maxNums,
+ sysFlag,
+ commitOffset,
+ brokerSuspendMaxTimeMillis,
+ timeoutMillis,
+ communicationMode,
+ pullCallback
+ );
+ }
+
public long recalculatePullFromWhichNode(final MessageQueue mq) {
if (this.isConnectBrokerByUser()) {
return this.defaultBrokerId;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index d7e02fe..a8c65b2 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -61,6 +61,7 @@ import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.ServiceState;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.constant.PermName;
+import org.apache.rocketmq.common.filter.ExpressionType;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
@@ -98,6 +99,8 @@ public class MQClientInstance {
private final Lock lockHeartbeat = new ReentrantLock();
private final ConcurrentHashMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> brokerAddrTable =
new ConcurrentHashMap<String, HashMap<Long, String>>();
+ private final ConcurrentHashMap<String/* Broker Name */, HashMap<String/* address */, Integer>> brokerVersionTable =
+ new ConcurrentHashMap<String, HashMap<String, Integer>>();
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
@@ -404,6 +407,44 @@ public class MQClientInstance {
}
}
+ public void checkClientInBroker() throws MQClientException {
+ Iterator<Entry<String, MQConsumerInner>> it = this.consumerTable.entrySet().iterator();
+
+ while (it.hasNext()) {
+ Entry<String, MQConsumerInner> entry = it.next();
+ Set<SubscriptionData> subscriptionInner = entry.getValue().subscriptions();
+ if (subscriptionInner == null || subscriptionInner.isEmpty()) {
+ return;
+ }
+
+ for (SubscriptionData subscriptionData : subscriptionInner) {
+ if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ continue;
+ }
+ // may need to check one broker every cluster...
+ // assume that the configs of every broker in cluster are the the same.
+ String addr = findBrokerAddrByTopic(subscriptionData.getTopic());
+
+ if (addr != null) {
+ try {
+ this.getMQClientAPIImpl().checkClientInBroker(
+ addr, entry.getKey(), this.clientId, subscriptionData, 3 * 1000
+ );
+ } catch (Exception e) {
+ if (e instanceof MQClientException) {
+ throw (MQClientException) e;
+ } else {
+ throw new MQClientException("Check client in broker error, maybe because you use "
+ + subscriptionData.getExpressionType() + " to filter message, but server has not been upgraded to support!"
+ + "This error would not affect the launch of consumer, but may has impact on message receiving if you " +
+ "have use the new features which are not supported by server, please check the log!", e);
+ }
+ }
+ }
+ }
+ }
+ }
+
public void sendHeartbeatToAllBrokerWithLock() {
if (this.lockHeartbeat.tryLock()) {
try {
@@ -493,7 +534,11 @@ public class MQClientInstance {
}
try {
- this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
+ int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
+ if (!this.brokerVersionTable.containsKey(brokerName)) {
+ this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
+ }
+ this.brokerVersionTable.get(brokerName).put(addr, version);
if (times % 20 == 0) {
log.info("send heart beat to broker[{} {} {}] success", brokerName, id, addr);
log.info(heartbeatData.toString());
@@ -943,7 +988,7 @@ public class MQClientInstance {
}
if (found) {
- return new FindBrokerResult(brokerAddr, slave);
+ return new FindBrokerResult(brokerAddr, slave, findBrokerVersion(brokerName, brokerAddr));
}
return null;
@@ -982,12 +1027,21 @@ public class MQClientInstance {
}
if (found) {
- return new FindBrokerResult(brokerAddr, slave);
+ return new FindBrokerResult(brokerAddr, slave, findBrokerVersion(brokerName, brokerAddr));
}
return null;
}
+ public int findBrokerVersion(String brokerName, String brokerAddr) {
+ if (this.brokerVersionTable.containsKey(brokerName)) {
+ if (this.brokerVersionTable.get(brokerName).containsKey(brokerAddr)) {
+ return this.brokerVersionTable.get(brokerName).get(brokerAddr);
+ }
+ }
+ return 0;
+ }
+
public List<String> findConsumerIdList(final String topic, final String group) {
String brokerAddr = this.findBrokerAddrByTopic(topic);
if (null == brokerAddr) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
index f79f726..f0a73bd 100644
--- a/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
+++ b/common/src/main/java/org/apache/rocketmq/common/BrokerConfig.java
@@ -99,6 +99,25 @@ public class BrokerConfig {
private boolean traceOn = true;
+ // Switch of filter bit map calculation.
+ // If switch on:
+ // 1. Calculate filter bit map when construct queue.
+ // 2. Filter bit map will be saved to consume queue extend file if allowed.
+ private boolean enableCalcFilterBitMap = false;
+
+ // Expect num of consumers will use filter.
+ private int expectConsumerNumUseFilter = 32;
+
+ // Error rate of bloom filter, 1~100.
+ private int maxErrorRateOfBloomFilter = 20;
+
+ //how long to clean filter data after dead.Default: 24h
+ private long filterDataCleanTimeSpan = 24 * 3600 * 1000;
+
+ // whether do filter when retry.
+ private boolean filterSupportRetry = false;
+ private boolean enablePropertyFilter = false;
+
public static String localHostName() {
try {
return InetAddress.getLocalHost().getHostName();
@@ -484,4 +503,52 @@ public class BrokerConfig {
public void setCommercialBaseCount(int commercialBaseCount) {
this.commercialBaseCount = commercialBaseCount;
}
+
+ public boolean isEnableCalcFilterBitMap() {
+ return enableCalcFilterBitMap;
+ }
+
+ public void setEnableCalcFilterBitMap(boolean enableCalcFilterBitMap) {
+ this.enableCalcFilterBitMap = enableCalcFilterBitMap;
+ }
+
+ public int getExpectConsumerNumUseFilter() {
+ return expectConsumerNumUseFilter;
+ }
+
+ public void setExpectConsumerNumUseFilter(int expectConsumerNumUseFilter) {
+ this.expectConsumerNumUseFilter = expectConsumerNumUseFilter;
+ }
+
+ public int getMaxErrorRateOfBloomFilter() {
+ return maxErrorRateOfBloomFilter;
+ }
+
+ public void setMaxErrorRateOfBloomFilter(int maxErrorRateOfBloomFilter) {
+ this.maxErrorRateOfBloomFilter = maxErrorRateOfBloomFilter;
+ }
+
+ public long getFilterDataCleanTimeSpan() {
+ return filterDataCleanTimeSpan;
+ }
+
+ public void setFilterDataCleanTimeSpan(long filterDataCleanTimeSpan) {
+ this.filterDataCleanTimeSpan = filterDataCleanTimeSpan;
+ }
+
+ public boolean isFilterSupportRetry() {
+ return filterSupportRetry;
+ }
+
+ public void setFilterSupportRetry(boolean filterSupportRetry) {
+ this.filterSupportRetry = filterSupportRetry;
+ }
+
+ public boolean isEnablePropertyFilter() {
+ return enablePropertyFilter;
+ }
+
+ public void setEnablePropertyFilter(boolean enablePropertyFilter) {
+ this.enablePropertyFilter = enablePropertyFilter;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/MixAll.java b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
index 4a54a60..e75efd9 100644
--- a/common/src/main/java/org/apache/rocketmq/common/MixAll.java
+++ b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
@@ -55,8 +55,8 @@ public class MixAll {
public static final String DEFAULT_NAMESRV_ADDR_LOOKUP = "jmenv.tbsite.net";
public static final String WS_DOMAIN_NAME = System.getProperty("rocketmq.namesrv.domain", DEFAULT_NAMESRV_ADDR_LOOKUP);
public static final String WS_DOMAIN_SUBGROUP = System.getProperty("rocketmq.namesrv.domain.subgroup", "nsaddr");
- // http://jmenv.tbsite.net:8080/rocketmq/nsaddr
- public static final String WS_ADDR = "http://" + WS_DOMAIN_NAME + ":8080/rocketmq/" + WS_DOMAIN_SUBGROUP;
+// // http://jmenv.tbsite.net:8080/rocketmq/nsaddr
+// public static final String WS_ADDR = "http://" + WS_DOMAIN_NAME + ":8080/rocketmq/" + WS_DOMAIN_SUBGROUP;
public static final String DEFAULT_TOPIC = "TBW102";
public static final String BENCHMARK_TOPIC = "BenchmarkTest";
public static final String DEFAULT_PRODUCER_GROUP = "DEFAULT_PRODUCER";
@@ -89,6 +89,16 @@ public class MixAll {
public static final String DEFAULT_TRACE_REGION_ID = "DefaultRegion";
public static final String CONSUME_CONTEXT_TYPE = "ConsumeContextType";
+ public static String getWSAddr() {
+ String wsDomainName = System.getProperty("rocketmq.namesrv.domain", DEFAULT_NAMESRV_ADDR_LOOKUP);
+ String wsDomainSubgroup = System.getProperty("rocketmq.namesrv.domain.subgroup", "nsaddr");
+ String wsAddr = "http://" + wsDomainName + ":8080/rocketmq/" + wsDomainSubgroup;
+ if (wsDomainName.indexOf(":") > 0) {
+ wsAddr = "http://" + wsDomainName + "/rocketmq/" + wsDomainSubgroup;
+ }
+ return wsAddr;
+ }
+
public static String getRetryTopic(final String consumerGroup) {
return RETRY_GROUP_TOPIC_PREFIX + consumerGroup;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
index e706e28..385c121 100644
--- a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
+++ b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
@@ -34,4 +34,5 @@ public class LoggerName {
public static final String DUPLICATION_LOGGER_NAME = "RocketmqDuplication";
public static final String PROTECTION_LOGGER_NAME = "RocketmqProtection";
public static final String WATER_MARK_LOGGER_NAME = "RocketmqWaterMark";
+ public static final String FILTER_LOGGER_NAME = "RocketmqFilter";
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/filter/ExpressionType.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/filter/ExpressionType.java b/common/src/main/java/org/apache/rocketmq/common/filter/ExpressionType.java
new file mode 100644
index 0000000..3b7940a
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/filter/ExpressionType.java
@@ -0,0 +1,67 @@
+/*
+ * 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.common.filter;
+
+public class ExpressionType {
+
+ /**
+ * <ul>
+ * Keywords:
+ * <li>{@code AND, OR, NOT, BETWEEN, IN, TRUE, FALSE, IS, NULL}</li>
+ * </ul>
+ * <p/>
+ * <ul>
+ * Data type:
+ * <li>Boolean, like: TRUE, FALSE</li>
+ * <li>String, like: 'abc'</li>
+ * <li>Decimal, like: 123</li>
+ * <li>Float number, like: 3.1415</li>
+ * </ul>
+ * <p/>
+ * <ul>
+ * Grammar:
+ * <li>{@code AND, OR}</li>
+ * <li>{@code >, >=, <, <=, =}</li>
+ * <li>{@code BETWEEN A AND B}, equals to {@code >=A AND <=B}</li>
+ * <li>{@code NOT BETWEEN A AND B}, equals to {@code >B OR <A}</li>
+ * <li>{@code IN ('a', 'b')}, equals to {@code ='a' OR ='b'}, this operation only support String type.</li>
+ * <li>{@code IS NULL}, {@code IS NOT NULL}, check parameter whether is null, or not.</li>
+ * <li>{@code =TRUE}, {@code =FALSE}, check parameter whether is true, or false.</li>
+ * </ul>
+ * <p/>
+ * <p>
+ * Example:
+ * (a > 10 AND a < 100) OR (b IS NOT NULL AND b=TRUE)
+ * </p>
+ */
+ public static final String SQL92 = "SQL92";
+
+ /**
+ * Only support or operation such as
+ * "tag1 || tag2 || tag3", <br>
+ * If null or * expression,meaning subscribe all.
+ */
+ public static final String TAG = "TAG";
+
+ public static boolean isTagType(String type) {
+ if (type == null || TAG.equals(type)) {
+ return true;
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java b/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java
index e9bf3fa..fc8525c 100644
--- a/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java
+++ b/common/src/main/java/org/apache/rocketmq/common/filter/FilterAPI.java
@@ -63,4 +63,22 @@ public class FilterAPI {
return subscriptionData;
}
+
+ public static SubscriptionData build(final String topic, final String subString,
+ final String type) throws Exception {
+ if (ExpressionType.TAG.equals(type) || type == null) {
+ return buildSubscriptionData(null, topic, subString);
+ }
+
+ if (subString == null || subString.length() < 1) {
+ throw new IllegalArgumentException("Expression can't be null! " + type);
+ }
+
+ SubscriptionData subscriptionData = new SubscriptionData();
+ subscriptionData.setTopic(topic);
+ subscriptionData.setSubString(subString);
+ subscriptionData.setExpressionType(type);
+
+ return subscriptionData;
+ }
}
[39/50] [abbrv] incubator-rocketmq git commit: Remove diamond
operator for client module with JDK 1.6
Posted by do...@apache.org.
Remove diamond operator for client module with JDK 1.6
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/8d781757
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/8d781757
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/8d781757
Branch: refs/heads/release-4.1.0-incubating
Commit: 8d781757dfb56ebd95b0494e8e2c87422c22d767
Parents: e57f9ac
Author: dongeforever <zh...@yeah.net>
Authored: Sat May 27 14:09:08 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 14:09:08 2017 +0800
----------------------------------------------------------------------
.../AllocateMessageQueueConsistentHash.java | 8 +++---
.../AllocateMessageQueueConsitentHashTest.java | 27 ++++++++++----------
.../consistenthash/ConsistentHashRouter.java | 4 +--
.../org/apache/rocketmq/store/CommitLog.java | 4 +--
4 files changed, 22 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8d781757/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
index 77198b7..09d940a 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsistentHash.java
@@ -76,19 +76,19 @@ public class AllocateMessageQueueConsistentHash implements AllocateMessageQueue
}
- Collection<ClientNode> cidNodes = new ArrayList<>();
+ Collection<ClientNode> cidNodes = new ArrayList<ClientNode>();
for (String cid : cidAll) {
cidNodes.add(new ClientNode(cid));
}
final ConsistentHashRouter<ClientNode> router; //for building hash ring
if (customHashFunction != null) {
- router = new ConsistentHashRouter<>(cidNodes, virtualNodeCnt, customHashFunction);
+ router = new ConsistentHashRouter<ClientNode>(cidNodes, virtualNodeCnt, customHashFunction);
} else {
- router = new ConsistentHashRouter<>(cidNodes, virtualNodeCnt);
+ router = new ConsistentHashRouter<ClientNode>(cidNodes, virtualNodeCnt);
}
- List<MessageQueue> results = new ArrayList<>();
+ List<MessageQueue> results = new ArrayList<MessageQueue>();
for (MessageQueue mq : mqAll) {
ClientNode clientNode = router.routeNode(mq.toString());
if (clientNode != null && currentCID.equals(clientNode.getKey())) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8d781757/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java b/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
index fc7ab9f..e9e5db7 100644
--- a/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
+++ b/client/src/test/java/org/apache/rocketmq/client/consumer/rebalance/AllocateMessageQueueConsitentHashTest.java
@@ -23,6 +23,7 @@ import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy;
+import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.junit.Assert;
import org.junit.Before;
@@ -113,13 +114,13 @@ public class AllocateMessageQueueConsitentHashTest {
//System.out.println("mqAll:" + mqAll.toString());
List<String> cidAll = createConsumerIdList(consumerSize);
- List<MessageQueue> allocatedResAll = new ArrayList<>();
+ List<MessageQueue> allocatedResAll = new ArrayList<MessageQueue>();
- Map<MessageQueue, String> allocateToAllOrigin = new TreeMap<>();
+ Map<MessageQueue, String> allocateToAllOrigin = new TreeMap<MessageQueue, String>();
//test allocate all
{
- List<String> cidBegin = new ArrayList<>(cidAll);
+ List<String> cidBegin = new ArrayList<String>(cidAll);
//System.out.println("cidAll:" + cidBegin.toString());
for (String cid : cidBegin) {
@@ -135,13 +136,13 @@ public class AllocateMessageQueueConsitentHashTest {
verifyAllocateAll(cidBegin,mqAll, allocatedResAll));
}
- Map<MessageQueue, String> allocateToAllAfterRemoveOne = new TreeMap<>();
- List<String> cidAfterRemoveOne = new ArrayList<>(cidAll);
+ Map<MessageQueue, String> allocateToAllAfterRemoveOne = new TreeMap<MessageQueue, String>();
+ List<String> cidAfterRemoveOne = new ArrayList<String>(cidAll);
//test allocate remove one cid
{
String removeCID = cidAfterRemoveOne.remove(0);
//System.out.println("removing one cid "+removeCID);
- List<MessageQueue> mqShouldOnlyChanged = new ArrayList<>();
+ List<MessageQueue> mqShouldOnlyChanged = new ArrayList<MessageQueue>();
Iterator<Map.Entry<MessageQueue, String>> it = allocateToAllOrigin.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<MessageQueue, String> entry = it.next();
@@ -151,7 +152,7 @@ public class AllocateMessageQueueConsitentHashTest {
}
//System.out.println("cidAll:" + cidAfterRemoveOne.toString());
- List<MessageQueue> allocatedResAllAfterRemove = new ArrayList<>();
+ List<MessageQueue> allocatedResAllAfterRemove = new ArrayList<MessageQueue>();
for (String cid : cidAfterRemoveOne) {
List<MessageQueue> rs = allocateMessageQueueConsistentHash.allocate("testConsumerGroup", cid, mqAll, cidAfterRemoveOne);
allocatedResAllAfterRemove.addAll(rs);
@@ -166,16 +167,16 @@ public class AllocateMessageQueueConsitentHashTest {
verifyAfterRemove(allocateToAllOrigin, allocateToAllAfterRemoveOne, removeCID);
}
- List<String> cidAfterAdd = new ArrayList<>(cidAfterRemoveOne);
+ List<String> cidAfterAdd = new ArrayList<String>(cidAfterRemoveOne);
//test allocate add one more cid
{
String newCid = CID_PREFIX+"NEW";
//System.out.println("add one more cid "+newCid);
cidAfterAdd.add(newCid);
- List<MessageQueue> mqShouldOnlyChanged = new ArrayList<>();
+ List<MessageQueue> mqShouldOnlyChanged = new ArrayList<MessageQueue>();
//System.out.println("cidAll:" + cidAfterAdd.toString());
- List<MessageQueue> allocatedResAllAfterAdd = new ArrayList<>();
- Map<MessageQueue, String> allocateToAll3 = new TreeMap<>();
+ List<MessageQueue> allocatedResAllAfterAdd = new ArrayList<MessageQueue>();
+ Map<MessageQueue, String> allocateToAll3 = new TreeMap<MessageQueue, String>();
for (String cid : cidAfterAdd) {
List<MessageQueue> rs = allocateMessageQueueConsistentHash.allocate("testConsumerGroup", cid, mqAll, cidAfterAdd);
allocatedResAllAfterAdd.addAll(rs);
@@ -225,7 +226,7 @@ public class AllocateMessageQueueConsitentHashTest {
}
private List<String> createConsumerIdList(int size) {
- List<String> consumerIdList = new ArrayList<>(size);
+ List<String> consumerIdList = new ArrayList<String>(size);
for (int i = 0; i < size; i++) {
consumerIdList.add(CID_PREFIX + String.valueOf(i));
}
@@ -233,7 +234,7 @@ public class AllocateMessageQueueConsitentHashTest {
}
private List<MessageQueue> createMessageQueueList(int size) {
- List<MessageQueue> messageQueueList = new ArrayList<>(size);
+ List<MessageQueue> messageQueueList = new ArrayList<MessageQueue>(size);
for (int i = 0; i < size; i++) {
MessageQueue mq = new MessageQueue(topic, "brokerName", i);
messageQueueList.add(mq);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8d781757/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java b/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
index 8606c43..a6fce51 100644
--- a/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
+++ b/common/src/main/java/org/apache/rocketmq/common/consistenthash/ConsistentHashRouter.java
@@ -30,7 +30,7 @@ import java.util.TreeMap;
* @param <T>
*/
public class ConsistentHashRouter<T extends Node> {
- private final SortedMap<Long, VirtualNode<T>> ring = new TreeMap<>();
+ private final SortedMap<Long, VirtualNode<T>> ring = new TreeMap<Long, VirtualNode<T>>();
private final HashFunction hashFunction;
public ConsistentHashRouter(Collection<T> pNodes, int vNodeCount) {
@@ -64,7 +64,7 @@ public class ConsistentHashRouter<T extends Node> {
if (vNodeCount < 0) throw new IllegalArgumentException("illegal virtual node counts :" + vNodeCount);
int existingReplicas = getExistingReplicas(pNode);
for (int i = 0; i < vNodeCount; i++) {
- VirtualNode<T> vNode = new VirtualNode<>(pNode, i + existingReplicas);
+ VirtualNode<T> vNode = new VirtualNode<T>(pNode, i + existingReplicas);
ring.put(hashFunction.hash(vNode.getKey()), vNode);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/8d781757/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
index 7b29263..b44211c 100644
--- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
+++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
@@ -722,7 +722,7 @@ public class CommitLog {
messageExtBatch.setEncodedBuff(batchEncoder.encode(messageExtBatch));
- lockForPutMessage(); //spin...
+ putMessageLock.lock();
try {
long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now();
this.beginTimeInLock = beginLockTimestamp;
@@ -771,7 +771,7 @@ public class CommitLog {
eclipseTimeInLock = this.defaultMessageStore.getSystemClock().now() - beginLockTimestamp;
beginTimeInLock = 0;
} finally {
- releasePutMessageLock();
+ putMessageLock.unlock();
}
[05/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java b/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java
index 33529da..3d33eaf 100644
--- a/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java
+++ b/store/src/main/java/org/apache/rocketmq/store/DispatchRequest.java
@@ -16,6 +16,8 @@
*/
package org.apache.rocketmq.store;
+import java.util.Map;
+
public class DispatchRequest {
private final String topic;
private final int queueId;
@@ -30,6 +32,8 @@ public class DispatchRequest {
private final int sysFlag;
private final long preparedTransactionOffset;
+ private final Map<String, String> propertiesMap;
+ private byte[] bitMap;
public DispatchRequest(
final String topic,
@@ -42,7 +46,8 @@ public class DispatchRequest {
final String keys,
final String uniqKey,
final int sysFlag,
- final long preparedTransactionOffset
+ final long preparedTransactionOffset,
+ final Map<String, String> propertiesMap
) {
this.topic = topic;
this.queueId = queueId;
@@ -57,6 +62,7 @@ public class DispatchRequest {
this.sysFlag = sysFlag;
this.preparedTransactionOffset = preparedTransactionOffset;
this.success = true;
+ this.propertiesMap = propertiesMap;
}
public DispatchRequest(int size) {
@@ -81,6 +87,7 @@ public class DispatchRequest {
this.sysFlag = 0;
this.preparedTransactionOffset = 0;
this.success = false;
+ this.propertiesMap = null;
}
public DispatchRequest(int size, boolean success) {
@@ -105,6 +112,7 @@ public class DispatchRequest {
this.sysFlag = 0;
this.preparedTransactionOffset = 0;
this.success = success;
+ this.propertiesMap = null;
}
public String getTopic() {
@@ -155,4 +163,15 @@ public class DispatchRequest {
return uniqKey;
}
+ public Map<String, String> getPropertiesMap() {
+ return propertiesMap;
+ }
+
+ public byte[] getBitMap() {
+ return bitMap;
+ }
+
+ public void setBitMap(byte[] bitMap) {
+ this.bitMap = bitMap;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java
index 550e578..a9a00a8 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MappedFile.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MappedFile.java
@@ -245,6 +245,31 @@ public class MappedFile extends ReferenceResource {
}
/**
+ * Content of data from offset to offset + length will be wrote to file.
+ *
+ * @param data
+ * @param offset The offset of the subarray to be used.
+ * @param length The length of the subarray to be used.
+ * @return
+ */
+ public boolean appendMessage(final byte[] data, final int offset, final int length) {
+ int currentPos = this.wrotePosition.get();
+
+ if ((currentPos + length) <= this.fileSize) {
+ try {
+ this.fileChannel.position(currentPos);
+ this.fileChannel.write(ByteBuffer.wrap(data, offset, length));
+ } catch (Throwable e) {
+ log.error("Error occurred when append message to mappedFile.", e);
+ }
+ this.wrotePosition.addAndGet(length);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* @param flushLeastPages
* @return The current flushed position
*/
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java
index 5c6c62c..a8fa364 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MappedFileQueue.java
@@ -121,7 +121,7 @@ public class MappedFileQueue {
this.deleteExpiredFile(willRemoveFiles);
}
- private void deleteExpiredFile(List<MappedFile> files) {
+ void deleteExpiredFile(List<MappedFile> files) {
if (!files.isEmpty()) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/MessageArrivingListener.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MessageArrivingListener.java b/store/src/main/java/org/apache/rocketmq/store/MessageArrivingListener.java
index 2523c1a..dee1bc7 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MessageArrivingListener.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MessageArrivingListener.java
@@ -17,6 +17,9 @@
package org.apache.rocketmq.store;
+import java.util.Map;
+
public interface MessageArrivingListener {
- void arriving(String topic, int queueId, long logicOffset, long tagsCode);
+ void arriving(String topic, int queueId, long logicOffset, long tagsCode,
+ long msgStoreTime, byte[] filterBitMap, Map<String, String> properties);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java b/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java
index 859ce99..6b34758 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MessageFilter.java
@@ -16,8 +16,30 @@
*/
package org.apache.rocketmq.store;
-import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import java.nio.ByteBuffer;
+import java.util.Map;
public interface MessageFilter {
- boolean isMessageMatched(final SubscriptionData subscriptionData, final Long tagsCode);
+ /**
+ * match by tags code or filter bit map which is calculated when message received
+ * and stored in consume queue ext.
+ *
+ * @param tagsCode tagsCode
+ * @param cqExtUnit extend unit of consume queue
+ * @return
+ */
+ boolean isMatchedByConsumeQueue(final Long tagsCode,
+ final ConsumeQueueExt.CqExtUnit cqExtUnit);
+
+ /**
+ * match by message content which are stored in commit log.
+ * <br>{@code msgBuffer} and {@code properties} are not all null.If invoked in store,
+ * {@code properties} is null;If invoked in {@code PullRequestHoldService}, {@code msgBuffer} is null.
+ *
+ * @param msgBuffer message buffer in commit log, may be null if not invoked in store.
+ * @param properties message properties, should decode from buffer if null by yourself.
+ * @return
+ */
+ boolean isMatchedByCommitLog(final ByteBuffer msgBuffer,
+ final Map<String, String> properties);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MessageStore.java b/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
index 65c546b..e841c08 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
@@ -17,10 +17,10 @@
package org.apache.rocketmq.store;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Set;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageExtBatch;
-import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
public interface MessageStore {
@@ -37,7 +37,7 @@ public interface MessageStore {
PutMessageResult putMessages(final MessageExtBatch messageExtBatch);
GetMessageResult getMessage(final String group, final String topic, final int queueId,
- final long offset, final int maxMsgNums, final SubscriptionData subscriptionData);
+ final long offset, final int maxMsgNums, final MessageFilter messageFilter);
long getMaxOffsetInQuque(final String topic, final int queueId);
@@ -105,4 +105,8 @@ public interface MessageStore {
long lockTimeMills();
boolean isTransientStorePoolDeficient();
+
+ LinkedList<CommitLogDispatcher> getDispatcherList();
+
+ ConsumeQueue getConsumeQueue(String topic, int queueId);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
index 7ae2ab5..29f800c 100644
--- a/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
+++ b/store/src/main/java/org/apache/rocketmq/store/config/MessageStoreConfig.java
@@ -34,6 +34,13 @@ public class MessageStoreConfig {
private int mapedFileSizeCommitLog = 1024 * 1024 * 1024;
// ConsumeQueue file size,default is 30W
private int mapedFileSizeConsumeQueue = 300000 * ConsumeQueue.CQ_STORE_UNIT_SIZE;
+ // enable consume queue ext
+ private boolean enableConsumeQueueExt = false;
+ // ConsumeQueue extend file size, 48M
+ private int mappedFileSizeConsumeQueueExt = 48 * 1024 * 1024;
+ // Bit count of filter bit map.
+ // this will be set by pipe of calculate filter bit map.
+ private int bitMapLengthConsumeQueueExt = 64;
// CommitLog flush interval
// flush data to disk
@@ -191,6 +198,30 @@ public class MessageStoreConfig {
this.mapedFileSizeConsumeQueue = mapedFileSizeConsumeQueue;
}
+ public boolean isEnableConsumeQueueExt() {
+ return enableConsumeQueueExt;
+ }
+
+ public void setEnableConsumeQueueExt(boolean enableConsumeQueueExt) {
+ this.enableConsumeQueueExt = enableConsumeQueueExt;
+ }
+
+ public int getMappedFileSizeConsumeQueueExt() {
+ return mappedFileSizeConsumeQueueExt;
+ }
+
+ public void setMappedFileSizeConsumeQueueExt(int mappedFileSizeConsumeQueueExt) {
+ this.mappedFileSizeConsumeQueueExt = mappedFileSizeConsumeQueueExt;
+ }
+
+ public int getBitMapLengthConsumeQueueExt() {
+ return bitMapLengthConsumeQueueExt;
+ }
+
+ public void setBitMapLengthConsumeQueueExt(int bitMapLengthConsumeQueueExt) {
+ this.bitMapLengthConsumeQueueExt = bitMapLengthConsumeQueueExt;
+ }
+
public int getFlushIntervalCommitLog() {
return flushIntervalCommitLog;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/config/StorePathConfigHelper.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/config/StorePathConfigHelper.java b/store/src/main/java/org/apache/rocketmq/store/config/StorePathConfigHelper.java
index aebebaf..ef1d670 100644
--- a/store/src/main/java/org/apache/rocketmq/store/config/StorePathConfigHelper.java
+++ b/store/src/main/java/org/apache/rocketmq/store/config/StorePathConfigHelper.java
@@ -24,6 +24,10 @@ public class StorePathConfigHelper {
return rootDir + File.separator + "consumequeue";
}
+ public static String getStorePathConsumeQueueExt(final String rootDir) {
+ return rootDir + File.separator + "consumequeue_ext";
+ }
+
public static String getStorePathIndex(final String rootDir) {
return rootDir + File.separator + "index";
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
index e08a6f5..d45b994 100644
--- a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
+++ b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
@@ -32,6 +32,7 @@ import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.running.RunningStats;
import org.apache.rocketmq.store.ConsumeQueue;
+import org.apache.rocketmq.store.ConsumeQueueExt;
import org.apache.rocketmq.store.DefaultMessageStore;
import org.apache.rocketmq.store.MessageExtBrokerInner;
import org.apache.rocketmq.store.PutMessageResult;
@@ -248,11 +249,24 @@ public class ScheduleMessageService extends ConfigManager {
try {
long nextOffset = offset;
int i = 0;
+ ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit();
for (; i < bufferCQ.getSize(); i += ConsumeQueue.CQ_STORE_UNIT_SIZE) {
long offsetPy = bufferCQ.getByteBuffer().getLong();
int sizePy = bufferCQ.getByteBuffer().getInt();
long tagsCode = bufferCQ.getByteBuffer().getLong();
+ if (cq.isExtAddr(tagsCode)) {
+ if (cq.getExt(tagsCode, cqExtUnit)) {
+ tagsCode = cqExtUnit.getTagsCode();
+ } else {
+ //can't find ext content.So re compute tags code.
+ log.error("[BUG] can't find consume queue extend file content!addr={}, offsetPy={}, sizePy={}",
+ tagsCode, offsetPy, sizePy);
+ long msgStoreTime = defaultMessageStore.getCommitLog().pickupStoreTimestamp(offsetPy, sizePy);
+ tagsCode = computeDeliverTimestamp(delayLevel, msgStoreTime);
+ }
+ }
+
long now = System.currentTimeMillis();
long deliverTimestamp = this.correctDeliverTimestamp(now, tagsCode);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueExtTest.java
----------------------------------------------------------------------
diff --git a/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueExtTest.java b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueExtTest.java
new file mode 100644
index 0000000..5dbc584
--- /dev/null
+++ b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueExtTest.java
@@ -0,0 +1,251 @@
+/*
+ * 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.store;
+
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Random;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConsumeQueueExtTest {
+
+ private static final String topic = "abc";
+ private static final int queueId = 0;
+ private static final String storePath = "." + File.separator + "unit_test_store";
+ private static final int bitMapLength = 64;
+ private static final int unitSizeWithBitMap = ConsumeQueueExt.CqExtUnit.MIN_EXT_UNIT_SIZE + bitMapLength / Byte.SIZE;
+ private static final int cqExtFileSize = 10 * unitSizeWithBitMap;
+ private static final int unitCount = 20;
+
+
+ protected ConsumeQueueExt genExt() {
+ return new ConsumeQueueExt(
+ topic, queueId, storePath, cqExtFileSize, bitMapLength
+ );
+ }
+
+ protected byte[] genBitMap(int bitMapLength) {
+ byte[] bytes = new byte[bitMapLength / Byte.SIZE];
+
+ Random random = new Random(System.currentTimeMillis());
+ random.nextBytes(bytes);
+
+ return bytes;
+ }
+
+ protected ConsumeQueueExt.CqExtUnit genUnit(boolean hasBitMap) {
+ ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit();
+
+ cqExtUnit.setTagsCode(Math.abs((new Random(System.currentTimeMillis())).nextInt()));
+ cqExtUnit.setMsgStoreTime(System.currentTimeMillis());
+ if (hasBitMap) {
+ cqExtUnit.setFilterBitMap(genBitMap(bitMapLength));
+ }
+
+ return cqExtUnit;
+ }
+
+ protected void deleteDirectory(String rootPath) {
+ File file = new File(rootPath);
+ deleteFile(file);
+ }
+
+ protected void deleteFile(File file) {
+ File[] subFiles = file.listFiles();
+ if (subFiles != null) {
+ for (File sub : subFiles) {
+ deleteFile(sub);
+ }
+ }
+
+ file.delete();
+ }
+
+ protected void putSth(ConsumeQueueExt consumeQueueExt, boolean getAfterPut,
+ boolean unitSameSize, int unitCount) {
+ for (int i = 0; i < unitCount; i++) {
+ ConsumeQueueExt.CqExtUnit putUnit =
+ unitSameSize ? genUnit(true) : genUnit(i % 2 == 0);
+
+ long addr = consumeQueueExt.put(putUnit);
+ assertThat(addr).isLessThan(0);
+
+ if (getAfterPut) {
+ ConsumeQueueExt.CqExtUnit getUnit = consumeQueueExt.get(addr);
+
+ assertThat(getUnit).isNotNull();
+ assertThat(putUnit).isEqualTo(getUnit);
+ }
+
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ assertThat(false).isTrue();
+ }
+ }
+ }
+
+ @Test
+ public void testPut() {
+ ConsumeQueueExt consumeQueueExt = genExt();
+
+ try {
+ putSth(consumeQueueExt, true, false, unitCount);
+ } finally {
+ consumeQueueExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testGet() {
+ ConsumeQueueExt consumeQueueExt = genExt();
+
+ putSth(consumeQueueExt, false, false, unitCount);
+
+ try {
+ // from start.
+ long addr = consumeQueueExt.decorate(0);
+
+ ConsumeQueueExt.CqExtUnit unit = new ConsumeQueueExt.CqExtUnit();
+ while (true) {
+ boolean ret = consumeQueueExt.get(addr, unit);
+
+ if (!ret) {
+ break;
+ }
+
+ assertThat(unit.getSize()).isGreaterThanOrEqualTo(ConsumeQueueExt.CqExtUnit.MIN_EXT_UNIT_SIZE);
+
+ addr += unit.getSize();
+ }
+ } finally {
+ consumeQueueExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testGet_invalidAddress() {
+ ConsumeQueueExt consumeQueueExt = genExt();
+
+ putSth(consumeQueueExt, false, true, unitCount);
+
+ try {
+ ConsumeQueueExt.CqExtUnit unit = consumeQueueExt.get(0);
+
+ assertThat(unit).isNull();
+
+ long addr = (cqExtFileSize / unitSizeWithBitMap) * unitSizeWithBitMap;
+ addr += unitSizeWithBitMap;
+
+ unit = consumeQueueExt.get(addr);
+ assertThat(unit).isNull();
+ } finally {
+ consumeQueueExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testRecovery() {
+ ConsumeQueueExt putCqExt = genExt();
+
+ putSth(putCqExt, false, true, unitCount);
+
+ ConsumeQueueExt loadCqExt = genExt();
+
+ loadCqExt.load();
+
+ loadCqExt.recover();
+
+ try {
+ assertThat(loadCqExt.getMinAddress()).isEqualTo(Long.MIN_VALUE);
+
+ // same unit size.
+ int countPerFile = (cqExtFileSize - ConsumeQueueExt.END_BLANK_DATA_LENGTH) / unitSizeWithBitMap;
+
+ int lastFileUnitCount = unitCount % countPerFile;
+
+ int fileCount = unitCount / countPerFile + 1;
+ if (lastFileUnitCount == 0) {
+ fileCount -= 1;
+ }
+
+ if (lastFileUnitCount == 0) {
+ assertThat(loadCqExt.unDecorate(loadCqExt.getMaxAddress()) % cqExtFileSize).isEqualTo(0);
+ } else {
+ assertThat(loadCqExt.unDecorate(loadCqExt.getMaxAddress()))
+ .isEqualTo(lastFileUnitCount * unitSizeWithBitMap + (fileCount - 1) * cqExtFileSize);
+ }
+ } finally {
+ putCqExt.destroy();
+ loadCqExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testTruncateByMinOffset() {
+ ConsumeQueueExt consumeQueueExt = genExt();
+
+ putSth(consumeQueueExt, false, true, unitCount * 2);
+
+ try {
+ // truncate first one file.
+ long address = consumeQueueExt.decorate((long) (cqExtFileSize * 1.5));
+
+ long expectMinAddress = consumeQueueExt.decorate(cqExtFileSize);
+
+ consumeQueueExt.truncateByMinAddress(address);
+
+ long minAddress = consumeQueueExt.getMinAddress();
+
+ assertThat(expectMinAddress).isEqualTo(minAddress);
+ } finally {
+ consumeQueueExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+
+ @Test
+ public void testTruncateByMaxOffset() {
+ ConsumeQueueExt consumeQueueExt = genExt();
+
+ putSth(consumeQueueExt, false, true, unitCount * 2);
+
+ try {
+ // truncate, only first 3 files exist.
+ long address = consumeQueueExt.decorate(cqExtFileSize * 2 + unitSizeWithBitMap);
+
+ long expectMaxAddress = address + unitSizeWithBitMap;
+
+ consumeQueueExt.truncateByMaxAddress(address);
+
+ long maxAddress = consumeQueueExt.getMaxAddress();
+
+ assertThat(expectMaxAddress).isEqualTo(maxAddress);
+ } finally {
+ consumeQueueExt.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueTest.java
----------------------------------------------------------------------
diff --git a/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueTest.java b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueTest.java
new file mode 100644
index 0000000..9c42fb9
--- /dev/null
+++ b/store/src/test/java/org/apache/rocketmq/store/ConsumeQueueTest.java
@@ -0,0 +1,226 @@
+/*
+ * 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.store;
+
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.apache.rocketmq.store.stats.BrokerStatsManager;
+import org.junit.Test;
+
+import java.io.File;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConsumeQueueTest {
+
+ private static final String msg = "Once, there was a chance for me!";
+ private static final byte[] msgBody = msg.getBytes();
+
+ private static final String topic = "abc";
+ private static final int queueId = 0;
+ private static final String storePath = "." + File.separator + "unit_test_store";
+ private static final int commitLogFileSize = 1024 * 8;
+ private static final int cqFileSize = 10 * 20;
+ private static final int cqExtFileSize = 10 * (ConsumeQueueExt.CqExtUnit.MIN_EXT_UNIT_SIZE + 64);
+
+ private static SocketAddress BornHost;
+
+ private static SocketAddress StoreHost;
+
+ static {
+ try {
+ StoreHost = new InetSocketAddress(InetAddress.getLocalHost(), 8123);
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ try {
+ BornHost = new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0);
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public MessageExtBrokerInner buildMessage() {
+ MessageExtBrokerInner msg = new MessageExtBrokerInner();
+ msg.setTopic(topic);
+ msg.setTags("TAG1");
+ msg.setKeys("Hello");
+ msg.setBody(msgBody);
+ msg.setKeys(String.valueOf(System.currentTimeMillis()));
+ msg.setQueueId(queueId);
+ msg.setSysFlag(0);
+ msg.setBornTimestamp(System.currentTimeMillis());
+ msg.setStoreHost(StoreHost);
+ msg.setBornHost(BornHost);
+ for (int i = 0; i < 1; i++) {
+ msg.putUserProperty(String.valueOf(i), "imagoodperson" + i);
+ }
+ msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));
+
+ return msg;
+ }
+
+
+ public MessageStoreConfig buildStoreConfig(int commitLogFileSize, int cqFileSize,
+ boolean enableCqExt, int cqExtFileSize) {
+ MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
+ messageStoreConfig.setMapedFileSizeCommitLog(commitLogFileSize);
+ messageStoreConfig.setMapedFileSizeConsumeQueue(cqFileSize);
+ messageStoreConfig.setMappedFileSizeConsumeQueueExt(cqExtFileSize);
+ messageStoreConfig.setMessageIndexEnable(false);
+ messageStoreConfig.setEnableConsumeQueueExt(enableCqExt);
+
+ messageStoreConfig.setStorePathRootDir(storePath);
+ messageStoreConfig.setStorePathCommitLog(storePath + File.separator + "commitlog");
+
+ return messageStoreConfig;
+ }
+
+ protected DefaultMessageStore gen() throws Exception {
+ MessageStoreConfig messageStoreConfig = buildStoreConfig(
+ commitLogFileSize, cqFileSize, true, cqExtFileSize
+ );
+
+ BrokerConfig brokerConfig = new BrokerConfig();
+
+ DefaultMessageStore master = new DefaultMessageStore(
+ messageStoreConfig,
+ new BrokerStatsManager(brokerConfig.getBrokerClusterName()),
+ new MessageArrivingListener() {
+ @Override
+ public void arriving(String topic, int queueId, long logicOffset, long tagsCode,
+ long msgStoreTime, byte[] filterBitMap, Map<String, String> properties) {
+ }
+ }
+ , brokerConfig);
+
+ assertThat(master.load()).isTrue();
+
+ master.start();
+
+ return master;
+ }
+
+ protected void putMsg(DefaultMessageStore master) throws Exception {
+ long totalMsgs = 200;
+
+ for (long i = 0; i < totalMsgs; i++) {
+ master.putMessage(buildMessage());
+ }
+ }
+
+ protected void deleteDirectory(String rootPath) {
+ File file = new File(rootPath);
+ deleteFile(file);
+ }
+
+ protected void deleteFile(File file) {
+ File[] subFiles = file.listFiles();
+ if (subFiles != null) {
+ for (File sub : subFiles) {
+ deleteFile(sub);
+ }
+ }
+
+ file.delete();
+ }
+
+ @Test
+ public void testConsumeQueueWithExtendData() {
+ DefaultMessageStore master = null;
+ try {
+ master = gen();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ master.getDispatcherList().addFirst(new CommitLogDispatcher() {
+
+ @Override
+ public void dispatch(DispatchRequest request) {
+ runCount++;
+ }
+
+ private int runCount = 0;
+ });
+
+ try {
+ try {
+ putMsg(master);
+ // wait build consume queue
+ Thread.sleep(1000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ ConsumeQueue cq = master.getConsumeQueueTable().get(topic).get(queueId);
+
+ assertThat(cq).isNotNull();
+
+ long index = 0;
+
+ while (index < cq.getMaxOffsetInQueue()) {
+ SelectMappedBufferResult bufferResult = cq.getIndexBuffer(index);
+
+ assertThat(bufferResult).isNotNull();
+
+ ByteBuffer buffer = bufferResult.getByteBuffer();
+
+ assertThat(buffer).isNotNull();
+ try {
+ ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit();
+ for (int i = 0; i < bufferResult.getSize(); i += ConsumeQueue.CQ_STORE_UNIT_SIZE) {
+ long phyOffset = buffer.getLong();
+ int size = buffer.getInt();
+ long tagsCode = buffer.getLong();
+
+ assertThat(phyOffset).isGreaterThanOrEqualTo(0);
+ assertThat(size).isGreaterThan(0);
+ assertThat(tagsCode).isLessThan(0);
+
+ boolean ret = cq.getExt(tagsCode, cqExtUnit);
+
+ assertThat(ret).isTrue();
+ assertThat(cqExtUnit).isNotNull();
+ assertThat(cqExtUnit.getSize()).isGreaterThan((short) 0);
+ assertThat(cqExtUnit.getMsgStoreTime()).isGreaterThan(0);
+ assertThat(cqExtUnit.getTagsCode()).isGreaterThan(0);
+ }
+
+ } finally {
+ bufferResult.release();
+ }
+
+ index += cqFileSize / ConsumeQueue.CQ_STORE_UNIT_SIZE;
+ }
+ } finally {
+ master.shutdown();
+ master.destroy();
+ deleteDirectory(storePath);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/test/java/org/apache/rocketmq/store/DefaultMessageStoreTest.java
----------------------------------------------------------------------
diff --git a/store/src/test/java/org/apache/rocketmq/store/DefaultMessageStoreTest.java b/store/src/test/java/org/apache/rocketmq/store/DefaultMessageStoreTest.java
index 5c9c46f..75f1de9 100644
--- a/store/src/test/java/org/apache/rocketmq/store/DefaultMessageStoreTest.java
+++ b/store/src/test/java/org/apache/rocketmq/store/DefaultMessageStoreTest.java
@@ -20,6 +20,7 @@ package org.apache.rocketmq.store;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.rocketmq.common.BrokerConfig;
import org.apache.rocketmq.store.config.FlushDiskType;
@@ -124,7 +125,8 @@ public class DefaultMessageStoreTest {
private class MyMessageArrivingListener implements MessageArrivingListener {
@Override
- public void arriving(String topic, int queueId, long logicOffset, long tagsCode) {
+ public void arriving(String topic, int queueId, long logicOffset, long tagsCode, long msgStoreTime,
+ byte[] filterBitMap, Map<String, String> properties) {
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java
----------------------------------------------------------------------
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java
index 19bff89..409ea33 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExt.java
@@ -41,6 +41,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
@@ -469,4 +470,12 @@ public class DefaultMQAdminExt extends ClientConfig implements MQAdminExt {
UnsupportedEncodingException {
return this.defaultMQAdminExtImpl.getNameServerConfig(nameServers);
}
+
+ @Override
+ public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic, int queueId, long index, int count, String consumerGroup)
+ throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
+ return this.defaultMQAdminExtImpl.queryConsumeQueue(
+ brokerAddr, topic, queueId, index, count, consumerGroup
+ );
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
----------------------------------------------------------------------
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
index a31b69d..157ae21 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/DefaultMQAdminExtImpl.java
@@ -63,6 +63,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
@@ -955,4 +956,11 @@ public class DefaultMQAdminExtImpl implements MQAdminExt, MQAdminExtInner {
return this.mqClientInstance.getMQClientAPIImpl().getNameServerConfig(nameServers, timeoutMillis);
}
+ @Override
+ public QueryConsumeQueueResponseBody queryConsumeQueue(String brokerAddr, String topic, int queueId, long index, int count, String consumerGroup)
+ throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException {
+ return this.mqClientInstance.getMQClientAPIImpl().queryConsumeQueue(
+ brokerAddr, topic, queueId, index, count, consumerGroup, timeoutMillis
+ );
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java
----------------------------------------------------------------------
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java b/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java
index 493cf54..82add92 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/admin/MQAdminExt.java
@@ -39,6 +39,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumerRunningInfo;
import org.apache.rocketmq.common.protocol.body.GroupList;
import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
import org.apache.rocketmq.common.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.common.protocol.body.TopicConfigSerializeWrapper;
@@ -241,4 +242,25 @@ public interface MQAdminExt extends MQAdmin {
Map<String, Properties> getNameServerConfig(final List<String> nameServers) throws InterruptedException,
RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException,
MQClientException, UnsupportedEncodingException;
+
+ /**
+ * query consume queue data
+ *
+ * @param brokerAddr broker ip address
+ * @param topic topic
+ * @param queueId id of queue
+ * @param index start offset
+ * @param count how many
+ * @param consumerGroup group
+ * @return
+ * @throws InterruptedException
+ * @throws RemotingTimeoutException
+ * @throws RemotingSendRequestException
+ * @throws RemotingConnectException
+ * @throws MQClientException
+ */
+ QueryConsumeQueueResponseBody queryConsumeQueue(final String brokerAddr,
+ final String topic, final int queueId,
+ final long index, final int count, final String consumerGroup)
+ throws InterruptedException, RemotingTimeoutException, RemotingSendRequestException, RemotingConnectException, MQClientException;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java
----------------------------------------------------------------------
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java b/tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java
index 9bd37e8..6398291 100644
--- a/tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/MQAdminStartup.java
@@ -59,6 +59,7 @@ import org.apache.rocketmq.tools.command.namesrv.UpdateNamesrvConfigCommand;
import org.apache.rocketmq.tools.command.namesrv.WipeWritePermSubCommand;
import org.apache.rocketmq.tools.command.offset.CloneGroupOffsetCommand;
import org.apache.rocketmq.tools.command.offset.ResetOffsetByTimeCommand;
+import org.apache.rocketmq.tools.command.queue.QueryConsumeQueueCommand;
import org.apache.rocketmq.tools.command.stats.StatsAllSubCommand;
import org.apache.rocketmq.tools.command.topic.AllocateMQSubCommand;
import org.apache.rocketmq.tools.command.topic.DeleteTopicSubCommand;
@@ -189,6 +190,8 @@ public class MQAdminStartup {
initCommand(new GetNamesrvConfigCommand());
initCommand(new UpdateNamesrvConfigCommand());
initCommand(new GetBrokerConfigCommand());
+
+ initCommand(new QueryConsumeQueueCommand());
}
private static void initLogback() throws JoranException {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
----------------------------------------------------------------------
diff --git a/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
new file mode 100644
index 0000000..611addd
--- /dev/null
+++ b/tools/src/main/java/org/apache/rocketmq/tools/command/queue/QueryConsumeQueueCommand.java
@@ -0,0 +1,159 @@
+/*
+ * 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.tools.command.queue;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+import org.apache.rocketmq.common.protocol.body.ConsumeQueueData;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
+import org.apache.rocketmq.common.protocol.route.TopicRouteData;
+import org.apache.rocketmq.remoting.RPCHook;
+import org.apache.rocketmq.srvutil.ServerUtil;
+import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
+import org.apache.rocketmq.tools.command.SubCommand;
+
+public class QueryConsumeQueueCommand implements SubCommand {
+
+ public static void main(String[] args) {
+ QueryConsumeQueueCommand cmd = new QueryConsumeQueueCommand();
+
+ Options options = ServerUtil.buildCommandlineOptions(new Options());
+ String[] subargs = new String[]{"-t TopicTest", "-q 0", "-i 6447", "-b 100.81.165.119:10911"};
+ final CommandLine commandLine =
+ ServerUtil.parseCmdLine("mqadmin " + cmd.commandName(), subargs, cmd.buildCommandlineOptions(options),
+ new PosixParser());
+ cmd.execute(commandLine, options, null);
+ }
+
+ @Override
+ public String commandName() {
+ return "queryCq";
+ }
+
+ @Override
+ public String commandDesc() {
+ return "Query cq command.";
+ }
+
+ @Override
+ public Options buildCommandlineOptions(Options options) {
+ Option opt = new Option("t", "topic", true, "topic name");
+ opt.setRequired(true);
+ options.addOption(opt);
+
+ opt = new Option("q", "queue", true, "queue num, ie. 1");
+ opt.setRequired(true);
+ options.addOption(opt);
+
+ opt = new Option("i", "index", true, "start queue index.");
+ opt.setRequired(true);
+ options.addOption(opt);
+
+ opt = new Option("c", "count", true, "how many.");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ opt = new Option("b", "broker", true, "broker addr.");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ opt = new Option("g", "consumer", true, "consumer group.");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ return options;
+ }
+
+ @Override
+ public void execute(CommandLine commandLine, Options options, RPCHook rpcHook) {
+ DefaultMQAdminExt defaultMQAdminExt = new DefaultMQAdminExt(rpcHook);
+
+ defaultMQAdminExt.setInstanceName(Long.toString(System.currentTimeMillis()));
+
+ try {
+ defaultMQAdminExt.start();
+
+ String topic = commandLine.getOptionValue("t").trim();
+ int queueId = Integer.valueOf(commandLine.getOptionValue("q").trim());
+ long index = Long.valueOf(commandLine.getOptionValue("i").trim());
+ int count = Integer.valueOf(commandLine.getOptionValue("c", "10").trim());
+ String broker = null;
+ if (commandLine.hasOption("b")) {
+ broker = commandLine.getOptionValue("b").trim();
+ }
+ String consumerGroup = null;
+ if (commandLine.hasOption("g")) {
+ consumerGroup = commandLine.getOptionValue("g").trim();
+ }
+
+ if (broker == null || broker == "") {
+ TopicRouteData topicRouteData = defaultMQAdminExt.examineTopicRouteInfo(topic);
+
+ if (topicRouteData == null || topicRouteData.getBrokerDatas() == null
+ || topicRouteData.getBrokerDatas().isEmpty()) {
+ throw new Exception("No topic route data!");
+ }
+
+ broker = topicRouteData.getBrokerDatas().get(0).getBrokerAddrs().get(0L);
+ }
+
+ QueryConsumeQueueResponseBody queryConsumeQueueResponseBody = defaultMQAdminExt.queryConsumeQueue(
+ broker, topic, queueId, index, count, consumerGroup
+ );
+
+ if (queryConsumeQueueResponseBody.getSubscriptionData() != null) {
+ System.out.printf("Subscription data: \n%s\n", JSON.toJSONString(queryConsumeQueueResponseBody.getSubscriptionData(), true));
+ System.out.print("======================================\n");
+ }
+
+ if (queryConsumeQueueResponseBody.getFilterData() != null) {
+ System.out.printf("Filter data: \n%s\n", queryConsumeQueueResponseBody.getFilterData());
+ System.out.print("======================================\n");
+ }
+
+ System.out.printf("Queue data: \nmax: %d, min: %d\n", queryConsumeQueueResponseBody.getMaxQueueIndex(),
+ queryConsumeQueueResponseBody.getMinQueueIndex());
+ System.out.print("======================================\n");
+
+ if (queryConsumeQueueResponseBody.getQueueData() != null) {
+
+ long i = index;
+ for (ConsumeQueueData queueData : queryConsumeQueueResponseBody.getQueueData()) {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("idx: " + i + "\n");
+
+ stringBuilder.append(queueData.toString() + "\n");
+
+ stringBuilder.append("======================================\n");
+
+ System.out.print(stringBuilder.toString());
+ i++;
+ }
+
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ defaultMQAdminExt.shutdown();
+ }
+ }
+}
[16/50] [abbrv] incubator-rocketmq git commit: Changed list creation
at DynaCode() to a singleton.
Posted by do...@apache.org.
Changed list creation at DynaCode() to a singleton.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/6898d96c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/6898d96c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/6898d96c
Branch: refs/heads/release-4.1.0-incubating
Commit: 6898d96c0a355a7256cc74d558b660d77c2871c7
Parents: d72addf
Author: shroman <rs...@yahoo.com>
Authored: Thu May 4 21:03:38 2017 +0900
Committer: shroman <rs...@yahoo.com>
Committed: Thu May 4 21:03:38 2017 +0900
----------------------------------------------------------------------
.../java/org/apache/rocketmq/filtersrv/filter/DynaCode.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6898d96c/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/DynaCode.java
----------------------------------------------------------------------
diff --git a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/DynaCode.java b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/DynaCode.java
index a57b57f..e0a94d7 100644
--- a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/DynaCode.java
+++ b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/DynaCode.java
@@ -28,7 +28,7 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -71,9 +71,8 @@ public class DynaCode {
private String target;
- @SuppressWarnings("unchecked")
public DynaCode(String code) {
- this(Thread.currentThread().getContextClassLoader(), Arrays.asList(code));
+ this(Thread.currentThread().getContextClassLoader(), Collections.singletonList(code));
}
public DynaCode(ClassLoader parentClassLoader, List<String> codeStrs) {
[15/50] [abbrv] incubator-rocketmq git commit: Removed author info
and formatted.
Posted by do...@apache.org.
Removed author info and formatted.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/d72addff
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/d72addff
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/d72addff
Branch: refs/heads/release-4.1.0-incubating
Commit: d72addffb3c31a76da5c96f11c183402d8d4323f
Parents: 8feb88d
Author: shroman <rs...@yahoo.com>
Authored: Thu May 4 20:45:11 2017 +0900
Committer: shroman <rs...@yahoo.com>
Committed: Thu May 4 20:45:11 2017 +0900
----------------------------------------------------------------------
.../common/MessageEncodeDecodeTest.java | 30 ++++++++------------
1 file changed, 12 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/d72addff/common/src/test/java/org/apache/rocketmq/common/MessageEncodeDecodeTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/rocketmq/common/MessageEncodeDecodeTest.java b/common/src/test/java/org/apache/rocketmq/common/MessageEncodeDecodeTest.java
index a219eda..42d3909 100644
--- a/common/src/test/java/org/apache/rocketmq/common/MessageEncodeDecodeTest.java
+++ b/common/src/test/java/org/apache/rocketmq/common/MessageEncodeDecodeTest.java
@@ -6,39 +6,33 @@
* (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
+ * 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.
+ * 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.common;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.common.message.MessageDecoder;
-import org.junit.Test;
-
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.junit.Test;
import static org.junit.Assert.assertTrue;
-/**
- * Created by liuzhendong on 16/12/21.
- */
public class MessageEncodeDecodeTest {
-
@Test
- public void testEncodeDecodeSingle() throws Exception{
+ public void testEncodeDecodeSingle() throws Exception {
Message message = new Message("topic", "body".getBytes());
message.setFlag(12);
- message.putUserProperty("key","value");
+ message.putUserProperty("key", "value");
byte[] bytes = MessageDecoder.encodeMessage(message);
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
@@ -59,7 +53,7 @@ public class MessageEncodeDecodeTest {
message.putUserProperty("key", "value" + i);
messages.add(message);
}
- byte[] bytes = MessageDecoder.encodeMessages(messages);
+ byte[] bytes = MessageDecoder.encodeMessages(messages);
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
[40/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-88] Polish
the developer list in pom.xml
Posted by do...@apache.org.
[ROCKETMQ-88] Polish the developer list in pom.xml
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/de4c948c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/de4c948c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/de4c948c
Branch: refs/heads/release-4.1.0-incubating
Commit: de4c948cff561b9e20994947b32b0c328f30e194
Parents: 8d78175
Author: dongeforever <zh...@yeah.net>
Authored: Sat May 27 14:30:53 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 14:30:53 2017 +0800
----------------------------------------------------------------------
pom.xml | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/de4c948c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c60c93c..a77f21d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,8 +76,7 @@
<role>committer</role>
</roles>
<email>vintagewang@apache.org</email>
- <url>https://github.com/vintagewang</url>
- <timezone>8</timezone>
+ <timezone>+8</timezone>
</developer>
<developer>
<id>vongosling@apache.org</id>
@@ -87,14 +86,12 @@
<role>committer</role>
</roles>
<email>vongosling@apache.org</email>
- <url>https://github.com/vongosling@apache.org</url>
<timezone>+8</timezone>
</developer>
<developer>
<id>yukon</id>
<name>Xinyu Zhou</name>
<email>yukon@@apache.org</email>
- <url>https://github.com/zhouxinyu</url>
<roles>
<role>committer</role>
</roles>
@@ -130,6 +127,16 @@
</roles>
<timezone>+8</timezone>
</developer>
+ <developer>
+ <id>dongeforever</id>
+ <name>dongeforever</name>
+ <email>dongeforever@apache.org</email>
+ <roles>
+ <role>committer</role>
+ </roles>
+ <timezone>+8</timezone>
+ </developer>
+
</developers>
<licenses>
[06/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/test/java/org/apache/rocketmq/filter/BitsArrayTest.java
----------------------------------------------------------------------
diff --git a/filter/src/test/java/org/apache/rocketmq/filter/BitsArrayTest.java b/filter/src/test/java/org/apache/rocketmq/filter/BitsArrayTest.java
new file mode 100644
index 0000000..ef81b29
--- /dev/null
+++ b/filter/src/test/java/org/apache/rocketmq/filter/BitsArrayTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.filter.util.BitsArray;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BitsArrayTest {
+
+ BitsArray gen(int bitCount) {
+ BitsArray bitsArray = BitsArray.create(bitCount);
+
+ for (int i = 0; i < bitCount / Byte.SIZE; i++) {
+ bitsArray.setByte(i, (byte) (new Random(System.currentTimeMillis())).nextInt(0xff));
+ try {
+ Thread.sleep(2);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ return bitsArray;
+ }
+
+ int bitLength = Byte.SIZE;
+
+ @Test
+ public void testConstructor() {
+ BitsArray bitsArray = BitsArray.create(8);
+
+ assertThat(bitsArray.byteLength() == 1 && bitsArray.bitLength() == 8).isTrue();
+
+ bitsArray = BitsArray.create(9);
+
+ assertThat(bitsArray.byteLength() == 2 && bitsArray.bitLength() == 9).isTrue();
+
+ bitsArray = BitsArray.create(7);
+
+ assertThat(bitsArray.byteLength() == 1 && bitsArray.bitLength() == 7).isTrue();
+ }
+
+ @Test
+ public void testSet() {
+ BitsArray bitsArray = gen(bitLength);
+ BitsArray backUp = bitsArray.clone();
+
+ boolean val = bitsArray.getBit(2);
+
+ bitsArray.setBit(2, !val);
+
+ bitsArray.xor(backUp);
+
+ assertThat(bitsArray.getBit(2)).isTrue();
+ }
+
+ @Test
+ public void testAndOr() {
+ BitsArray bitsArray = gen(bitLength);
+
+ boolean val = bitsArray.getBit(2);
+
+ if (val) {
+ bitsArray.and(2, false);
+ assertThat(!bitsArray.getBit(2)).isTrue();
+ } else {
+ bitsArray.or(2, true);
+ assertThat(bitsArray.getBit(2)).isTrue();
+ }
+ }
+
+ @Test
+ public void testXor() {
+ BitsArray bitsArray = gen(bitLength);
+
+ boolean val = bitsArray.getBit(2);
+
+ bitsArray.xor(2, !val);
+
+ assertThat(bitsArray.getBit(2)).isTrue();
+ }
+
+ @Test
+ public void testNot() {
+ BitsArray bitsArray = gen(bitLength);
+ BitsArray backUp = bitsArray.clone();
+
+ bitsArray.not(2);
+
+ bitsArray.xor(backUp);
+
+ assertThat(bitsArray.getBit(2)).isTrue();
+ }
+
+ @Test
+ public void testOr() {
+ BitsArray b1 = BitsArray.create(new byte[]{(byte) 0xff, 0x00});
+ BitsArray b2 = BitsArray.create(new byte[]{0x00, (byte) 0xff});
+
+ b1.or(b2);
+
+ for (int i = 0; i < b1.bitLength(); i++) {
+ assertThat(b1.getBit(i)).isTrue();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/test/java/org/apache/rocketmq/filter/BloomFilterTest.java
----------------------------------------------------------------------
diff --git a/filter/src/test/java/org/apache/rocketmq/filter/BloomFilterTest.java b/filter/src/test/java/org/apache/rocketmq/filter/BloomFilterTest.java
new file mode 100644
index 0000000..c6097ee
--- /dev/null
+++ b/filter/src/test/java/org/apache/rocketmq/filter/BloomFilterTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.filter.util.BitsArray;
+import org.apache.rocketmq.filter.util.BloomFilter;
+import org.apache.rocketmq.filter.util.BloomFilterData;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BloomFilterTest {
+
+ @Test
+ public void testEquals() {
+ BloomFilter a = BloomFilter.createByFn(10, 20);
+
+ BloomFilter b = BloomFilter.createByFn(10, 20);
+
+ BloomFilter c = BloomFilter.createByFn(12, 20);
+
+ BloomFilter d = BloomFilter.createByFn(10, 30);
+
+ assertThat(a).isEqualTo(b);
+ assertThat(a).isNotEqualTo(c);
+ assertThat(a).isNotEqualTo(d);
+ assertThat(d).isNotEqualTo(c);
+
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ assertThat(a.hashCode()).isNotEqualTo(c.hashCode());
+ assertThat(a.hashCode()).isNotEqualTo(d.hashCode());
+ assertThat(c.hashCode()).isNotEqualTo(d.hashCode());
+ }
+
+ @Test
+ public void testHashTo() {
+ String cid = "CID_abc_efg";
+
+ BloomFilter bloomFilter = BloomFilter.createByFn(10, 20);
+
+ BitsArray bits = BitsArray.create(bloomFilter.getM());
+
+ int[] bitPos = bloomFilter.calcBitPositions(cid);
+
+ bloomFilter.hashTo(cid, bits);
+
+ for (int bit : bitPos) {
+ assertThat(bits.getBit(bit)).isTrue();
+ }
+ }
+
+ @Test
+ public void testCalcBitPositions() {
+ String cid = "CID_abc_efg";
+
+ BloomFilter bloomFilter = BloomFilter.createByFn(10, 20);
+
+ int[] bitPos = bloomFilter.calcBitPositions(cid);
+
+ assertThat(bitPos).isNotNull();
+ assertThat(bitPos.length).isEqualTo(bloomFilter.getK());
+
+ int[] bitPos2 = bloomFilter.calcBitPositions(cid);
+
+ assertThat(bitPos2).isNotNull();
+ assertThat(bitPos2.length).isEqualTo(bloomFilter.getK());
+
+ assertThat(bitPos).isEqualTo(bitPos2);
+ }
+
+ @Test
+ public void testIsHit() {
+ String cid = "CID_abc_efg";
+ String cid2 = "CID_abc_123";
+
+ BloomFilter bloomFilter = BloomFilter.createByFn(10, 20);
+
+ BitsArray bits = BitsArray.create(bloomFilter.getM());
+
+ bloomFilter.hashTo(cid, bits);
+
+ assertThat(bloomFilter.isHit(cid, bits)).isTrue();
+ assertThat(!bloomFilter.isHit(cid2, bits)).isTrue();
+
+ bloomFilter.hashTo(cid2, bits);
+
+ assertThat(bloomFilter.isHit(cid, bits)).isTrue();
+ assertThat(bloomFilter.isHit(cid2, bits)).isTrue();
+ }
+
+ @Test
+ public void testBloomFilterData() {
+ BloomFilterData bloomFilterData = new BloomFilterData(new int[]{1, 2, 3}, 128);
+ BloomFilterData bloomFilterData1 = new BloomFilterData(new int[]{1, 2, 3}, 128);
+ BloomFilterData bloomFilterData2 = new BloomFilterData(new int[]{1, 2, 3}, 129);
+
+ assertThat(bloomFilterData).isEqualTo(bloomFilterData1);
+ assertThat(bloomFilterData2).isNotEqualTo(bloomFilterData);
+ assertThat(bloomFilterData2).isNotEqualTo(bloomFilterData1);
+
+ assertThat(bloomFilterData.hashCode()).isEqualTo(bloomFilterData1.hashCode());
+ assertThat(bloomFilterData2.hashCode()).isNotEqualTo(bloomFilterData.hashCode());
+ assertThat(bloomFilterData2.hashCode()).isNotEqualTo(bloomFilterData1.hashCode());
+
+ assertThat(bloomFilterData.getBitPos()).isEqualTo(bloomFilterData2.getBitPos());
+ assertThat(bloomFilterData.getBitNum()).isEqualTo(bloomFilterData1.getBitNum());
+ assertThat(bloomFilterData.getBitNum()).isNotEqualTo(bloomFilterData2.getBitNum());
+
+ bloomFilterData2.setBitNum(128);
+
+ assertThat(bloomFilterData).isEqualTo(bloomFilterData2);
+
+ bloomFilterData2.setBitPos(new int[]{1, 2, 3, 4});
+
+ assertThat(bloomFilterData).isNotEqualTo(bloomFilterData2);
+
+ BloomFilterData nullData = new BloomFilterData();
+
+ assertThat(nullData.getBitNum()).isEqualTo(0);
+ assertThat(nullData.getBitPos()).isNull();
+
+ BloomFilter bloomFilter = BloomFilter.createByFn(1, 300);
+
+ assertThat(bloomFilter).isNotNull();
+ assertThat(bloomFilter.isValid(bloomFilterData)).isFalse();
+ }
+
+ @Test
+ public void testCheckFalseHit() {
+ BloomFilter bloomFilter = BloomFilter.createByFn(1, 300);
+ BitsArray bits = BitsArray.create(bloomFilter.getM());
+ int falseHit = 0;
+ for (int i = 0; i < bloomFilter.getN(); i++) {
+ String str = randomString((new Random(System.nanoTime())).nextInt(127) + 10);
+ int[] bitPos = bloomFilter.calcBitPositions(str);
+
+ if (bloomFilter.checkFalseHit(bitPos, bits)) {
+ falseHit++;
+ }
+
+ bloomFilter.hashTo(bitPos, bits);
+ }
+
+ assertThat(falseHit).isLessThanOrEqualTo(bloomFilter.getF() * bloomFilter.getN() / 100);
+ }
+
+ private String randomString(int length) {
+ StringBuilder stringBuilder = new StringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ stringBuilder.append((char) ((new Random(System.nanoTime())).nextInt(123 - 97) + 97));
+ }
+
+ return stringBuilder.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/test/java/org/apache/rocketmq/filter/ExpressionTest.java
----------------------------------------------------------------------
diff --git a/filter/src/test/java/org/apache/rocketmq/filter/ExpressionTest.java b/filter/src/test/java/org/apache/rocketmq/filter/ExpressionTest.java
new file mode 100644
index 0000000..0ee81c9
--- /dev/null
+++ b/filter/src/test/java/org/apache/rocketmq/filter/ExpressionTest.java
@@ -0,0 +1,594 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.filter.expression.ComparisonExpression;
+import org.apache.rocketmq.filter.expression.ConstantExpression;
+import org.apache.rocketmq.filter.expression.EvaluationContext;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.apache.rocketmq.filter.expression.PropertyExpression;
+import org.apache.rocketmq.filter.parser.SelectorParser;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ExpressionTest {
+
+ private static String andExpression = "a=3 and b<>4 And c>5 AND d<=4";
+ private static String orExpression = "a=3 or b<>4 Or c>5 OR d<=4";
+ private static String inExpression = "a in ('3', '4', '5')";
+ private static String notInExpression = "a not in ('3', '4', '5')";
+ private static String betweenExpression = "a between 2 and 10";
+ private static String notBetweenExpression = "a not between 2 and 10";
+ private static String isNullExpression = "a is null";
+ private static String isNotNullExpression = "a is not null";
+ private static String equalExpression = "a is not null and a='hello'";
+ private static String booleanExpression = "a=TRUE OR b=FALSE";
+ private static String nullOrExpression = "a is null OR a='hello'";
+ private static String stringHasString = "TAGS is not null and TAGS='''''tag'''''";
+
+ @Test
+ public void testEvaluate_stringHasString() {
+ Expression expr = genExp(stringHasString);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("TAGS", "''tag''")
+ );
+
+ eval(expr, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_now() {
+ EvaluationContext context = genContext(
+ KeyValue.c("a", System.currentTimeMillis())
+ );
+
+ Expression nowExpression = ConstantExpression.createNow();
+ Expression propertyExpression = new PropertyExpression("a");
+
+ Expression expression = ComparisonExpression.createLessThanEqual(propertyExpression,
+ nowExpression);
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_stringCompare() {
+ Expression expression = genExp("a between up and low");
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "3.14")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+
+ {
+ context = genContext(
+ KeyValue.c("a", "3.14"),
+ KeyValue.c("up", "up"),
+ KeyValue.c("low", "low")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ {
+ expression = genExp("key is not null and key between 0 and 100");
+
+ context = genContext(
+ KeyValue.c("key", "con")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ {
+ expression = genExp("a between 0 and 100");
+
+ context = genContext(
+ KeyValue.c("a", "abc")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ {
+ expression = genExp("a=b");
+
+ context = genContext(
+ KeyValue.c("a", "3.14"),
+ KeyValue.c("b", "3.14")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ {
+ expression = genExp("a<>b");
+
+ context = genContext(
+ KeyValue.c("a", "3.14"),
+ KeyValue.c("b", "3.14")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ {
+ expression = genExp("a<>b");
+
+ context = genContext(
+ KeyValue.c("a", "3.14"),
+ KeyValue.c("b", "3.141")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+ }
+
+ @Test
+ public void testEvaluate_exponent() {
+ Expression expression = genExp("a > 3.1E10");
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", String.valueOf(3.1415 * Math.pow(10, 10)))
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_floatNumber() {
+ Expression expression = genExp("a > 3.14");
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", String.valueOf(3.1415))
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_twoVariable() {
+ Expression expression = genExp("a > b");
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", String.valueOf(10)),
+ KeyValue.c("b", String.valueOf(20))
+ );
+
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("b", String.valueOf(10)),
+ KeyValue.c("a", String.valueOf(20))
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_nullOr() {
+ Expression expression = genExp(nullOrExpression);
+
+ EvaluationContext context = genContext(
+ );
+
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "hello")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "abc")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_boolean() {
+ Expression expression = genExp(booleanExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "true"),
+ KeyValue.c("b", "false")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "false"),
+ KeyValue.c("b", "true")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_equal() {
+ Expression expression = genExp(equalExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "hello")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_andTrue() {
+ Expression expression = genExp(andExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", 3),
+ KeyValue.c("b", 5),
+ KeyValue.c("c", 6),
+ KeyValue.c("d", 1)
+ );
+
+ for (int i = 0; i < 500; i++) {
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ long start = System.currentTimeMillis();
+ for (int j = 0; j < 100; j++) {
+ for (int i = 0; i < 1000; i++) {
+ eval(expression, context, Boolean.TRUE);
+ }
+ }
+
+ // use string
+ context = genContext(
+ KeyValue.c("a", "3"),
+ KeyValue.c("b", "5"),
+ KeyValue.c("c", "6"),
+ KeyValue.c("d", "1")
+ );
+
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_andFalse() {
+ Expression expression = genExp(andExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", 4),
+ KeyValue.c("b", 5),
+ KeyValue.c("c", 6),
+ KeyValue.c("d", 1)
+ );
+
+ eval(expression, context, Boolean.FALSE);
+
+ // use string
+ context = genContext(
+ KeyValue.c("a", "4"),
+ KeyValue.c("b", "5"),
+ KeyValue.c("c", "6"),
+ KeyValue.c("d", "1")
+ );
+
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_orTrue() {
+ Expression expression = genExp(orExpression);
+
+ // first
+ EvaluationContext context = genContext(
+ KeyValue.c("a", 3)
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ // second
+ context = genContext(
+ KeyValue.c("a", 4),
+ KeyValue.c("b", 5)
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ // third
+ context = genContext(
+ KeyValue.c("a", 4),
+ KeyValue.c("b", 4),
+ KeyValue.c("c", 6)
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ // forth
+ context = genContext(
+ KeyValue.c("a", 4),
+ KeyValue.c("b", 4),
+ KeyValue.c("c", 3),
+ KeyValue.c("d", 2)
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_orFalse() {
+ Expression expression = genExp(orExpression);
+ // forth
+ EvaluationContext context = genContext(
+ KeyValue.c("a", 4),
+ KeyValue.c("b", 4),
+ KeyValue.c("c", 3),
+ KeyValue.c("d", 10)
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_inTrue() {
+ Expression expression = genExp(inExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "3")
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "4")
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "5")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_inFalse() {
+ Expression expression = genExp(inExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "8")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_notInTrue() {
+ Expression expression = genExp(notInExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "8")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_notInFalse() {
+ Expression expression = genExp(notInExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "3")
+ );
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("a", "4")
+ );
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("a", "5")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_betweenTrue() {
+ Expression expression = genExp(betweenExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "2")
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "10")
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "3")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_betweenFalse() {
+ Expression expression = genExp(betweenExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "1")
+ );
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("a", "11")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_notBetweenTrue() {
+ Expression expression = genExp(notBetweenExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "1")
+ );
+ eval(expression, context, Boolean.TRUE);
+
+ context = genContext(
+ KeyValue.c("a", "11")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_notBetweenFalse() {
+ Expression expression = genExp(notBetweenExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "2")
+ );
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("a", "10")
+ );
+ eval(expression, context, Boolean.FALSE);
+
+ context = genContext(
+ KeyValue.c("a", "3")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_isNullTrue() {
+ Expression expression = genExp(isNullExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("abc", "2")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_isNullFalse() {
+ Expression expression = genExp(isNullExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "2")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ @Test
+ public void testEvaluate_isNotNullTrue() {
+ Expression expression = genExp(isNotNullExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("a", "2")
+ );
+ eval(expression, context, Boolean.TRUE);
+ }
+
+ @Test
+ public void testEvaluate_isNotNullFalse() {
+ Expression expression = genExp(isNotNullExpression);
+
+ EvaluationContext context = genContext(
+ KeyValue.c("abc", "2")
+ );
+ eval(expression, context, Boolean.FALSE);
+ }
+
+ protected void eval(Expression expression, EvaluationContext context, Boolean result) {
+ Object ret = null;
+ try {
+ ret = expression.evaluate(context);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ if (ret == null || !(ret instanceof Boolean)) {
+ assertThat(result).isFalse();
+ } else {
+ assertThat(result).isEqualTo(ret);
+ }
+ }
+
+ protected EvaluationContext genContext(KeyValue... keyValues) {
+ if (keyValues == null || keyValues.length < 1) {
+ return new PropertyContext();
+ }
+
+ PropertyContext context = new PropertyContext();
+ for (KeyValue keyValue : keyValues) {
+ context.properties.put(keyValue.key, keyValue.value);
+ }
+
+ return context;
+ }
+
+ protected Expression genExp(String exp) {
+ Expression expression = null;
+
+ try {
+ expression = SelectorParser.parse(exp);
+
+ assertThat(expression).isNotNull();
+ } catch (MQFilterException e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ return expression;
+ }
+
+ static class KeyValue {
+ public static KeyValue c(String key, Object value) {
+ return new KeyValue(key, value);
+ }
+
+ public KeyValue(String key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public String key;
+ public Object value;
+ }
+
+ class PropertyContext implements EvaluationContext {
+
+ public Map<String, Object> properties = new HashMap<String, Object>(8);
+
+ @Override
+ public Object get(final String name) {
+ return properties.get(name);
+ }
+
+ @Override
+ public Map<String, Object> keyValues() {
+ return properties;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/test/java/org/apache/rocketmq/filter/FilterSpiTest.java
----------------------------------------------------------------------
diff --git a/filter/src/test/java/org/apache/rocketmq/filter/FilterSpiTest.java b/filter/src/test/java/org/apache/rocketmq/filter/FilterSpiTest.java
new file mode 100644
index 0000000..22eeb86
--- /dev/null
+++ b/filter/src/test/java/org/apache/rocketmq/filter/FilterSpiTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.filter.expression.EmptyEvaluationContext;
+import org.apache.rocketmq.filter.expression.EvaluationContext;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FilterSpiTest {
+
+ static class NothingExpression implements Expression {
+
+ @Override
+ public Object evaluate(final EvaluationContext context) throws Exception {
+ return Boolean.TRUE;
+ }
+ }
+
+ static class NothingFilter implements FilterSpi {
+ @Override
+ public Expression compile(final String expr) throws MQFilterException {
+ return new NothingExpression();
+ }
+
+ @Override
+ public String ofType() {
+ return "Nothing";
+ }
+ }
+
+
+ @Test
+ public void testRegister() {
+ FilterFactory.INSTANCE.register(new NothingFilter());
+
+ Expression expr = null;
+ try {
+ expr = FilterFactory.INSTANCE.get("Nothing").compile("abc");
+ } catch (MQFilterException e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ assertThat(expr).isNotNull();
+
+ try {
+ assertThat((Boolean) expr.evaluate(new EmptyEvaluationContext())).isTrue();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+ }
+
+ @Test
+ public void testGet() {
+ try {
+ assertThat((Boolean) FilterFactory.INSTANCE.get(ExpressionType.SQL92).compile("a is not null and a > 0")
+ .evaluate(new EmptyEvaluationContext())).isFalse();
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/test/java/org/apache/rocketmq/filter/ParserTest.java
----------------------------------------------------------------------
diff --git a/filter/src/test/java/org/apache/rocketmq/filter/ParserTest.java b/filter/src/test/java/org/apache/rocketmq/filter/ParserTest.java
new file mode 100644
index 0000000..36ef271
--- /dev/null
+++ b/filter/src/test/java/org/apache/rocketmq/filter/ParserTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.apache.rocketmq.filter.parser.SelectorParser;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ParserTest {
+
+ private static String andExpression = "a=3 and b<>4 And c>5 AND d<=4";
+ private static String andExpressionHasBlank = "a=3 and b<>4 And c>5 AND d<=4";
+ private static String orExpression = "a=3 or b<>4 Or c>5 OR d<=4";
+ private static String inExpression = "a in ('3', '4', '5')";
+ private static String notInExpression = "(a not in ('6', '4', '5')) or (b in ('3', '4', '5'))";
+ private static String betweenExpression = "(a between 2 and 10) AND (b not between 6 and 9)";
+ private static String equalNullExpression = "a is null";
+ private static String notEqualNullExpression = "a is not null";
+ private static String nowExpression = "a <= now";
+
+ private static String invalidExpression = "a and between 2 and 10";
+ private static String illegalBetween = " a between 10 and 0";
+
+ @Test
+ public void testParse_valid() {
+ for (String expr : Arrays.asList(
+ andExpression, orExpression, inExpression, notInExpression, betweenExpression,
+ equalNullExpression, notEqualNullExpression, nowExpression
+ )) {
+
+ try {
+ Expression expression = SelectorParser.parse(expr);
+ assertThat(expression).isNotNull();
+ } catch (MQFilterException e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ }
+ }
+
+ @Test
+ public void testParse_invalid() {
+ try {
+ SelectorParser.parse(invalidExpression);
+
+ assertThat(Boolean.TRUE).isFalse();
+ } catch (MQFilterException e) {
+ }
+ }
+
+ @Test
+ public void testParse_decimalOverFlow() {
+ try {
+ String str = "100000000000000000000000";
+
+ SelectorParser.parse("a > " + str);
+
+ assertThat(Boolean.TRUE).isFalse();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testParse_floatOverFlow() {
+ try {
+ String str = "1";
+ for (int i = 0; i < 2048; i++) {
+ str += "111111111111111111111111111111111111111111111111111";
+ }
+ str += ".";
+ for (int i = 0; i < 2048; i++) {
+ str += "111111111111111111111111111111111111111111111111111";
+ }
+
+ SelectorParser.parse("a > " + str);
+
+ assertThat(Boolean.TRUE).isFalse();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testParse_illegalBetween() {
+ try {
+ SelectorParser.parse(illegalBetween);
+
+ assertThat(Boolean.TRUE).isFalse();
+ } catch (Exception e) {
+ }
+ }
+
+ @Test
+ public void testEquals() {
+ try {
+ Expression expr1 = SelectorParser.parse(andExpression);
+
+ Expression expr2 = SelectorParser.parse(andExpressionHasBlank);
+
+ Expression expr3 = SelectorParser.parse(orExpression);
+
+ assertThat(expr1).isEqualTo(expr2);
+ assertThat(expr1).isNotEqualTo(expr3);
+ } catch (MQFilterException e) {
+ e.printStackTrace();
+ assertThat(Boolean.TRUE).isFalse();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 47df84d..feb8b14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -178,6 +178,7 @@
<module>example</module>
<module>filtersrv</module>
<module>srvutil</module>
+ <module>filter</module>
<module>test</module>
<module>distribution</module>
</modules>
@@ -554,6 +555,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-filter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rocketmq-example</artifactId>
<version>${project.version}</version>
@@ -603,6 +609,11 @@
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>19.0</version>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/srvutil/pom.xml
----------------------------------------------------------------------
diff --git a/srvutil/pom.xml b/srvutil/pom.xml
index 3269903..6dc0377 100644
--- a/srvutil/pom.xml
+++ b/srvutil/pom.xml
@@ -41,5 +41,9 @@
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
index 5be8258..7841feb 100644
--- a/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
+++ b/store/src/main/java/org/apache/rocketmq/store/CommitLog.java
@@ -314,10 +314,11 @@ public class CommitLog {
// 17 properties
short propertiesLength = byteBuffer.getShort();
+ Map<String, String> propertiesMap = null;
if (propertiesLength > 0) {
byteBuffer.get(bytesContent, 0, propertiesLength);
String properties = new String(bytesContent, 0, propertiesLength, MessageDecoder.CHARSET_UTF8);
- Map<String, String> propertiesMap = MessageDecoder.string2messageProperties(properties);
+ propertiesMap = MessageDecoder.string2messageProperties(properties);
keys = propertiesMap.get(MessageConst.PROPERTY_KEYS);
@@ -369,8 +370,9 @@ public class CommitLog {
queueOffset, // 7
keys, // 8
uniqKey, //9
- sysFlag, // 9
- preparedTransactionOffset// 10
+ sysFlag, // 10
+ preparedTransactionOffset, // 11
+ propertiesMap // 12
);
} catch (Exception e) {
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/CommitLogDispatcher.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/CommitLogDispatcher.java b/store/src/main/java/org/apache/rocketmq/store/CommitLogDispatcher.java
new file mode 100644
index 0000000..e1564a9
--- /dev/null
+++ b/store/src/main/java/org/apache/rocketmq/store/CommitLogDispatcher.java
@@ -0,0 +1,26 @@
+/*
+ * 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.store;
+
+/**
+ * Dispatcher of commit log.
+ */
+public interface CommitLogDispatcher {
+
+ void dispatch(final DispatchRequest request);
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java
index 919c637..d03ff0f 100644
--- a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java
+++ b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueue.java
@@ -20,6 +20,7 @@ import java.io.File;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.store.config.StorePathConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +41,7 @@ public class ConsumeQueue {
private final int mappedFileSize;
private long maxPhysicOffset = -1;
private volatile long minLogicOffset = 0;
+ private ConsumeQueueExt consumeQueueExt = null;
public ConsumeQueue(
final String topic,
@@ -61,11 +63,24 @@ public class ConsumeQueue {
this.mappedFileQueue = new MappedFileQueue(queueDir, mappedFileSize, null);
this.byteBufferIndex = ByteBuffer.allocate(CQ_STORE_UNIT_SIZE);
+
+ if (defaultMessageStore.getMessageStoreConfig().isEnableConsumeQueueExt()) {
+ this.consumeQueueExt = new ConsumeQueueExt(
+ topic,
+ queueId,
+ StorePathConfigHelper.getStorePathConsumeQueueExt(defaultMessageStore.getMessageStoreConfig().getStorePathRootDir()),
+ defaultMessageStore.getMessageStoreConfig().getMappedFileSizeConsumeQueueExt(),
+ defaultMessageStore.getMessageStoreConfig().getBitMapLengthConsumeQueueExt()
+ );
+ }
}
public boolean load() {
boolean result = this.mappedFileQueue.load();
log.info("load consume queue " + this.topic + "-" + this.queueId + " " + (result ? "OK" : "Failed"));
+ if (isExtReadEnable()) {
+ result &= this.consumeQueueExt.load();
+ }
return result;
}
@@ -82,6 +97,7 @@ public class ConsumeQueue {
ByteBuffer byteBuffer = mappedFile.sliceByteBuffer();
long processOffset = mappedFile.getFileFromOffset();
long mappedFileOffset = 0;
+ long maxExtAddr = 1;
while (true) {
for (int i = 0; i < mappedFileSizeLogics; i += CQ_STORE_UNIT_SIZE) {
long offset = byteBuffer.getLong();
@@ -91,6 +107,9 @@ public class ConsumeQueue {
if (offset >= 0 && size > 0) {
mappedFileOffset = i + CQ_STORE_UNIT_SIZE;
this.maxPhysicOffset = offset;
+ if (isExtAddr(tagsCode)) {
+ maxExtAddr = tagsCode;
+ }
} else {
log.info("recover current consume queue file over, " + mappedFile.getFileName() + " "
+ offset + " " + size + " " + tagsCode);
@@ -123,6 +142,12 @@ public class ConsumeQueue {
this.mappedFileQueue.setFlushedWhere(processOffset);
this.mappedFileQueue.setCommittedWhere(processOffset);
this.mappedFileQueue.truncateDirtyFiles(processOffset);
+
+ if (isExtReadEnable()) {
+ this.consumeQueueExt.recover();
+ log.info("Truncate consume queue extend file by max {}", maxExtAddr);
+ this.consumeQueueExt.truncateByMaxAddress(maxExtAddr);
+ }
}
}
@@ -200,7 +225,7 @@ public class ConsumeQueue {
int logicFileSize = this.mappedFileSize;
this.maxPhysicOffset = phyOffet - 1;
-
+ long maxExtAddr = 1;
while (true) {
MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile();
if (mappedFile != null) {
@@ -213,7 +238,7 @@ public class ConsumeQueue {
for (int i = 0; i < logicFileSize; i += CQ_STORE_UNIT_SIZE) {
long offset = byteBuffer.getLong();
int size = byteBuffer.getInt();
- byteBuffer.getLong();
+ long tagsCode = byteBuffer.getLong();
if (0 == i) {
if (offset >= phyOffet) {
@@ -225,6 +250,10 @@ public class ConsumeQueue {
mappedFile.setCommittedPosition(pos);
mappedFile.setFlushedPosition(pos);
this.maxPhysicOffset = offset;
+ // This maybe not take effect, when not every consume queue has extend file.
+ if (isExtAddr(tagsCode)) {
+ maxExtAddr = tagsCode;
+ }
}
} else {
@@ -239,6 +268,9 @@ public class ConsumeQueue {
mappedFile.setCommittedPosition(pos);
mappedFile.setFlushedPosition(pos);
this.maxPhysicOffset = offset;
+ if (isExtAddr(tagsCode)) {
+ maxExtAddr = tagsCode;
+ }
if (pos == logicFileSize) {
return;
@@ -252,6 +284,10 @@ public class ConsumeQueue {
break;
}
}
+
+ if (isExtReadEnable()) {
+ this.consumeQueueExt.truncateByMaxAddress(maxExtAddr);
+ }
}
public long getLastOffset() {
@@ -285,7 +321,12 @@ public class ConsumeQueue {
}
public boolean flush(final int flushLeastPages) {
- return this.mappedFileQueue.flush(flushLeastPages);
+ boolean result = this.mappedFileQueue.flush(flushLeastPages);
+ if (isExtReadEnable()) {
+ result = result & this.consumeQueueExt.flush(flushLeastPages);
+ }
+
+ return result;
}
public int deleteExpiredFile(long offset) {
@@ -296,6 +337,7 @@ public class ConsumeQueue {
public void correctMinOffset(long phyMinOffset) {
MappedFile mappedFile = this.mappedFileQueue.getFirstMappedFile();
+ long minExtAddr = 1;
if (mappedFile != null) {
SelectMappedBufferResult result = mappedFile.selectMappedBuffer(0);
if (result != null) {
@@ -303,12 +345,16 @@ public class ConsumeQueue {
for (int i = 0; i < result.getSize(); i += ConsumeQueue.CQ_STORE_UNIT_SIZE) {
long offsetPy = result.getByteBuffer().getLong();
result.getByteBuffer().getInt();
- result.getByteBuffer().getLong();
+ long tagsCode = result.getByteBuffer().getLong();
if (offsetPy >= phyMinOffset) {
this.minLogicOffset = result.getMappedFile().getFileFromOffset() + i;
log.info("Compute logical min offset: {}, topic: {}, queueId: {}",
this.getMinOffsetInQueue(), this.topic, this.queueId);
+ // This maybe not take effect, when not every consume queue has extend file.
+ if (isExtAddr(tagsCode)) {
+ minExtAddr = tagsCode;
+ }
break;
}
}
@@ -319,24 +365,43 @@ public class ConsumeQueue {
}
}
}
+
+ if (isExtReadEnable()) {
+ this.consumeQueueExt.truncateByMinAddress(minExtAddr);
+ }
}
public long getMinOffsetInQueue() {
return this.minLogicOffset / CQ_STORE_UNIT_SIZE;
}
- public void putMessagePositionInfoWrapper(long offset, int size, long tagsCode, long storeTimestamp,
- long logicOffset) {
+ public void putMessagePositionInfoWrapper(DispatchRequest request) {
final int maxRetries = 30;
boolean canWrite = this.defaultMessageStore.getRunningFlags().isCQWriteable();
for (int i = 0; i < maxRetries && canWrite; i++) {
- boolean result = this.putMessagePositionInfo(offset, size, tagsCode, logicOffset);
+ long tagsCode = request.getTagsCode();
+ if (isExtWriteEnable()) {
+ ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit();
+ cqExtUnit.setFilterBitMap(request.getBitMap());
+ cqExtUnit.setMsgStoreTime(request.getStoreTimestamp());
+ cqExtUnit.setTagsCode(request.getTagsCode());
+
+ long extAddr = this.consumeQueueExt.put(cqExtUnit);
+ if (isExtAddr(extAddr)) {
+ tagsCode = extAddr;
+ } else {
+ log.warn("Save consume queue extend fail, So just save tagsCode! {}, topic:{}, queueId:{}, offset:{}", cqExtUnit,
+ topic, queueId, request.getCommitLogOffset());
+ }
+ }
+ boolean result = this.putMessagePositionInfo(request.getCommitLogOffset(),
+ request.getMsgSize(), tagsCode, request.getConsumeQueueOffset());
if (result) {
- this.defaultMessageStore.getStoreCheckpoint().setLogicsMsgTimestamp(storeTimestamp);
+ this.defaultMessageStore.getStoreCheckpoint().setLogicsMsgTimestamp(request.getStoreTimestamp());
return;
} else {
// XXX: warn and notify me
- log.warn("[BUG]put commit log position info to " + topic + ":" + queueId + " " + offset
+ log.warn("[BUG]put commit log position info to " + topic + ":" + queueId + " " + request.getCommitLogOffset()
+ " failed, retry " + i + " times");
try {
@@ -423,6 +488,20 @@ public class ConsumeQueue {
return null;
}
+ public ConsumeQueueExt.CqExtUnit getExt(final long offset) {
+ if (isExtReadEnable()) {
+ return this.consumeQueueExt.get(offset);
+ }
+ return null;
+ }
+
+ public boolean getExt(final long offset, ConsumeQueueExt.CqExtUnit cqExtUnit) {
+ if (isExtReadEnable()) {
+ return this.consumeQueueExt.get(offset, cqExtUnit);
+ }
+ return false;
+ }
+
public long getMinLogicOffset() {
return minLogicOffset;
}
@@ -457,6 +536,9 @@ public class ConsumeQueue {
this.maxPhysicOffset = -1;
this.minLogicOffset = 0;
this.mappedFileQueue.destroy();
+ if (isExtReadEnable()) {
+ this.consumeQueueExt.destroy();
+ }
}
public long getMessageTotalInQueue() {
@@ -469,5 +551,27 @@ public class ConsumeQueue {
public void checkSelf() {
mappedFileQueue.checkSelf();
+ if (isExtReadEnable()) {
+ this.consumeQueueExt.checkSelf();
+ }
+ }
+
+ protected boolean isExtReadEnable() {
+ return this.consumeQueueExt != null;
+ }
+
+ protected boolean isExtWriteEnable() {
+ return this.consumeQueueExt != null
+ && this.defaultMessageStore.getMessageStoreConfig().isEnableConsumeQueueExt();
+ }
+
+ /**
+ * Check {@code tagsCode} is address of extend file or tags code.
+ *
+ * @param tagsCode
+ * @return
+ */
+ public boolean isExtAddr(long tagsCode) {
+ return isExtReadEnable() && this.consumeQueueExt.isExtAddr(tagsCode);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueueExt.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/ConsumeQueueExt.java b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueueExt.java
new file mode 100644
index 0000000..1a177e9
--- /dev/null
+++ b/store/src/main/java/org/apache/rocketmq/store/ConsumeQueueExt.java
@@ -0,0 +1,638 @@
+/*
+ * 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.store;
+
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Extend of consume queue, to store something not important,
+ * such as message store time, filter bit map and etc.
+ * <p/>
+ * <li>1. This class is used only by {@link ConsumeQueue}</li>
+ * <li>2. And is week reliable.</li>
+ * <li>3. Be careful, address returned is always less than 0.</li>
+ * <li>4. Pls keep this file small.</li>
+ */
+public class ConsumeQueueExt {
+ private static final Logger log = LoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);
+
+ private final MappedFileQueue mappedFileQueue;
+ private final String topic;
+ private final int queueId;
+
+ private final String storePath;
+ private final int mappedFileSize;
+ private ByteBuffer tempContainer;
+
+ public static final int END_BLANK_DATA_LENGTH = 4;
+
+ /**
+ * Addr can not exceed this value.For compatible.
+ */
+ public static final long MAX_ADDR = Integer.MIN_VALUE - 1L;
+ public static final long MAX_REAL_OFFSET = MAX_ADDR - Long.MIN_VALUE;
+
+ /**
+ * Constructor.
+ *
+ * @param topic topic
+ * @param queueId id of queue
+ * @param storePath root dir of files to store.
+ * @param mappedFileSize file size
+ * @param bitMapLength bit map length.
+ */
+ public ConsumeQueueExt(final String topic,
+ final int queueId,
+ final String storePath,
+ final int mappedFileSize,
+ final int bitMapLength) {
+
+ this.storePath = storePath;
+ this.mappedFileSize = mappedFileSize;
+
+ this.topic = topic;
+ this.queueId = queueId;
+
+ String queueDir = this.storePath
+ + File.separator + topic
+ + File.separator + queueId;
+
+ this.mappedFileQueue = new MappedFileQueue(queueDir, mappedFileSize, null);
+
+ if (bitMapLength > 0) {
+ this.tempContainer = ByteBuffer.allocate(
+ bitMapLength / Byte.SIZE
+ );
+ }
+ }
+
+ /**
+ * Check whether {@code address} point to extend file.
+ * <p>
+ * Just test {@code address} is less than 0.
+ * </p>
+ *
+ * @param address
+ * @return
+ */
+ public boolean isExtAddr(final long address) {
+ return address <= MAX_ADDR;
+ }
+
+ /**
+ * Transform {@code address}(decorated by {@link #decorate}) to offset in mapped file.
+ * <p>
+ * if {@code address} is less than 0, return {@code address} - {@link java.lang.Long#MIN_VALUE};
+ * else, just return {@code address}
+ * </p>
+ *
+ * @param address
+ * @return
+ */
+ public long unDecorate(final long address) {
+ if (isExtAddr(address)) {
+ return address - Long.MIN_VALUE;
+ }
+ return address;
+ }
+
+ /**
+ * Decorate {@code offset} from mapped file, in order to distinguish with tagsCode(saved in cq originally).
+ * <p>
+ * if {@code offset} is greater than or equal to 0, then return {@code offset} + {@link java.lang.Long#MIN_VALUE};
+ * else, just return {@code offset}
+ * </p>
+ *
+ * @param offset
+ * @return ext address(value is less than 0)
+ */
+ public long decorate(final long offset) {
+ if (!isExtAddr(offset)) {
+ return offset + Long.MIN_VALUE;
+ }
+ return offset;
+ }
+
+ /**
+ * Get data from buffer.
+ *
+ * @param address less than 0
+ * @return
+ */
+ public CqExtUnit get(final long address) {
+ CqExtUnit cqExtUnit = new CqExtUnit();
+ if (get(address, cqExtUnit)) {
+ return cqExtUnit;
+ }
+
+ return null;
+ }
+
+ /**
+ * Get data from buffer, and set to {@code cqExtUnit}
+ *
+ * @param address less than 0
+ * @param cqExtUnit
+ * @return
+ */
+ public boolean get(final long address, final CqExtUnit cqExtUnit) {
+ if (!isExtAddr(address)) {
+ return false;
+ }
+
+ final int mappedFileSize = this.mappedFileSize;
+ final long realOffset = unDecorate(address);
+
+ MappedFile mappedFile = this.mappedFileQueue.findMappedFileByOffset(realOffset, realOffset == 0);
+ if (mappedFile == null) {
+ return false;
+ }
+
+ int pos = (int) (realOffset % mappedFileSize);
+
+ SelectMappedBufferResult bufferResult = mappedFile.selectMappedBuffer(pos);
+ if (bufferResult == null) {
+ log.warn("[BUG] Consume queue extend unit({}) is not found!", realOffset);
+ return false;
+ }
+ boolean ret = false;
+ try {
+ ret = cqExtUnit.read(bufferResult.getByteBuffer());
+ } finally {
+ bufferResult.release();
+ }
+
+ return ret;
+ }
+
+ /**
+ * Save to mapped buffer of file and return address.
+ * <p>
+ * Be careful, this method is not thread safe.
+ * </p>
+ *
+ * @param cqExtUnit
+ * @return success: < 0: fail: >=0
+ */
+ public long put(final CqExtUnit cqExtUnit) {
+ final int retryTimes = 3;
+ try {
+ int size = cqExtUnit.calcUnitSize();
+ if (size > CqExtUnit.MAX_EXT_UNIT_SIZE) {
+ log.error("Size of cq ext unit is greater than {}, {}", CqExtUnit.MAX_EXT_UNIT_SIZE, cqExtUnit);
+ return 1;
+ }
+ if (this.mappedFileQueue.getMaxOffset() + size > MAX_REAL_OFFSET) {
+ log.warn("Capacity of ext is maximum!{}, {}", this.mappedFileQueue.getMaxOffset(), size);
+ return 1;
+ }
+ // unit size maybe change.but, the same most of the time.
+ if (this.tempContainer == null || this.tempContainer.capacity() < size) {
+ this.tempContainer = ByteBuffer.allocate(size);
+ }
+
+ for (int i = 0; i < retryTimes; i++) {
+ MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile();
+
+ if (mappedFile == null || mappedFile.isFull()) {
+ mappedFile = this.mappedFileQueue.getLastMappedFile(0);
+ }
+
+ if (mappedFile == null) {
+ log.error("Create mapped file when save consume queue extend, {}", cqExtUnit);
+ continue;
+ }
+ final int wrotePosition = mappedFile.getWrotePosition();
+ final int blankSize = this.mappedFileSize - wrotePosition - END_BLANK_DATA_LENGTH;
+
+ // check whether has enough space.
+ if (size > blankSize) {
+ fullFillToEnd(mappedFile, wrotePosition);
+ log.info("No enough space(need:{}, has:{}) of file {}, so fill to end",
+ size, blankSize, mappedFile.getFileName());
+ continue;
+ }
+
+ if (mappedFile.appendMessage(cqExtUnit.write(this.tempContainer), 0, size)) {
+ return decorate(wrotePosition + mappedFile.getFileFromOffset());
+ }
+ }
+ } catch (Throwable e) {
+ log.error("Save consume queue extend error, " + cqExtUnit, e);
+ }
+
+ return 1;
+ }
+
+ protected void fullFillToEnd(final MappedFile mappedFile, final int wrotePosition) {
+ ByteBuffer mappedFileBuffer = mappedFile.sliceByteBuffer();
+ mappedFileBuffer.position(wrotePosition);
+
+ // ending.
+ mappedFileBuffer.putShort((short) -1);
+
+ mappedFile.setWrotePosition(this.mappedFileSize);
+ }
+
+ /**
+ * Load data from file when startup.
+ *
+ * @return
+ */
+ public boolean load() {
+ boolean result = this.mappedFileQueue.load();
+ log.info("load consume queue extend" + this.topic + "-" + this.queueId + " " + (result ? "OK" : "Failed"));
+ return result;
+ }
+
+ /**
+ * Check whether the step size in mapped file queue is correct.
+ */
+ public void checkSelf() {
+ this.mappedFileQueue.checkSelf();
+ }
+
+ /**
+ * Recover.
+ */
+ public void recover() {
+ final List<MappedFile> mappedFiles = this.mappedFileQueue.getMappedFiles();
+ if (mappedFiles == null || mappedFiles.isEmpty()) {
+ return;
+ }
+
+ // load all files, consume queue will truncate extend files.
+ int index = 0;
+
+ MappedFile mappedFile = mappedFiles.get(index);
+ ByteBuffer byteBuffer = mappedFile.sliceByteBuffer();
+ long processOffset = mappedFile.getFileFromOffset();
+ long mappedFileOffset = 0;
+ CqExtUnit extUnit = new CqExtUnit();
+ while (true) {
+ extUnit.readBySkip(byteBuffer);
+
+ // check whether write sth.
+ if (extUnit.getSize() > 0) {
+ mappedFileOffset += extUnit.getSize();
+ continue;
+ }
+
+ index++;
+ if (index < mappedFiles.size()) {
+ mappedFile = mappedFiles.get(index);
+ byteBuffer = mappedFile.sliceByteBuffer();
+ processOffset = mappedFile.getFileFromOffset();
+ mappedFileOffset = 0;
+ log.info("Recover next consume queue extend file, " + mappedFile.getFileName());
+ continue;
+ }
+
+ log.info("All files of consume queue extend has been recovered over, last mapped file "
+ + mappedFile.getFileName());
+ break;
+ }
+
+ processOffset += mappedFileOffset;
+ this.mappedFileQueue.setFlushedWhere(processOffset);
+ this.mappedFileQueue.setCommittedWhere(processOffset);
+ this.mappedFileQueue.truncateDirtyFiles(processOffset);
+ }
+
+ /**
+ * Delete files before {@code minAddress}.
+ *
+ * @param minAddress less than 0
+ */
+ public void truncateByMinAddress(final long minAddress) {
+ if (!isExtAddr(minAddress)) {
+ return;
+ }
+
+ log.info("Truncate consume queue ext by min {}.", minAddress);
+
+ List<MappedFile> willRemoveFiles = new ArrayList<MappedFile>();
+
+ List<MappedFile> mappedFiles = this.mappedFileQueue.getMappedFiles();
+ final long realOffset = unDecorate(minAddress);
+
+ for (MappedFile file : mappedFiles) {
+ long fileTailOffset = file.getFileFromOffset() + this.mappedFileSize;
+
+ if (fileTailOffset < realOffset) {
+ log.info("Destroy consume queue ext by min: file={}, fileTailOffset={}, minOffset={}", file.getFileName(),
+ fileTailOffset, realOffset);
+ if (file.destroy(1000)) {
+ willRemoveFiles.add(file);
+ }
+ }
+ }
+
+ this.mappedFileQueue.deleteExpiredFile(willRemoveFiles);
+ }
+
+ /**
+ * Delete files after {@code maxAddress}, and reset wrote/commit/flush position to last file.
+ *
+ * @param maxAddress less than 0
+ */
+ public void truncateByMaxAddress(final long maxAddress) {
+ if (!isExtAddr(maxAddress)) {
+ return;
+ }
+
+ log.info("Truncate consume queue ext by max {}.", maxAddress);
+
+ CqExtUnit cqExtUnit = get(maxAddress);
+ if (cqExtUnit == null) {
+ log.error("[BUG] address {} of consume queue extend not found!", maxAddress);
+ return;
+ }
+
+ final long realOffset = unDecorate(maxAddress);
+
+ this.mappedFileQueue.truncateDirtyFiles(realOffset + cqExtUnit.getSize());
+ }
+
+ /**
+ * flush buffer to file.
+ *
+ * @param flushLeastPages
+ * @return
+ */
+ public boolean flush(final int flushLeastPages) {
+ return this.mappedFileQueue.flush(flushLeastPages);
+ }
+
+ /**
+ * delete files and directory.
+ */
+ public void destroy() {
+ this.mappedFileQueue.destroy();
+ }
+
+ /**
+ * Max address(value is less than 0).
+ * <p/>
+ * <p>
+ * Be careful: it's an address just when invoking this method.
+ * </p>
+ *
+ * @return
+ */
+ public long getMaxAddress() {
+ MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile();
+ if (mappedFile == null) {
+ return decorate(0);
+ }
+ return decorate(mappedFile.getFileFromOffset() + mappedFile.getWrotePosition());
+ }
+
+ /**
+ * Minus address saved in file.
+ *
+ * @return
+ */
+ public long getMinAddress() {
+ MappedFile firstFile = this.mappedFileQueue.getFirstMappedFile();
+ if (firstFile == null) {
+ return decorate(0);
+ }
+ return decorate(firstFile.getFileFromOffset());
+ }
+
+ /**
+ * Store unit.
+ */
+ public static class CqExtUnit {
+ public static final short MIN_EXT_UNIT_SIZE
+ = 2 * 1 // size, 32k max
+ + 8 * 2 // msg time + tagCode
+ + 2; // bitMapSize
+
+ public static final int MAX_EXT_UNIT_SIZE = Short.MAX_VALUE;
+
+ public CqExtUnit() {}
+
+ public CqExtUnit(Long tagsCode, long msgStoreTime, byte[] filterBitMap) {
+ this.tagsCode = tagsCode == null ? 0 : tagsCode;
+ this.msgStoreTime = msgStoreTime;
+ this.filterBitMap = filterBitMap;
+ this.bitMapSize = (short) (filterBitMap == null ? 0 : filterBitMap.length);
+ this.size = (short) (MIN_EXT_UNIT_SIZE + this.bitMapSize);
+ }
+
+ /**
+ * unit size
+ */
+ private short size;
+ /**
+ * has code of tags
+ */
+ private long tagsCode;
+ /**
+ * the time to store into commit log of message
+ */
+ private long msgStoreTime;
+ /**
+ * size of bit map
+ */
+ private short bitMapSize;
+ /**
+ * filter bit map
+ */
+ private byte[] filterBitMap;
+
+ /**
+ * build unit from buffer from current position.
+ *
+ * @param buffer
+ * @return
+ */
+ private boolean read(final ByteBuffer buffer) {
+ if (buffer.position() + 2 > buffer.limit()) {
+ return false;
+ }
+
+ this.size = buffer.getShort();
+
+ if (this.size < 1) {
+ return false;
+ }
+
+ this.tagsCode = buffer.getLong();
+ this.msgStoreTime = buffer.getLong();
+ this.bitMapSize = buffer.getShort();
+
+ if (this.bitMapSize < 1) {
+ return true;
+ }
+
+ if (this.filterBitMap == null || this.filterBitMap.length != this.bitMapSize) {
+ this.filterBitMap = new byte[bitMapSize];
+ }
+
+ buffer.get(this.filterBitMap);
+ return true;
+ }
+
+ /**
+ * Only read first 2 byte to get unit size.
+ * <p>
+ * if size > 0, then skip buffer position with size.
+ * </p>
+ * <p>
+ * if size <= 0, nothing to do.
+ * </p>
+ *
+ * @param buffer
+ */
+ private void readBySkip(final ByteBuffer buffer) {
+ ByteBuffer temp = buffer.slice();
+
+ short tempSize = temp.getShort();
+ this.size = tempSize;
+
+ if (tempSize > 0) {
+ buffer.position(buffer.position() + this.size);
+ }
+ }
+
+ /**
+ * Transform unit data to byte array.
+ * <p/>
+ * <li>1. @{code container} can be null, it will be created if null.</li>
+ * <li>2. if capacity of @{code container} is less than unit size, it will be created also.</li>
+ * <li>3. Pls be sure that size of unit is not greater than {@link #MAX_EXT_UNIT_SIZE}</li>
+ *
+ * @param container
+ * @return
+ */
+ private byte[] write(final ByteBuffer container) {
+ this.bitMapSize = (short) (filterBitMap == null ? 0 : filterBitMap.length);
+ this.size = (short) (MIN_EXT_UNIT_SIZE + this.bitMapSize);
+
+ ByteBuffer temp = container;
+
+ if (temp == null || temp.capacity() < this.size) {
+ temp = ByteBuffer.allocate(this.size);
+ }
+
+ temp.flip();
+ temp.limit(this.size);
+
+ temp.putShort(this.size);
+ temp.putLong(this.tagsCode);
+ temp.putLong(this.msgStoreTime);
+ temp.putShort(this.bitMapSize);
+ if (this.bitMapSize > 0) {
+ temp.put(this.filterBitMap);
+ }
+
+ return temp.array();
+ }
+
+ /**
+ * Calculate unit size by current data.
+ *
+ * @return
+ */
+ private int calcUnitSize() {
+ int sizeTemp = MIN_EXT_UNIT_SIZE + (filterBitMap == null ? 0 : filterBitMap.length);
+ return sizeTemp;
+ }
+
+ public long getTagsCode() {
+ return tagsCode;
+ }
+
+ public void setTagsCode(final long tagsCode) {
+ this.tagsCode = tagsCode;
+ }
+
+ public long getMsgStoreTime() {
+ return msgStoreTime;
+ }
+
+ public void setMsgStoreTime(final long msgStoreTime) {
+ this.msgStoreTime = msgStoreTime;
+ }
+
+ public byte[] getFilterBitMap() {
+ if (this.bitMapSize < 1) {
+ return null;
+ }
+ return filterBitMap;
+ }
+
+ public void setFilterBitMap(final byte[] filterBitMap) {
+ this.filterBitMap = filterBitMap;
+ // not safe transform, but size will be calculate by #calcUnitSize
+ this.bitMapSize = (short) (filterBitMap == null ? 0 : filterBitMap.length);
+ }
+
+ public short getSize() {
+ return size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof CqExtUnit)) return false;
+
+ CqExtUnit cqExtUnit = (CqExtUnit) o;
+
+ if (bitMapSize != cqExtUnit.bitMapSize) return false;
+ if (msgStoreTime != cqExtUnit.msgStoreTime) return false;
+ if (size != cqExtUnit.size) return false;
+ if (tagsCode != cqExtUnit.tagsCode) return false;
+ if (!Arrays.equals(filterBitMap, cqExtUnit.filterBitMap)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (int) size;
+ result = 31 * result + (int) (tagsCode ^ (tagsCode >>> 32));
+ result = 31 * result + (int) (msgStoreTime ^ (msgStoreTime >>> 32));
+ result = 31 * result + (int) bitMapSize;
+ result = 31 * result + (filterBitMap != null ? Arrays.hashCode(filterBitMap) : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "CqExtUnit{" +
+ "size=" + size +
+ ", tagsCode=" + tagsCode +
+ ", msgStoreTime=" + msgStoreTime +
+ ", bitMapSize=" + bitMapSize +
+ ", filterBitMap=" + Arrays.toString(filterBitMap) +
+ '}';
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageFilter.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageFilter.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageFilter.java
index 1350026..9db87f3 100644
--- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageFilter.java
+++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageFilter.java
@@ -18,26 +18,33 @@ package org.apache.rocketmq.store;
import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
public class DefaultMessageFilter implements MessageFilter {
- @Override
- public boolean isMessageMatched(SubscriptionData subscriptionData, Long tagsCode) {
- if (tagsCode == null) {
- return true;
- }
+ private SubscriptionData subscriptionData;
- if (null == subscriptionData) {
- return true;
- }
+ public DefaultMessageFilter(final SubscriptionData subscriptionData) {
+ this.subscriptionData = subscriptionData;
+ }
- if (subscriptionData.isClassFilterMode())
+ @Override
+ public boolean isMatchedByConsumeQueue(Long tagsCode, ConsumeQueueExt.CqExtUnit cqExtUnit) {
+ if (null == tagsCode || null == subscriptionData) {
return true;
+ }
- if (subscriptionData.getSubString().equals(SubscriptionData.SUB_ALL)) {
+ if (subscriptionData.isClassFilterMode()) {
return true;
}
- return subscriptionData.getCodeSet().contains(tagsCode.intValue());
+ return subscriptionData.getSubString().equals(SubscriptionData.SUB_ALL)
+ || subscriptionData.getCodeSet().contains(tagsCode.intValue());
}
+ @Override
+ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map<String, String> properties) {
+ return true;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
index 0edfeec..7bed62c 100644
--- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
@@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
@@ -41,7 +42,6 @@ import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.message.MessageDecoder;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageExtBatch;
-import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.common.running.RunningStats;
import org.apache.rocketmq.common.sysflag.MessageSysFlag;
import org.apache.rocketmq.store.config.BrokerRole;
@@ -60,8 +60,6 @@ import static org.apache.rocketmq.store.config.BrokerRole.SLAVE;
public class DefaultMessageStore implements MessageStore {
private static final Logger log = LoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);
- private final MessageFilter messageFilter = new DefaultMessageFilter();
-
private final MessageStoreConfig messageStoreConfig;
// CommitLog
private final CommitLog commitLog;
@@ -103,6 +101,8 @@ public class DefaultMessageStore implements MessageStore {
private AtomicLong printTimes = new AtomicLong(0);
+ private final LinkedList<CommitLogDispatcher> dispatcherList;
+
public DefaultMessageStore(final MessageStoreConfig messageStoreConfig, final BrokerStatsManager brokerStatsManager,
final MessageArrivingListener messageArrivingListener, final BrokerConfig brokerConfig) throws IOException {
this.messageArrivingListener = messageArrivingListener;
@@ -133,6 +133,10 @@ public class DefaultMessageStore implements MessageStore {
this.allocateMappedFileService.start();
this.indexService.start();
+
+ this.dispatcherList = new LinkedList<>();
+ this.dispatcherList.addLast(new CommitLogDispatcherBuildConsumeQueue());
+ this.dispatcherList.addLast(new CommitLogDispatcherBuildIndex());
}
public void truncateDirtyLogicFiles(long phyOffset) {
@@ -409,7 +413,7 @@ public class DefaultMessageStore implements MessageStore {
}
public GetMessageResult getMessage(final String group, final String topic, final int queueId, final long offset, final int maxMsgNums,
- final SubscriptionData subscriptionData) {
+ final MessageFilter messageFilter) {
if (this.shutdown) {
log.warn("message store has shutdown, so getMessage is forbidden");
return null;
@@ -464,6 +468,7 @@ public class DefaultMessageStore implements MessageStore {
int i = 0;
final int maxFilterMessageCount = Math.max(16000, maxMsgNums * ConsumeQueue.CQ_STORE_UNIT_SIZE);
final boolean diskFallRecorded = this.messageStoreConfig.isDiskFallRecorded();
+ ConsumeQueueExt.CqExtUnit cqExtUnit = new ConsumeQueueExt.CqExtUnit();
for (; i < bufferConsumeQueue.getSize() && i < maxFilterMessageCount; i += ConsumeQueue.CQ_STORE_UNIT_SIZE) {
long offsetPy = bufferConsumeQueue.getByteBuffer().getLong();
int sizePy = bufferConsumeQueue.getByteBuffer().getInt();
@@ -483,29 +488,51 @@ public class DefaultMessageStore implements MessageStore {
break;
}
- if (this.messageFilter.isMessageMatched(subscriptionData, tagsCode)) {
- SelectMappedBufferResult selectResult = this.commitLog.getMessage(offsetPy, sizePy);
- if (selectResult != null) {
- this.storeStatsService.getGetMessageTransferedMsgCount().incrementAndGet();
- getResult.addMessage(selectResult);
- status = GetMessageStatus.FOUND;
- nextPhyFileStartOffset = Long.MIN_VALUE;
+ boolean extRet = false;
+ if (consumeQueue.isExtAddr(tagsCode)) {
+ extRet = consumeQueue.getExt(tagsCode, cqExtUnit);
+ if (extRet) {
+ tagsCode = cqExtUnit.getTagsCode();
} else {
- if (getResult.getBufferTotalSize() == 0) {
- status = GetMessageStatus.MESSAGE_WAS_REMOVING;
- }
-
- nextPhyFileStartOffset = this.commitLog.rollNextFile(offsetPy);
+ // can't find ext content.Client will filter messages by tag also.
+ log.error("[BUG] can't find consume queue extend file content!addr={}, offsetPy={}, sizePy={}, topic={}, group={}",
+ tagsCode, offsetPy, sizePy, topic, group);
}
- } else {
+ }
+
+ if (messageFilter != null
+ && !messageFilter.isMatchedByConsumeQueue(tagsCode, extRet ? cqExtUnit : null)) {
if (getResult.getBufferTotalSize() == 0) {
status = GetMessageStatus.NO_MATCHED_MESSAGE;
}
- if (log.isDebugEnabled()) {
- log.debug("message type not matched, client: " + subscriptionData + " server: " + tagsCode);
+ continue;
+ }
+
+ SelectMappedBufferResult selectResult = this.commitLog.getMessage(offsetPy, sizePy);
+ if (null == selectResult) {
+ if (getResult.getBufferTotalSize() == 0) {
+ status = GetMessageStatus.MESSAGE_WAS_REMOVING;
+ }
+
+ nextPhyFileStartOffset = this.commitLog.rollNextFile(offsetPy);
+ continue;
+ }
+
+ if (messageFilter != null
+ && !messageFilter.isMatchedByCommitLog(selectResult.getByteBuffer().slice(), null)) {
+ if (getResult.getBufferTotalSize() == 0) {
+ status = GetMessageStatus.NO_MATCHED_MESSAGE;
}
+ // release...
+ selectResult.release();
+ continue;
}
+
+ this.storeStatsService.getGetMessageTransferedMsgCount().incrementAndGet();
+ getResult.addMessage(selectResult);
+ status = GetMessageStatus.FOUND;
+ nextPhyFileStartOffset = Long.MIN_VALUE;
}
if (diskFallRecorded) {
@@ -1318,27 +1345,14 @@ public class DefaultMessageStore implements MessageStore {
}
public void doDispatch(DispatchRequest req) {
- final int tranType = MessageSysFlag.getTransactionValue(req.getSysFlag());
- switch (tranType) {
- case MessageSysFlag.TRANSACTION_NOT_TYPE:
- case MessageSysFlag.TRANSACTION_COMMIT_TYPE:
- DefaultMessageStore.this.putMessagePositionInfo(req.getTopic(), req.getQueueId(), req.getCommitLogOffset(), req.getMsgSize(),
- req.getTagsCode(), req.getStoreTimestamp(), req.getConsumeQueueOffset());
- break;
- case MessageSysFlag.TRANSACTION_PREPARED_TYPE:
- case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE:
- break;
- }
-
- if (DefaultMessageStore.this.getMessageStoreConfig().isMessageIndexEnable()) {
- DefaultMessageStore.this.indexService.buildIndex(req);
+ for (CommitLogDispatcher dispatcher : this.dispatcherList) {
+ dispatcher.dispatch(req);
}
}
- public void putMessagePositionInfo(String topic, int queueId, long offset, int size, long tagsCode, long storeTimestamp,
- long logicOffset) {
- ConsumeQueue cq = this.findConsumeQueue(topic, queueId);
- cq.putMessagePositionInfoWrapper(offset, size, tagsCode, storeTimestamp, logicOffset);
+ public void putMessagePositionInfo(DispatchRequest dispatchRequest) {
+ ConsumeQueue cq = this.findConsumeQueue(dispatchRequest.getTopic(), dispatchRequest.getQueueId());
+ cq.putMessagePositionInfoWrapper(dispatchRequest);
}
public BrokerStatsManager getBrokerStatsManager() {
@@ -1354,6 +1368,20 @@ public class DefaultMessageStore implements MessageStore {
return remainTransientStoreBufferNumbs() == 0;
}
+ @Override
+ public LinkedList<CommitLogDispatcher> getDispatcherList() {
+ return this.dispatcherList;
+ }
+
+ @Override
+ public ConsumeQueue getConsumeQueue(String topic, int queueId) {
+ ConcurrentHashMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
+ if (map == null) {
+ return null;
+ }
+ return map.get(queueId);
+ }
+
public void unlockMappedFile(final MappedFile mappedFile) {
this.scheduledExecutorService.schedule(new Runnable() {
@Override
@@ -1363,6 +1391,33 @@ public class DefaultMessageStore implements MessageStore {
}, 6, TimeUnit.SECONDS);
}
+ class CommitLogDispatcherBuildConsumeQueue implements CommitLogDispatcher {
+
+ @Override
+ public void dispatch(DispatchRequest request) {
+ final int tranType = MessageSysFlag.getTransactionValue(request.getSysFlag());
+ switch (tranType) {
+ case MessageSysFlag.TRANSACTION_NOT_TYPE:
+ case MessageSysFlag.TRANSACTION_COMMIT_TYPE:
+ DefaultMessageStore.this.putMessagePositionInfo(request);
+ break;
+ case MessageSysFlag.TRANSACTION_PREPARED_TYPE:
+ case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE:
+ break;
+ }
+ }
+ }
+
+ class CommitLogDispatcherBuildIndex implements CommitLogDispatcher {
+
+ @Override
+ public void dispatch(DispatchRequest request) {
+ if (DefaultMessageStore.this.messageStoreConfig.isMessageIndexEnable()) {
+ DefaultMessageStore.this.indexService.buildIndex(request);
+ }
+ }
+ }
+
class CleanCommitLogService {
private final static int MAX_MANUAL_DELETE_FILE_TIMES = 20;
@@ -1695,7 +1750,8 @@ public class DefaultMessageStore implements MessageStore {
&& DefaultMessageStore.this.brokerConfig.isLongPollingEnable()) {
DefaultMessageStore.this.messageArrivingListener.arriving(dispatchRequest.getTopic(),
dispatchRequest.getQueueId(), dispatchRequest.getConsumeQueueOffset() + 1,
- dispatchRequest.getTagsCode());
+ dispatchRequest.getTagsCode(), dispatchRequest.getStoreTimestamp(),
+ dispatchRequest.getBitMap(), dispatchRequest.getPropertiesMap());
}
// FIXED BUG By shijia
this.reputFromOffset += size;
[22/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-186]
Implement the OpenMessaging specification 0.1.0-alpha version
Posted by do...@apache.org.
[ROCKETMQ-186] Implement the OpenMessaging specification 0.1.0-alpha version
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/1d966b50
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/1d966b50
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/1d966b50
Branch: refs/heads/release-4.1.0-incubating
Commit: 1d966b50c2ec189ca4f1bf81420959a33159a8ad
Parents: 1630f27
Author: yukon <yu...@apache.org>
Authored: Wed May 24 16:50:51 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Wed May 24 16:50:51 2017 +0800
----------------------------------------------------------------------
distribution/release-client.xml | 1 +
distribution/release.xml | 1 +
example/pom.xml | 9 +
.../example/openmessaging/SimpleProducer.java | 76 +++++++
.../openmessaging/SimplePullConsumer.java | 58 +++++
.../openmessaging/SimplePushConsumer.java | 59 +++++
openmessaging/pom.xml | 42 ++++
.../rocketmq/MessagingAccessPointImpl.java | 132 +++++++++++
.../rocketmq/config/ClientConfig.java | 194 ++++++++++++++++
.../rocketmq/consumer/LocalMessageCache.java | 213 +++++++++++++++++
.../rocketmq/consumer/PullConsumerImpl.java | 166 ++++++++++++++
.../rocketmq/consumer/PushConsumerImpl.java | 181 +++++++++++++++
.../rocketmq/domain/BytesMessageImpl.java | 108 +++++++++
.../rocketmq/domain/ConsumeRequest.java | 55 +++++
.../rocketmq/domain/NonStandardKeys.java | 30 +++
.../rocketmq/domain/SendResultImpl.java | 40 ++++
.../rocketmq/producer/AbstractOMSProducer.java | 138 +++++++++++
.../rocketmq/producer/ProducerImpl.java | 124 ++++++++++
.../rocketmq/producer/SequenceProducerImpl.java | 95 ++++++++
.../rocketmq/promise/DefaultPromise.java | 227 +++++++++++++++++++
.../rocketmq/promise/FutureState.java | 51 +++++
.../openmessaging/rocketmq/utils/BeanUtils.java | 185 +++++++++++++++
.../openmessaging/rocketmq/utils/OMSUtil.java | 182 +++++++++++++++
.../consumer/LocalMessageCacheTest.java | 89 ++++++++
.../rocketmq/consumer/PullConsumerImplTest.java | 96 ++++++++
.../rocketmq/consumer/PushConsumerImplTest.java | 87 +++++++
.../rocketmq/producer/ProducerImplTest.java | 101 +++++++++
.../producer/SequenceProducerImplTest.java | 86 +++++++
.../rocketmq/promise/DefaultPromiseTest.java | 136 +++++++++++
.../rocketmq/utils/BeanUtilsTest.java | 110 +++++++++
pom.xml | 6 +
31 files changed, 3078 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/distribution/release-client.xml
----------------------------------------------------------------------
diff --git a/distribution/release-client.xml b/distribution/release-client.xml
index 46563eb..84d33a0 100644
--- a/distribution/release-client.xml
+++ b/distribution/release-client.xml
@@ -47,6 +47,7 @@
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
<include>org.apache.rocketmq:rocketmq-client</include>
+ <include>org.apache.rocketmq:rocketmq-openmessaging</include>
</includes>
<binaries>
<outputDirectory>./</outputDirectory>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/distribution/release.xml
----------------------------------------------------------------------
diff --git a/distribution/release.xml b/distribution/release.xml
index 9e4ef2a..c67d23e 100644
--- a/distribution/release.xml
+++ b/distribution/release.xml
@@ -68,6 +68,7 @@
<include>org.apache.rocketmq:rocketmq-filtersrv</include>
<include>org.apache.rocketmq:rocketmq-example</include>
<include>org.apache.rocketmq:rocketmq-filter</include>
+ <include>org.apache.rocketmq:rocketmq-openmessaging</include>
</includes>
<binaries>
<outputDirectory>lib/</outputDirectory>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/example/pom.xml
----------------------------------------------------------------------
diff --git a/example/pom.xml b/example/pom.xml
index 785a4ca..840fa36 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -48,5 +48,14 @@
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
+ <dependency>
+ <groupId>io.openmessaging</groupId>
+ <artifactId>openmessaging-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-openmessaging</artifactId>
+ <version>4.1.0-incubating-SNAPSHOT</version>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimpleProducer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimpleProducer.java b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimpleProducer.java
new file mode 100644
index 0000000..9d162ac
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimpleProducer.java
@@ -0,0 +1,76 @@
+/*
+ * 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.example.openmessaging;
+
+import io.openmessaging.Message;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.Producer;
+import io.openmessaging.Promise;
+import io.openmessaging.PromiseListener;
+import io.openmessaging.SendResult;
+import java.nio.charset.Charset;
+
+public class SimpleProducer {
+ public static void main(String[] args) {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+
+ final Producer producer = messagingAccessPoint.createProducer();
+
+ messagingAccessPoint.startup();
+ System.out.printf("MessagingAccessPoint startup OK%n");
+
+ producer.startup();
+ System.out.printf("Producer startup OK%n");
+
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ producer.shutdown();
+ messagingAccessPoint.shutdown();
+ }
+ }));
+
+ {
+ Message message = producer.createBytesMessageToTopic("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8")));
+ SendResult sendResult = producer.send(message);
+ //final Void aVoid = result.get(3000L);
+ System.out.printf("Send async message OK, msgId: %s%n", sendResult.messageId());
+ }
+
+ {
+ final Promise<SendResult> result = producer.sendAsync(producer.createBytesMessageToTopic("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8"))));
+ result.addListener(new PromiseListener<SendResult>() {
+ @Override
+ public void operationCompleted(Promise<SendResult> promise) {
+ System.out.printf("Send async message OK, msgId: %s%n", promise.get().messageId());
+ }
+
+ @Override
+ public void operationFailed(Promise<SendResult> promise) {
+ System.out.printf("Send async message Failed, error: %s%n", promise.getThrowable().getMessage());
+ }
+ });
+ }
+
+ {
+ producer.sendOneway(producer.createBytesMessageToTopic("OMS_HELLO_TOPIC", "OMS_HELLO_BODY".getBytes(Charset.forName("UTF-8"))));
+ System.out.printf("Send oneway message OK%n");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePullConsumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePullConsumer.java b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePullConsumer.java
new file mode 100644
index 0000000..8e06772
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePullConsumer.java
@@ -0,0 +1,58 @@
+/*
+ * 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.example.openmessaging;
+
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.OMS;
+import io.openmessaging.PullConsumer;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+
+public class SimplePullConsumer {
+ public static void main(String[] args) {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+
+ final PullConsumer consumer = messagingAccessPoint.createPullConsumer("OMS_HELLO_TOPIC",
+ OMS.newKeyValue().put(NonStandardKeys.CONSUMER_GROUP, "OMS_CONSUMER"));
+
+ messagingAccessPoint.startup();
+ System.out.printf("MessagingAccessPoint startup OK%n");
+
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ consumer.shutdown();
+ messagingAccessPoint.shutdown();
+ }
+ }));
+
+ consumer.startup();
+ System.out.printf("Consumer startup OK%n");
+
+ while (true) {
+ Message message = consumer.poll();
+ if (message != null) {
+ String msgId = message.headers().getString(MessageHeader.MESSAGE_ID);
+ System.out.printf("Received one message: %s%n", msgId);
+ consumer.ack(msgId);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePushConsumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePushConsumer.java b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePushConsumer.java
new file mode 100644
index 0000000..b0935d4
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/openmessaging/SimplePushConsumer.java
@@ -0,0 +1,59 @@
+/*
+ * 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.example.openmessaging;
+
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.MessageListener;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.OMS;
+import io.openmessaging.PushConsumer;
+import io.openmessaging.ReceivedMessageContext;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+
+public class SimplePushConsumer {
+ public static void main(String[] args) {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+
+ final PushConsumer consumer = messagingAccessPoint.
+ createPushConsumer(OMS.newKeyValue().put(NonStandardKeys.CONSUMER_GROUP, "OMS_CONSUMER"));
+
+ messagingAccessPoint.startup();
+ System.out.printf("MessagingAccessPoint startup OK%n");
+
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ consumer.shutdown();
+ messagingAccessPoint.shutdown();
+ }
+ }));
+
+ consumer.attachQueue("OMS_HELLO_TOPIC", new MessageListener() {
+ @Override
+ public void onMessage(final Message message, final ReceivedMessageContext context) {
+ System.out.printf("Received one message: %s%n", message.headers().getString(MessageHeader.MESSAGE_ID));
+ context.ack();
+ }
+ });
+
+ consumer.startup();
+ System.out.printf("Consumer startup OK%n");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/pom.xml
----------------------------------------------------------------------
diff --git a/openmessaging/pom.xml b/openmessaging/pom.xml
new file mode 100644
index 0000000..e853642
--- /dev/null
+++ b/openmessaging/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>rocketmq-all</artifactId>
+ <groupId>org.apache.rocketmq</groupId>
+ <version>4.1.0-incubating-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>rocketmq-openmessaging</artifactId>
+ <name>rocketmq-openmessaging ${project.version}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>io.openmessaging</groupId>
+ <artifactId>openmessaging-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-client</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/MessagingAccessPointImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/MessagingAccessPointImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/MessagingAccessPointImpl.java
new file mode 100644
index 0000000..65caf84
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/MessagingAccessPointImpl.java
@@ -0,0 +1,132 @@
+/*
+ * 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 io.openmessaging.rocketmq;
+
+import io.openmessaging.IterableConsumer;
+import io.openmessaging.KeyValue;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.Producer;
+import io.openmessaging.PullConsumer;
+import io.openmessaging.PushConsumer;
+import io.openmessaging.ResourceManager;
+import io.openmessaging.SequenceProducer;
+import io.openmessaging.ServiceEndPoint;
+import io.openmessaging.exception.OMSNotSupportedException;
+import io.openmessaging.observer.Observer;
+import io.openmessaging.rocketmq.consumer.PullConsumerImpl;
+import io.openmessaging.rocketmq.consumer.PushConsumerImpl;
+import io.openmessaging.rocketmq.producer.ProducerImpl;
+import io.openmessaging.rocketmq.producer.SequenceProducerImpl;
+import io.openmessaging.rocketmq.utils.OMSUtil;
+
+public class MessagingAccessPointImpl implements MessagingAccessPoint {
+ private final KeyValue accessPointProperties;
+
+ public MessagingAccessPointImpl(final KeyValue accessPointProperties) {
+ this.accessPointProperties = accessPointProperties;
+ }
+
+ @Override
+ public KeyValue properties() {
+ return accessPointProperties;
+ }
+
+ @Override
+ public Producer createProducer() {
+ return new ProducerImpl(this.accessPointProperties);
+ }
+
+ @Override
+ public Producer createProducer(KeyValue properties) {
+ return new ProducerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, properties));
+ }
+
+ @Override
+ public SequenceProducer createSequenceProducer() {
+ return new SequenceProducerImpl(this.accessPointProperties);
+ }
+
+ @Override
+ public SequenceProducer createSequenceProducer(KeyValue properties) {
+ return new SequenceProducerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, properties));
+ }
+
+ @Override
+ public PushConsumer createPushConsumer() {
+ return new PushConsumerImpl(accessPointProperties);
+ }
+
+ @Override
+ public PushConsumer createPushConsumer(KeyValue properties) {
+ return new PushConsumerImpl(OMSUtil.buildKeyValue(this.accessPointProperties, properties));
+ }
+
+ @Override
+ public PullConsumer createPullConsumer(String queueName) {
+ return new PullConsumerImpl(queueName, accessPointProperties);
+ }
+
+ @Override
+ public PullConsumer createPullConsumer(String queueName, KeyValue properties) {
+ return new PullConsumerImpl(queueName, OMSUtil.buildKeyValue(this.accessPointProperties, properties));
+ }
+
+ @Override
+ public IterableConsumer createIterableConsumer(String queueName) {
+ throw new OMSNotSupportedException("-1", "IterableConsumer is not supported in current version");
+ }
+
+ @Override
+ public IterableConsumer createIterableConsumer(String queueName, KeyValue properties) {
+ throw new OMSNotSupportedException("-1", "IterableConsumer is not supported in current version");
+ }
+
+ @Override
+ public ResourceManager getResourceManager() {
+ throw new OMSNotSupportedException("-1", "ResourceManager is not supported in current version.");
+ }
+
+ @Override
+ public ServiceEndPoint createServiceEndPoint() {
+ throw new OMSNotSupportedException("-1", "ServiceEndPoint is not supported in current version.");
+ }
+
+ @Override
+ public ServiceEndPoint createServiceEndPoint(KeyValue properties) {
+ throw new OMSNotSupportedException("-1", "ServiceEndPoint is not supported in current version.");
+ }
+
+ @Override
+ public void addObserver(Observer observer) {
+ //Ignore
+ }
+
+ @Override
+ public void deleteObserver(Observer observer) {
+ //Ignore
+ }
+
+ @Override
+ public void startup() {
+ //Ignore
+ }
+
+ @Override
+ public void shutdown() {
+ //Ignore
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/config/ClientConfig.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/config/ClientConfig.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/config/ClientConfig.java
new file mode 100644
index 0000000..7077c6d
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/config/ClientConfig.java
@@ -0,0 +1,194 @@
+/*
+ * 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 io.openmessaging.rocketmq.config;
+
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+
+public class ClientConfig implements PropertyKeys, NonStandardKeys {
+ private String omsDriverImpl;
+ private String omsAccessPoints;
+ private String omsNamespace;
+ private String omsProducerId;
+ private String omsConsumerId;
+ private int omsOperationTimeout = 5000;
+ private String omsRoutingName;
+ private String omsOperatorName;
+ private String omsDstQueue;
+ private String omsSrcTopic;
+ private String rmqConsumerGroup;
+ private String rmqProducerGroup = "__OMS_PRODUCER_DEFAULT_GROUP";
+ private int rmqMaxRedeliveryTimes = 16;
+ private int rmqMessageConsumeTimeout = 15; //In minutes
+ private int rmqMaxConsumeThreadNums = 64;
+ private int rmqMinConsumeThreadNums = 20;
+ private String rmqMessageDestination;
+ private int rmqPullMessageBatchNums = 32;
+ private int rmqPullMessageCacheCapacity = 1000;
+
+ public String getOmsDriverImpl() {
+ return omsDriverImpl;
+ }
+
+ public void setOmsDriverImpl(final String omsDriverImpl) {
+ this.omsDriverImpl = omsDriverImpl;
+ }
+
+ public String getOmsAccessPoints() {
+ return omsAccessPoints;
+ }
+
+ public void setOmsAccessPoints(final String omsAccessPoints) {
+ this.omsAccessPoints = omsAccessPoints;
+ }
+
+ public String getOmsNamespace() {
+ return omsNamespace;
+ }
+
+ public void setOmsNamespace(final String omsNamespace) {
+ this.omsNamespace = omsNamespace;
+ }
+
+ public String getOmsProducerId() {
+ return omsProducerId;
+ }
+
+ public void setOmsProducerId(final String omsProducerId) {
+ this.omsProducerId = omsProducerId;
+ }
+
+ public String getOmsConsumerId() {
+ return omsConsumerId;
+ }
+
+ public void setOmsConsumerId(final String omsConsumerId) {
+ this.omsConsumerId = omsConsumerId;
+ }
+
+ public int getOmsOperationTimeout() {
+ return omsOperationTimeout;
+ }
+
+ public void setOmsOperationTimeout(final int omsOperationTimeout) {
+ this.omsOperationTimeout = omsOperationTimeout;
+ }
+
+ public String getOmsRoutingName() {
+ return omsRoutingName;
+ }
+
+ public void setOmsRoutingName(final String omsRoutingName) {
+ this.omsRoutingName = omsRoutingName;
+ }
+
+ public String getOmsOperatorName() {
+ return omsOperatorName;
+ }
+
+ public void setOmsOperatorName(final String omsOperatorName) {
+ this.omsOperatorName = omsOperatorName;
+ }
+
+ public String getOmsDstQueue() {
+ return omsDstQueue;
+ }
+
+ public void setOmsDstQueue(final String omsDstQueue) {
+ this.omsDstQueue = omsDstQueue;
+ }
+
+ public String getOmsSrcTopic() {
+ return omsSrcTopic;
+ }
+
+ public void setOmsSrcTopic(final String omsSrcTopic) {
+ this.omsSrcTopic = omsSrcTopic;
+ }
+
+ public String getRmqConsumerGroup() {
+ return rmqConsumerGroup;
+ }
+
+ public void setRmqConsumerGroup(final String rmqConsumerGroup) {
+ this.rmqConsumerGroup = rmqConsumerGroup;
+ }
+
+ public String getRmqProducerGroup() {
+ return rmqProducerGroup;
+ }
+
+ public void setRmqProducerGroup(final String rmqProducerGroup) {
+ this.rmqProducerGroup = rmqProducerGroup;
+ }
+
+ public int getRmqMaxRedeliveryTimes() {
+ return rmqMaxRedeliveryTimes;
+ }
+
+ public void setRmqMaxRedeliveryTimes(final int rmqMaxRedeliveryTimes) {
+ this.rmqMaxRedeliveryTimes = rmqMaxRedeliveryTimes;
+ }
+
+ public int getRmqMessageConsumeTimeout() {
+ return rmqMessageConsumeTimeout;
+ }
+
+ public void setRmqMessageConsumeTimeout(final int rmqMessageConsumeTimeout) {
+ this.rmqMessageConsumeTimeout = rmqMessageConsumeTimeout;
+ }
+
+ public int getRmqMaxConsumeThreadNums() {
+ return rmqMaxConsumeThreadNums;
+ }
+
+ public void setRmqMaxConsumeThreadNums(final int rmqMaxConsumeThreadNums) {
+ this.rmqMaxConsumeThreadNums = rmqMaxConsumeThreadNums;
+ }
+
+ public int getRmqMinConsumeThreadNums() {
+ return rmqMinConsumeThreadNums;
+ }
+
+ public void setRmqMinConsumeThreadNums(final int rmqMinConsumeThreadNums) {
+ this.rmqMinConsumeThreadNums = rmqMinConsumeThreadNums;
+ }
+
+ public String getRmqMessageDestination() {
+ return rmqMessageDestination;
+ }
+
+ public void setRmqMessageDestination(final String rmqMessageDestination) {
+ this.rmqMessageDestination = rmqMessageDestination;
+ }
+
+ public int getRmqPullMessageBatchNums() {
+ return rmqPullMessageBatchNums;
+ }
+
+ public void setRmqPullMessageBatchNums(final int rmqPullMessageBatchNums) {
+ this.rmqPullMessageBatchNums = rmqPullMessageBatchNums;
+ }
+
+ public int getRmqPullMessageCacheCapacity() {
+ return rmqPullMessageCacheCapacity;
+ }
+
+ public void setRmqPullMessageCacheCapacity(final int rmqPullMessageCacheCapacity) {
+ this.rmqPullMessageCacheCapacity = rmqPullMessageCacheCapacity;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/LocalMessageCache.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/LocalMessageCache.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/LocalMessageCache.java
new file mode 100644
index 0000000..90f9e03
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/LocalMessageCache.java
@@ -0,0 +1,213 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.KeyValue;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.ServiceLifecycle;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.ConsumeRequest;
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.consumer.ProcessQueue;
+import org.apache.rocketmq.client.log.ClientLogger;
+import org.apache.rocketmq.common.ThreadFactoryImpl;
+import org.apache.rocketmq.common.message.MessageAccessor;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.apache.rocketmq.common.utils.ThreadUtils;
+import org.slf4j.Logger;
+
+class LocalMessageCache implements ServiceLifecycle {
+ private final BlockingQueue<ConsumeRequest> consumeRequestCache;
+ private final Map<String, ConsumeRequest> consumedRequest;
+ private final ConcurrentHashMap<MessageQueue, Long> pullOffsetTable;
+ private final DefaultMQPullConsumer rocketmqPullConsumer;
+ private final ClientConfig clientConfig;
+ private final ScheduledExecutorService cleanExpireMsgExecutors;
+
+ private final static Logger log = ClientLogger.getLog();
+
+ LocalMessageCache(final DefaultMQPullConsumer rocketmqPullConsumer, final ClientConfig clientConfig) {
+ consumeRequestCache = new LinkedBlockingQueue<>(clientConfig.getRmqPullMessageCacheCapacity());
+ this.consumedRequest = new ConcurrentHashMap<>();
+ this.pullOffsetTable = new ConcurrentHashMap<>();
+ this.rocketmqPullConsumer = rocketmqPullConsumer;
+ this.clientConfig = clientConfig;
+ this.cleanExpireMsgExecutors = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryImpl(
+ "OMS_CleanExpireMsgScheduledThread_"));
+ }
+
+ int nextPullBatchNums() {
+ return Math.min(clientConfig.getRmqPullMessageBatchNums(), consumeRequestCache.remainingCapacity());
+ }
+
+ long nextPullOffset(MessageQueue remoteQueue) {
+ if (!pullOffsetTable.containsKey(remoteQueue)) {
+ try {
+ pullOffsetTable.putIfAbsent(remoteQueue,
+ rocketmqPullConsumer.fetchConsumeOffset(remoteQueue, false));
+ } catch (MQClientException e) {
+ log.error("A error occurred in fetch consume offset process.", e);
+ }
+ }
+ return pullOffsetTable.get(remoteQueue);
+ }
+
+ void updatePullOffset(MessageQueue remoteQueue, long nextPullOffset) {
+ pullOffsetTable.put(remoteQueue, nextPullOffset);
+ }
+
+ void submitConsumeRequest(ConsumeRequest consumeRequest) {
+ try {
+ consumeRequestCache.put(consumeRequest);
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ MessageExt poll() {
+ return poll(clientConfig.getOmsOperationTimeout());
+ }
+
+ MessageExt poll(final KeyValue properties) {
+ int currentPollTimeout = clientConfig.getOmsOperationTimeout();
+ if (properties.containsKey(PropertyKeys.OPERATION_TIMEOUT)) {
+ currentPollTimeout = properties.getInt(PropertyKeys.OPERATION_TIMEOUT);
+ }
+ return poll(currentPollTimeout);
+ }
+
+ private MessageExt poll(long timeout) {
+ try {
+ ConsumeRequest consumeRequest = consumeRequestCache.poll(timeout, TimeUnit.MILLISECONDS);
+ if (consumeRequest != null) {
+ MessageExt messageExt = consumeRequest.getMessageExt();
+ consumeRequest.setStartConsumeTimeMillis(System.currentTimeMillis());
+ MessageAccessor.setConsumeStartTimeStamp(messageExt, String.valueOf(consumeRequest.getStartConsumeTimeMillis()));
+ consumedRequest.put(messageExt.getMsgId(), consumeRequest);
+ return messageExt;
+ }
+ } catch (InterruptedException ignore) {
+ }
+ return null;
+ }
+
+ void ack(final String messageId) {
+ ConsumeRequest consumeRequest = consumedRequest.remove(messageId);
+ if (consumeRequest != null) {
+ long offset = consumeRequest.getProcessQueue().removeMessage(Collections.singletonList(consumeRequest.getMessageExt()));
+ try {
+ rocketmqPullConsumer.updateConsumeOffset(consumeRequest.getMessageQueue(), offset);
+ } catch (MQClientException e) {
+ log.error("A error occurred in update consume offset process.", e);
+ }
+ }
+ }
+
+ void ack(final MessageQueue messageQueue, final ProcessQueue processQueue, final MessageExt messageExt) {
+ consumedRequest.remove(messageExt.getMsgId());
+ long offset = processQueue.removeMessage(Collections.singletonList(messageExt));
+ try {
+ rocketmqPullConsumer.updateConsumeOffset(messageQueue, offset);
+ } catch (MQClientException e) {
+ log.error("A error occurred in update consume offset process.", e);
+ }
+ }
+
+ @Override
+ public void startup() {
+ this.cleanExpireMsgExecutors.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ cleanExpireMsg();
+ }
+ }, clientConfig.getRmqMessageConsumeTimeout(), clientConfig.getRmqMessageConsumeTimeout(), TimeUnit.MINUTES);
+ }
+
+ @Override
+ public void shutdown() {
+ ThreadUtils.shutdownGracefully(cleanExpireMsgExecutors, 5000, TimeUnit.MILLISECONDS);
+ }
+
+ private void cleanExpireMsg() {
+ for (final Map.Entry<MessageQueue, ProcessQueue> next : rocketmqPullConsumer.getDefaultMQPullConsumerImpl()
+ .getRebalanceImpl().getProcessQueueTable().entrySet()) {
+ ProcessQueue pq = next.getValue();
+ MessageQueue mq = next.getKey();
+ ReadWriteLock lockTreeMap = getLockInProcessQueue(pq);
+ if (lockTreeMap == null) {
+ log.error("Gets tree map lock in process queue error, may be has compatibility issue");
+ return;
+ }
+
+ TreeMap<Long, MessageExt> msgTreeMap = pq.getMsgTreeMap();
+
+ int loop = msgTreeMap.size();
+ for (int i = 0; i < loop; i++) {
+ MessageExt msg = null;
+ try {
+ lockTreeMap.readLock().lockInterruptibly();
+ try {
+ if (!msgTreeMap.isEmpty()) {
+ msg = msgTreeMap.firstEntry().getValue();
+ if (System.currentTimeMillis() - Long.parseLong(MessageAccessor.getConsumeStartTimeStamp(msg))
+ > clientConfig.getRmqMessageConsumeTimeout() * 60 * 1000) {
+ //Expired, ack and remove it.
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ } finally {
+ lockTreeMap.readLock().unlock();
+ }
+ } catch (InterruptedException e) {
+ log.error("Gets expired message exception", e);
+ }
+
+ try {
+ rocketmqPullConsumer.sendMessageBack(msg, 3);
+ log.info("Send expired msg back. topic={}, msgId={}, storeHost={}, queueId={}, queueOffset={}",
+ msg.getTopic(), msg.getMsgId(), msg.getStoreHost(), msg.getQueueId(), msg.getQueueOffset());
+ ack(mq, pq, msg);
+ } catch (Exception e) {
+ log.error("Send back expired msg exception", e);
+ }
+ }
+ }
+ }
+
+ private ReadWriteLock getLockInProcessQueue(ProcessQueue pq) {
+ try {
+ return (ReadWriteLock) FieldUtils.readDeclaredField(pq, "lockTreeMap", true);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
new file mode 100644
index 0000000..8d396d4
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PullConsumerImpl.java
@@ -0,0 +1,166 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.KeyValue;
+import io.openmessaging.Message;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.PullConsumer;
+import io.openmessaging.exception.OMSRuntimeException;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.ConsumeRequest;
+import io.openmessaging.rocketmq.utils.BeanUtils;
+import io.openmessaging.rocketmq.utils.OMSUtil;
+import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
+import org.apache.rocketmq.client.consumer.MQPullConsumer;
+import org.apache.rocketmq.client.consumer.MQPullConsumerScheduleService;
+import org.apache.rocketmq.client.consumer.PullResult;
+import org.apache.rocketmq.client.consumer.PullTaskCallback;
+import org.apache.rocketmq.client.consumer.PullTaskContext;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.impl.consumer.ProcessQueue;
+import org.apache.rocketmq.client.log.ClientLogger;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.slf4j.Logger;
+
+public class PullConsumerImpl implements PullConsumer {
+ private final DefaultMQPullConsumer rocketmqPullConsumer;
+ private final KeyValue properties;
+ private boolean started = false;
+ private String targetQueueName;
+ private final MQPullConsumerScheduleService pullConsumerScheduleService;
+ private final LocalMessageCache localMessageCache;
+ private final ClientConfig clientConfig;
+
+ final static Logger log = ClientLogger.getLog();
+
+ public PullConsumerImpl(final String queueName, final KeyValue properties) {
+ this.properties = properties;
+ this.targetQueueName = queueName;
+
+ this.clientConfig = BeanUtils.populate(properties, ClientConfig.class);
+
+ String consumerGroup = clientConfig.getRmqConsumerGroup();
+ if (null == consumerGroup || consumerGroup.isEmpty()) {
+ throw new OMSRuntimeException("-1", "Consumer Group is necessary for RocketMQ, please set it.");
+ }
+ pullConsumerScheduleService = new MQPullConsumerScheduleService(consumerGroup);
+
+ this.rocketmqPullConsumer = pullConsumerScheduleService.getDefaultMQPullConsumer();
+
+ String accessPoints = clientConfig.getOmsAccessPoints();
+ if (accessPoints == null || accessPoints.isEmpty()) {
+ throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty.");
+ }
+ this.rocketmqPullConsumer.setNamesrvAddr(accessPoints.replace(',', ';'));
+
+ this.rocketmqPullConsumer.setConsumerGroup(consumerGroup);
+
+ int maxReDeliveryTimes = clientConfig.getRmqMaxRedeliveryTimes();
+ this.rocketmqPullConsumer.setMaxReconsumeTimes(maxReDeliveryTimes);
+
+ String consumerId = OMSUtil.buildInstanceName();
+ this.rocketmqPullConsumer.setInstanceName(consumerId);
+ properties.put(PropertyKeys.CONSUMER_ID, consumerId);
+
+ this.localMessageCache = new LocalMessageCache(this.rocketmqPullConsumer, clientConfig);
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+
+ @Override
+ public Message poll() {
+ MessageExt rmqMsg = localMessageCache.poll();
+ return rmqMsg == null ? null : OMSUtil.msgConvert(rmqMsg);
+ }
+
+ @Override
+ public Message poll(final KeyValue properties) {
+ MessageExt rmqMsg = localMessageCache.poll(properties);
+ return rmqMsg == null ? null : OMSUtil.msgConvert(rmqMsg);
+ }
+
+ @Override
+ public void ack(final String messageId) {
+ localMessageCache.ack(messageId);
+ }
+
+ @Override
+ public void ack(final String messageId, final KeyValue properties) {
+ localMessageCache.ack(messageId);
+ }
+
+ @Override
+ public synchronized void startup() {
+ if (!started) {
+ try {
+ registerPullTaskCallback();
+ this.pullConsumerScheduleService.start();
+ this.localMessageCache.startup();
+ } catch (MQClientException e) {
+ throw new OMSRuntimeException("-1", e);
+ }
+ }
+ this.started = true;
+ }
+
+ private void registerPullTaskCallback() {
+ this.pullConsumerScheduleService.registerPullTaskCallback(targetQueueName, new PullTaskCallback() {
+ @Override
+ public void doPullTask(final MessageQueue mq, final PullTaskContext context) {
+ MQPullConsumer consumer = context.getPullConsumer();
+ try {
+ long offset = localMessageCache.nextPullOffset(mq);
+
+ PullResult pullResult = consumer.pull(mq, "*",
+ offset, localMessageCache.nextPullBatchNums());
+ ProcessQueue pq = rocketmqPullConsumer.getDefaultMQPullConsumerImpl().getRebalanceImpl()
+ .getProcessQueueTable().get(mq);
+ switch (pullResult.getPullStatus()) {
+ case FOUND:
+ if (pq != null) {
+ pq.putMessage(pullResult.getMsgFoundList());
+ for (final MessageExt messageExt : pullResult.getMsgFoundList()) {
+ localMessageCache.submitConsumeRequest(new ConsumeRequest(messageExt, mq, pq));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ localMessageCache.updatePullOffset(mq, pullResult.getNextBeginOffset());
+ } catch (Exception e) {
+ log.error("A error occurred in pull message process.", e);
+ }
+ }
+ });
+ }
+
+ @Override
+ public synchronized void shutdown() {
+ if (this.started) {
+ this.localMessageCache.shutdown();
+ this.pullConsumerScheduleService.shutdown();
+ this.rocketmqPullConsumer.shutdown();
+ }
+ this.started = false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
new file mode 100644
index 0000000..f9b8058
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/consumer/PushConsumerImpl.java
@@ -0,0 +1,181 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.MessageListener;
+import io.openmessaging.OMS;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.PushConsumer;
+import io.openmessaging.ReceivedMessageContext;
+import io.openmessaging.exception.OMSRuntimeException;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import io.openmessaging.rocketmq.utils.BeanUtils;
+import io.openmessaging.rocketmq.utils.OMSUtil;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+public class PushConsumerImpl implements PushConsumer {
+ private final DefaultMQPushConsumer rocketmqPushConsumer;
+ private final KeyValue properties;
+ private boolean started = false;
+ private final Map<String, MessageListener> subscribeTable = new ConcurrentHashMap<>();
+ private final ClientConfig clientConfig;
+
+ public PushConsumerImpl(final KeyValue properties) {
+ this.rocketmqPushConsumer = new DefaultMQPushConsumer();
+ this.properties = properties;
+ this.clientConfig = BeanUtils.populate(properties, ClientConfig.class);
+
+ String accessPoints = clientConfig.getOmsAccessPoints();
+ if (accessPoints == null || accessPoints.isEmpty()) {
+ throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty.");
+ }
+ this.rocketmqPushConsumer.setNamesrvAddr(accessPoints.replace(',', ';'));
+
+ String consumerGroup = clientConfig.getRmqConsumerGroup();
+ if (null == consumerGroup || consumerGroup.isEmpty()) {
+ throw new OMSRuntimeException("-1", "Consumer Group is necessary for RocketMQ, please set it.");
+ }
+ this.rocketmqPushConsumer.setConsumerGroup(consumerGroup);
+ this.rocketmqPushConsumer.setMaxReconsumeTimes(clientConfig.getRmqMaxRedeliveryTimes());
+ this.rocketmqPushConsumer.setConsumeTimeout(clientConfig.getRmqMessageConsumeTimeout());
+ this.rocketmqPushConsumer.setConsumeThreadMax(clientConfig.getRmqMaxConsumeThreadNums());
+ this.rocketmqPushConsumer.setConsumeThreadMin(clientConfig.getRmqMinConsumeThreadNums());
+
+ String consumerId = OMSUtil.buildInstanceName();
+ this.rocketmqPushConsumer.setInstanceName(consumerId);
+ properties.put(PropertyKeys.CONSUMER_ID, consumerId);
+
+ this.rocketmqPushConsumer.registerMessageListener(new MessageListenerImpl());
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+
+ @Override
+ public void resume() {
+ this.rocketmqPushConsumer.resume();
+ }
+
+ @Override
+ public void suspend() {
+ this.rocketmqPushConsumer.suspend();
+ }
+
+ @Override
+ public boolean isSuspended() {
+ return this.rocketmqPushConsumer.getDefaultMQPushConsumerImpl().isPause();
+ }
+
+ @Override
+ public PushConsumer attachQueue(final String queueName, final MessageListener listener) {
+ this.subscribeTable.put(queueName, listener);
+ try {
+ this.rocketmqPushConsumer.subscribe(queueName, "*");
+ } catch (MQClientException e) {
+ throw new OMSRuntimeException("-1", String.format("RocketMQ push consumer can't attach to %s.", queueName));
+ }
+ return this;
+ }
+
+ @Override
+ public synchronized void startup() {
+ if (!started) {
+ try {
+ this.rocketmqPushConsumer.start();
+ } catch (MQClientException e) {
+ throw new OMSRuntimeException("-1", e);
+ }
+ }
+ this.started = true;
+ }
+
+ @Override
+ public synchronized void shutdown() {
+ if (this.started) {
+ this.rocketmqPushConsumer.shutdown();
+ }
+ this.started = false;
+ }
+
+ class MessageListenerImpl implements MessageListenerConcurrently {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> rmqMsgList,
+ ConsumeConcurrentlyContext contextRMQ) {
+ MessageExt rmqMsg = rmqMsgList.get(0);
+ BytesMessage omsMsg = OMSUtil.msgConvert(rmqMsg);
+
+ MessageListener listener = PushConsumerImpl.this.subscribeTable.get(rmqMsg.getTopic());
+
+ if (listener == null) {
+ throw new OMSRuntimeException("-1",
+ String.format("The topic/queue %s isn't attached to this consumer", rmqMsg.getTopic()));
+ }
+
+ final KeyValue contextProperties = OMS.newKeyValue();
+ final CountDownLatch sync = new CountDownLatch(1);
+
+ contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS, ConsumeConcurrentlyStatus.RECONSUME_LATER.name());
+
+ ReceivedMessageContext context = new ReceivedMessageContext() {
+ @Override
+ public KeyValue properties() {
+ return contextProperties;
+ }
+
+ @Override
+ public void ack() {
+ sync.countDown();
+ contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS,
+ ConsumeConcurrentlyStatus.CONSUME_SUCCESS.name());
+ }
+
+ @Override
+ public void ack(final KeyValue properties) {
+ sync.countDown();
+ contextProperties.put(NonStandardKeys.MESSAGE_CONSUME_STATUS,
+ properties.getString(NonStandardKeys.MESSAGE_CONSUME_STATUS));
+ }
+ };
+ long begin = System.currentTimeMillis();
+ listener.onMessage(omsMsg, context);
+ long costs = System.currentTimeMillis() - begin;
+ long timeoutMills = clientConfig.getRmqMessageConsumeTimeout() * 60 * 1000;
+ try {
+ sync.await(Math.max(0, timeoutMills - costs), TimeUnit.MILLISECONDS);
+ } catch (InterruptedException ignore) {
+ }
+
+ return ConsumeConcurrentlyStatus.valueOf(contextProperties.getString(NonStandardKeys.MESSAGE_CONSUME_STATUS));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/BytesMessageImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/BytesMessageImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/BytesMessageImpl.java
new file mode 100644
index 0000000..43f80ae
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/BytesMessageImpl.java
@@ -0,0 +1,108 @@
+/*
+ * 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 io.openmessaging.rocketmq.domain;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.Message;
+import io.openmessaging.OMS;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+
+public class BytesMessageImpl implements BytesMessage {
+ private KeyValue headers;
+ private KeyValue properties;
+ private byte[] body;
+
+ public BytesMessageImpl() {
+ this.headers = OMS.newKeyValue();
+ this.properties = OMS.newKeyValue();
+ }
+
+ @Override
+ public byte[] getBody() {
+ return body;
+ }
+
+ @Override
+ public BytesMessage setBody(final byte[] body) {
+ this.body = body;
+ return this;
+ }
+
+ @Override
+ public KeyValue headers() {
+ return headers;
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+
+ @Override
+ public Message putHeaders(final String key, final int value) {
+ headers.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putHeaders(final String key, final long value) {
+ headers.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putHeaders(final String key, final double value) {
+ headers.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putHeaders(final String key, final String value) {
+ headers.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putProperties(final String key, final int value) {
+ properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putProperties(final String key, final long value) {
+ properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putProperties(final String key, final double value) {
+ properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public Message putProperties(final String key, final String value) {
+ properties.put(key, value);
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/ConsumeRequest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/ConsumeRequest.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/ConsumeRequest.java
new file mode 100644
index 0000000..7ce4a9b
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/ConsumeRequest.java
@@ -0,0 +1,55 @@
+/*
+ * 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 io.openmessaging.rocketmq.domain;
+
+import org.apache.rocketmq.client.impl.consumer.ProcessQueue;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+
+public class ConsumeRequest {
+ private final MessageExt messageExt;
+ private final MessageQueue messageQueue;
+ private final ProcessQueue processQueue;
+ private long startConsumeTimeMillis;
+
+ public ConsumeRequest(final MessageExt messageExt, final MessageQueue messageQueue,
+ final ProcessQueue processQueue) {
+ this.messageExt = messageExt;
+ this.messageQueue = messageQueue;
+ this.processQueue = processQueue;
+ }
+
+ public MessageExt getMessageExt() {
+ return messageExt;
+ }
+
+ public MessageQueue getMessageQueue() {
+ return messageQueue;
+ }
+
+ public ProcessQueue getProcessQueue() {
+ return processQueue;
+ }
+
+ public long getStartConsumeTimeMillis() {
+ return startConsumeTimeMillis;
+ }
+
+ public void setStartConsumeTimeMillis(final long startConsumeTimeMillis) {
+ this.startConsumeTimeMillis = startConsumeTimeMillis;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/NonStandardKeys.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/NonStandardKeys.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/NonStandardKeys.java
new file mode 100644
index 0000000..3639a3f
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/NonStandardKeys.java
@@ -0,0 +1,30 @@
+/*
+ * 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 io.openmessaging.rocketmq.domain;
+
+public interface NonStandardKeys {
+ String CONSUMER_GROUP = "rmq.consumer.group";
+ String PRODUCER_GROUP = "rmq.producer.group";
+ String MAX_REDELIVERY_TIMES = "rmq.max.redelivery.times";
+ String MESSAGE_CONSUME_TIMEOUT = "rmq.message.consume.timeout";
+ String MAX_CONSUME_THREAD_NUMS = "rmq.max.consume.thread.nums";
+ String MIN_CONSUME_THREAD_NUMS = "rmq.min.consume.thread.nums";
+ String MESSAGE_CONSUME_STATUS = "rmq.message.consume.status";
+ String MESSAGE_DESTINATION = "rmq.message.destination";
+ String PULL_MESSAGE_BATCH_NUMS = "rmq.pull.message.batch.nums";
+ String PULL_MESSAGE_CACHE_CAPACITY = "rmq.pull.message.cache.capacity";
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/SendResultImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/SendResultImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/SendResultImpl.java
new file mode 100644
index 0000000..228a9f0
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/domain/SendResultImpl.java
@@ -0,0 +1,40 @@
+/*
+ * 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 io.openmessaging.rocketmq.domain;
+
+import io.openmessaging.KeyValue;
+import io.openmessaging.SendResult;
+
+public class SendResultImpl implements SendResult {
+ private String messageId;
+ private KeyValue properties;
+
+ public SendResultImpl(final String messageId, final KeyValue properties) {
+ this.messageId = messageId;
+ this.properties = properties;
+ }
+
+ @Override
+ public String messageId() {
+ return messageId;
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
new file mode 100644
index 0000000..8246bcd
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/AbstractOMSProducer.java
@@ -0,0 +1,138 @@
+/*
+ * 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 io.openmessaging.rocketmq.producer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.Message;
+import io.openmessaging.MessageFactory;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.ServiceLifecycle;
+import io.openmessaging.exception.OMSMessageFormatException;
+import io.openmessaging.exception.OMSNotSupportedException;
+import io.openmessaging.exception.OMSRuntimeException;
+import io.openmessaging.exception.OMSTimeOutException;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.BytesMessageImpl;
+import io.openmessaging.rocketmq.utils.BeanUtils;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.log.ClientLogger;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.exception.RemotingConnectException;
+import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
+import org.slf4j.Logger;
+
+import static io.openmessaging.rocketmq.utils.OMSUtil.buildInstanceName;
+
+abstract class AbstractOMSProducer implements ServiceLifecycle, MessageFactory {
+ final static Logger log = ClientLogger.getLog();
+ final KeyValue properties;
+ final DefaultMQProducer rocketmqProducer;
+ private boolean started = false;
+ final ClientConfig clientConfig;
+
+ AbstractOMSProducer(final KeyValue properties) {
+ this.properties = properties;
+ this.rocketmqProducer = new DefaultMQProducer();
+ this.clientConfig = BeanUtils.populate(properties, ClientConfig.class);
+
+ String accessPoints = clientConfig.getOmsAccessPoints();
+ if (accessPoints == null || accessPoints.isEmpty()) {
+ throw new OMSRuntimeException("-1", "OMS AccessPoints is null or empty.");
+ }
+ this.rocketmqProducer.setNamesrvAddr(accessPoints.replace(',', ';'));
+ this.rocketmqProducer.setProducerGroup(clientConfig.getRmqProducerGroup());
+
+ String producerId = buildInstanceName();
+ this.rocketmqProducer.setSendMsgTimeout(clientConfig.getOmsOperationTimeout());
+ this.rocketmqProducer.setInstanceName(producerId);
+ this.rocketmqProducer.setMaxMessageSize(1024 * 1024 * 4);
+ properties.put(PropertyKeys.PRODUCER_ID, producerId);
+ }
+
+ @Override
+ public synchronized void startup() {
+ if (!started) {
+ try {
+ this.rocketmqProducer.start();
+ } catch (MQClientException e) {
+ throw new OMSRuntimeException("-1", e);
+ }
+ }
+ this.started = true;
+ }
+
+ @Override
+ public synchronized void shutdown() {
+ if (this.started) {
+ this.rocketmqProducer.shutdown();
+ }
+ this.started = false;
+ }
+
+ OMSRuntimeException checkProducerException(String topic, String msgId, Throwable e) {
+ if (e instanceof MQClientException) {
+ if (e.getCause() != null) {
+ if (e.getCause() instanceof RemotingTimeoutException) {
+ return new OMSTimeOutException("-1", String.format("Send message to broker timeout, %dms, Topic=%s, msgId=%s",
+ this.rocketmqProducer.getSendMsgTimeout(), topic, msgId), e);
+ } else if (e.getCause() instanceof MQBrokerException || e.getCause() instanceof RemotingConnectException) {
+ MQBrokerException brokerException = (MQBrokerException) e.getCause();
+ return new OMSRuntimeException("-1", String.format("Received a broker exception, Topic=%s, msgId=%s, %s",
+ topic, msgId, brokerException.getErrorMessage()), e);
+ }
+ }
+ // Exception thrown by local.
+ else {
+ MQClientException clientException = (MQClientException) e;
+ if (-1 == clientException.getResponseCode()) {
+ return new OMSRuntimeException("-1", String.format("Topic does not exist, Topic=%s, msgId=%s",
+ topic, msgId), e);
+ } else if (ResponseCode.MESSAGE_ILLEGAL == clientException.getResponseCode()) {
+ return new OMSMessageFormatException("-1", String.format("A illegal message for RocketMQ, Topic=%s, msgId=%s",
+ topic, msgId), e);
+ }
+ }
+ }
+ return new OMSRuntimeException("-1", "Send message to RocketMQ broker failed.", e);
+ }
+
+ protected void checkMessageType(Message message) {
+ if (!(message instanceof BytesMessage)) {
+ throw new OMSNotSupportedException("-1", "Only BytesMessage is supported.");
+ }
+ }
+
+ @Override
+ public BytesMessage createBytesMessageToTopic(final String topic, final byte[] body) {
+ BytesMessage bytesMessage = new BytesMessageImpl();
+ bytesMessage.setBody(body);
+ bytesMessage.headers().put(MessageHeader.TOPIC, topic);
+ return bytesMessage;
+ }
+
+ @Override
+ public BytesMessage createBytesMessageToQueue(final String queue, final byte[] body) {
+ BytesMessage bytesMessage = new BytesMessageImpl();
+ bytesMessage.setBody(body);
+ bytesMessage.headers().put(MessageHeader.QUEUE, queue);
+ return bytesMessage;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/ProducerImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/ProducerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/ProducerImpl.java
new file mode 100644
index 0000000..2c00c60
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/ProducerImpl.java
@@ -0,0 +1,124 @@
+/*
+ * 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 io.openmessaging.rocketmq.producer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.Producer;
+import io.openmessaging.Promise;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.SendResult;
+import io.openmessaging.exception.OMSRuntimeException;
+import io.openmessaging.rocketmq.promise.DefaultPromise;
+import io.openmessaging.rocketmq.utils.OMSUtil;
+import org.apache.rocketmq.client.producer.SendCallback;
+import org.apache.rocketmq.client.producer.SendStatus;
+
+import static io.openmessaging.rocketmq.utils.OMSUtil.msgConvert;
+
+public class ProducerImpl extends AbstractOMSProducer implements Producer {
+
+ public ProducerImpl(final KeyValue properties) {
+ super(properties);
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+
+ @Override
+ public SendResult send(final Message message) {
+ return send(message, this.rocketmqProducer.getSendMsgTimeout());
+ }
+
+ @Override
+ public SendResult send(final Message message, final KeyValue properties) {
+ long timeout = properties.containsKey(PropertyKeys.OPERATION_TIMEOUT)
+ ? properties.getInt(PropertyKeys.OPERATION_TIMEOUT) : this.rocketmqProducer.getSendMsgTimeout();
+ return send(message, timeout);
+ }
+
+ private SendResult send(final Message message, long timeout) {
+ checkMessageType(message);
+ org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message);
+ try {
+ org.apache.rocketmq.client.producer.SendResult rmqResult = this.rocketmqProducer.send(rmqMessage, timeout);
+ if (!rmqResult.getSendStatus().equals(SendStatus.SEND_OK)) {
+ log.error(String.format("Send message to RocketMQ failed, %s", message));
+ throw new OMSRuntimeException("-1", "Send message to RocketMQ broker failed.");
+ }
+ message.headers().put(MessageHeader.MESSAGE_ID, rmqResult.getMsgId());
+ return OMSUtil.sendResultConvert(rmqResult);
+ } catch (Exception e) {
+ log.error(String.format("Send message to RocketMQ failed, %s", message), e);
+ throw checkProducerException(rmqMessage.getTopic(), message.headers().getString(MessageHeader.MESSAGE_ID), e);
+ }
+ }
+
+ @Override
+ public Promise<SendResult> sendAsync(final Message message) {
+ return sendAsync(message, this.rocketmqProducer.getSendMsgTimeout());
+ }
+
+ @Override
+ public Promise<SendResult> sendAsync(final Message message, final KeyValue properties) {
+ long timeout = properties.containsKey(PropertyKeys.OPERATION_TIMEOUT)
+ ? properties.getInt(PropertyKeys.OPERATION_TIMEOUT) : this.rocketmqProducer.getSendMsgTimeout();
+ return sendAsync(message, timeout);
+ }
+
+ private Promise<SendResult> sendAsync(final Message message, long timeout) {
+ checkMessageType(message);
+ org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message);
+ final Promise<SendResult> promise = new DefaultPromise<>();
+ try {
+ this.rocketmqProducer.send(rmqMessage, new SendCallback() {
+ @Override
+ public void onSuccess(final org.apache.rocketmq.client.producer.SendResult rmqResult) {
+ message.headers().put(MessageHeader.MESSAGE_ID, rmqResult.getMsgId());
+ promise.set(OMSUtil.sendResultConvert(rmqResult));
+ }
+
+ @Override
+ public void onException(final Throwable e) {
+ promise.setFailure(e);
+ }
+ }, timeout);
+ } catch (Exception e) {
+ promise.setFailure(e);
+ }
+ return promise;
+ }
+
+ @Override
+ public void sendOneway(final Message message) {
+ checkMessageType(message);
+ org.apache.rocketmq.common.message.Message rmqMessage = msgConvert((BytesMessage) message);
+ try {
+ this.rocketmqProducer.sendOneway(rmqMessage);
+ } catch (Exception ignore) { //Ignore the oneway exception.
+ }
+ }
+
+ @Override
+ public void sendOneway(final Message message, final KeyValue properties) {
+ sendOneway(message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/SequenceProducerImpl.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/SequenceProducerImpl.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/SequenceProducerImpl.java
new file mode 100644
index 0000000..05225cc
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/producer/SequenceProducerImpl.java
@@ -0,0 +1,95 @@
+/*
+ * 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 io.openmessaging.rocketmq.producer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.SequenceProducer;
+import io.openmessaging.rocketmq.utils.OMSUtil;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import org.apache.rocketmq.client.Validators;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.SendResult;
+
+public class SequenceProducerImpl extends AbstractOMSProducer implements SequenceProducer {
+
+ private BlockingQueue<Message> msgCacheQueue;
+
+ public SequenceProducerImpl(final KeyValue properties) {
+ super(properties);
+ this.msgCacheQueue = new LinkedBlockingQueue<>();
+ }
+
+ @Override
+ public KeyValue properties() {
+ return properties;
+ }
+
+ @Override
+ public void send(final Message message) {
+ checkMessageType(message);
+ org.apache.rocketmq.common.message.Message rmqMessage = OMSUtil.msgConvert((BytesMessage) message);
+ try {
+ Validators.checkMessage(rmqMessage, this.rocketmqProducer);
+ } catch (MQClientException e) {
+ throw checkProducerException(rmqMessage.getTopic(), message.headers().getString(MessageHeader.MESSAGE_ID), e);
+ }
+ msgCacheQueue.add(message);
+ }
+
+ @Override
+ public void send(final Message message, final KeyValue properties) {
+ send(message);
+ }
+
+ @Override
+ public synchronized void commit() {
+ List<Message> messages = new ArrayList<>();
+ msgCacheQueue.drainTo(messages);
+
+ List<org.apache.rocketmq.common.message.Message> rmqMessages = new ArrayList<>();
+
+ for (Message message : messages) {
+ rmqMessages.add(OMSUtil.msgConvert((BytesMessage) message));
+ }
+
+ if (rmqMessages.size() == 0) {
+ return;
+ }
+
+ try {
+ SendResult sendResult = this.rocketmqProducer.send(rmqMessages);
+ String[] msgIdArray = sendResult.getMsgId().split(",");
+ for (int i = 0; i < messages.size(); i++) {
+ Message message = messages.get(i);
+ message.headers().put(MessageHeader.MESSAGE_ID, msgIdArray[i]);
+ }
+ } catch (Exception e) {
+ throw checkProducerException("", "", e);
+ }
+ }
+
+ @Override
+ public synchronized void rollback() {
+ msgCacheQueue.clear();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/DefaultPromise.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/DefaultPromise.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/DefaultPromise.java
new file mode 100644
index 0000000..c863ccf
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/DefaultPromise.java
@@ -0,0 +1,227 @@
+/*
+ * 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 io.openmessaging.rocketmq.promise;
+
+import io.openmessaging.Promise;
+import io.openmessaging.PromiseListener;
+import io.openmessaging.exception.OMSRuntimeException;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultPromise<V> implements Promise<V> {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultPromise.class);
+ private final Object lock = new Object();
+ private volatile FutureState state = FutureState.DOING;
+ private V result = null;
+ private long timeout;
+ private long createTime;
+ private Throwable exception = null;
+ private List<PromiseListener<V>> promiseListenerList;
+
+ public DefaultPromise() {
+ createTime = System.currentTimeMillis();
+ promiseListenerList = new ArrayList<>();
+ timeout = 5000;
+ }
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return state.isCancelledState();
+ }
+
+ @Override
+ public boolean isDone() {
+ return state.isDoneState();
+ }
+
+ @Override
+ public V get() {
+ return result;
+ }
+
+ @Override
+ public V get(final long timeout) {
+ synchronized (lock) {
+ if (!isDoing()) {
+ return getValueOrThrowable();
+ }
+
+ if (timeout <= 0) {
+ try {
+ lock.wait();
+ } catch (Exception e) {
+ cancel(e);
+ }
+ return getValueOrThrowable();
+ } else {
+ long waitTime = timeout - (System.currentTimeMillis() - createTime);
+ if (waitTime > 0) {
+ for (;; ) {
+ try {
+ lock.wait(waitTime);
+ } catch (InterruptedException e) {
+ LOG.error("promise get value interrupted,excepiton:{}", e.getMessage());
+ }
+
+ if (!isDoing()) {
+ break;
+ } else {
+ waitTime = timeout - (System.currentTimeMillis() - createTime);
+ if (waitTime <= 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (isDoing()) {
+ timeoutSoCancel();
+ }
+ }
+ return getValueOrThrowable();
+ }
+ }
+
+ @Override
+ public boolean set(final V value) {
+ if (value == null)
+ return false;
+ this.result = value;
+ return done();
+ }
+
+ @Override
+ public boolean setFailure(final Throwable cause) {
+ if (cause == null)
+ return false;
+ this.exception = cause;
+ return done();
+ }
+
+ @Override
+ public void addListener(final PromiseListener<V> listener) {
+ if (listener == null) {
+ throw new NullPointerException("FutureListener is null");
+ }
+
+ boolean notifyNow = false;
+ synchronized (lock) {
+ if (!isDoing()) {
+ notifyNow = true;
+ } else {
+ if (promiseListenerList == null) {
+ promiseListenerList = new ArrayList<>();
+ }
+ promiseListenerList.add(listener);
+ }
+ }
+
+ if (notifyNow) {
+ notifyListener(listener);
+ }
+ }
+
+ @Override
+ public Throwable getThrowable() {
+ return exception;
+ }
+
+ private void notifyListeners() {
+ if (promiseListenerList != null) {
+ for (PromiseListener<V> listener : promiseListenerList) {
+ notifyListener(listener);
+ }
+ }
+ }
+
+ private boolean isSuccess() {
+ return isDone() && (exception == null);
+ }
+
+ private void timeoutSoCancel() {
+ synchronized (lock) {
+ if (!isDoing()) {
+ return;
+ }
+ state = FutureState.CANCELLED;
+ exception = new RuntimeException("Get request result is timeout or interrupted");
+ lock.notifyAll();
+ }
+ notifyListeners();
+ }
+
+ private V getValueOrThrowable() {
+ if (exception != null) {
+ Throwable e = exception.getCause() != null ? exception.getCause() : exception;
+ throw new OMSRuntimeException("-1", e);
+ }
+ notifyListeners();
+ return result;
+ }
+
+ private boolean isDoing() {
+ return state.isDoingState();
+ }
+
+ private boolean done() {
+ synchronized (lock) {
+ if (!isDoing()) {
+ return false;
+ }
+
+ state = FutureState.DONE;
+ lock.notifyAll();
+ }
+
+ notifyListeners();
+ return true;
+ }
+
+ private void notifyListener(final PromiseListener<V> listener) {
+ try {
+ if (exception != null)
+ listener.operationFailed(this);
+ else
+ listener.operationCompleted(this);
+ } catch (Throwable t) {
+ LOG.error("notifyListener {} Error:{}", listener.getClass().getSimpleName(), t);
+ }
+ }
+
+ private boolean cancel(Exception e) {
+ synchronized (lock) {
+ if (!isDoing()) {
+ return false;
+ }
+
+ state = FutureState.CANCELLED;
+ exception = e;
+ lock.notifyAll();
+ }
+
+ notifyListeners();
+ return true;
+ }
+}
+
[30/50] [abbrv] incubator-rocketmq git commit: Merge branch
'ROCKETMQ-206' into develop
Posted by do...@apache.org.
Merge branch 'ROCKETMQ-206' into develop
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/e5d01b41
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/e5d01b41
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/e5d01b41
Branch: refs/heads/release-4.1.0-incubating
Commit: e5d01b4121c3e17be8073752510a7ca78dd2bf76
Parents: 37fbb7b ceeef8e
Author: dongeforever <zh...@yeah.net>
Authored: Fri May 26 16:34:11 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri May 26 16:34:11 2017 +0800
----------------------------------------------------------------------
.../java/org/apache/rocketmq/common/MixAll.java | 26 ++++++++------------
.../org/apache/rocketmq/common/MixAllTest.java | 20 +++++++++++++++
2 files changed, 30 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
[23/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-206] Fix bug
when non-1byte character exists in JSON config files.
Posted by do...@apache.org.
[ROCKETMQ-206] Fix bug when non-1byte character exists in JSON config files.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/ceeef8ec
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/ceeef8ec
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/ceeef8ec
Branch: refs/heads/release-4.1.0-incubating
Commit: ceeef8ec25758eea490b39400328dd8a702b0175
Parents: 1d966b5
Author: yukon <yu...@apache.org>
Authored: Thu May 25 13:48:22 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu May 25 13:48:22 2017 +0800
----------------------------------------------------------------------
.../java/org/apache/rocketmq/common/MixAll.java | 26 ++++++++------------
.../org/apache/rocketmq/common/MixAllTest.java | 20 +++++++++++++++
2 files changed, 30 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/ceeef8ec/common/src/main/java/org/apache/rocketmq/common/MixAll.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/MixAll.java b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
index e75efd9..36d81d0 100644
--- a/common/src/main/java/org/apache/rocketmq/common/MixAll.java
+++ b/common/src/main/java/org/apache/rocketmq/common/MixAll.java
@@ -18,7 +18,7 @@ package org.apache.rocketmq.common;
import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
@@ -187,30 +187,24 @@ public class MixAll {
}
}
- public static String file2String(final String fileName) {
+ public static String file2String(final String fileName) throws IOException {
File file = new File(fileName);
return file2String(file);
}
- public static String file2String(final File file) {
+ public static String file2String(final File file) throws IOException {
if (file.exists()) {
- char[] data = new char[(int) file.length()];
- boolean result = false;
+ byte[] data = new byte[(int) file.length()];
+ boolean result;
- FileReader fileReader = null;
+ FileInputStream inputStream = null;
try {
- fileReader = new FileReader(file);
- int len = fileReader.read(data);
+ inputStream = new FileInputStream(file);
+ int len = inputStream.read(data);
result = len == data.length;
- } catch (IOException e) {
- // e.printStackTrace();
} finally {
- if (fileReader != null) {
- try {
- fileReader.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ if (inputStream != null) {
+ inputStream.close();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/ceeef8ec/common/src/test/java/org/apache/rocketmq/common/MixAllTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/rocketmq/common/MixAllTest.java b/common/src/test/java/org/apache/rocketmq/common/MixAllTest.java
index 8220981..218b36d 100644
--- a/common/src/test/java/org/apache/rocketmq/common/MixAllTest.java
+++ b/common/src/test/java/org/apache/rocketmq/common/MixAllTest.java
@@ -21,6 +21,10 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Test;
@@ -68,6 +72,22 @@ public class MixAllTest {
}
@Test
+ public void testFile2String_WithChinese() throws IOException {
+ String fileName = System.getProperty("java.io.tmpdir") + File.separator + "MixAllTest" + System.currentTimeMillis();
+ File file = new File(fileName);
+ if (file.exists()) {
+ file.delete();
+ }
+ file.createNewFile();
+ PrintWriter out = new PrintWriter(fileName);
+ out.write("TestForMixAll_中文");
+ out.close();
+ String string = MixAll.file2String(fileName);
+ assertThat(string).isEqualTo("TestForMixAll_中文");
+ file.delete();
+ }
+
+ @Test
public void testString2File() throws IOException {
String fileName = System.getProperty("java.io.tmpdir") + File.separator + "MixAllTest" + System.currentTimeMillis();
MixAll.string2File("MixAll_testString2File", fileName);
[17/50] [abbrv] incubator-rocketmq git commit: Add javadoc to message
store.
Posted by do...@apache.org.
Add javadoc to message store.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/e9814ad4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/e9814ad4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/e9814ad4
Branch: refs/heads/release-4.1.0-incubating
Commit: e9814ad47e3c2fb277ee37db1eb48c6c43848404
Parents: 6898d96
Author: Zhanhui Li <li...@apache.org>
Authored: Sun May 7 23:07:03 2017 +0800
Committer: Zhanhui Li <li...@apache.org>
Committed: Sun May 7 23:07:03 2017 +0800
----------------------------------------------------------------------
.../broker/client/net/Broker2Client.java | 2 +-
.../longpolling/PullRequestHoldService.java | 4 +-
.../broker/offset/ConsumerOffsetManager.java | 4 +-
.../plugin/AbstractPluginMessageStore.java | 20 +-
.../broker/processor/AdminBrokerProcessor.java | 16 +-
.../processor/ConsumerManageProcessor.java | 2 +-
.../rocketmq/store/DefaultMessageStore.java | 16 +-
.../org/apache/rocketmq/store/MessageStore.java | 239 ++++++++++++++++++-
.../store/schedule/ScheduleMessageService.java | 2 +-
9 files changed, 259 insertions(+), 46 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
index c00898c..863da62 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
@@ -149,7 +149,7 @@ public class Broker2Client {
long timeStampOffset;
if (timeStamp == -1) {
- timeStampOffset = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
+ timeStampOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, i);
} else {
timeStampOffset = this.brokerController.getMessageStore().getOffsetInQueueByTime(topic, i, timeStamp);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
index 1a53db1..71f56a4 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
@@ -98,7 +98,7 @@ public class PullRequestHoldService extends ServiceThread {
if (2 == kArray.length) {
String topic = kArray[0];
int queueId = Integer.parseInt(kArray[1]);
- final long offset = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, queueId);
+ final long offset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, queueId);
try {
this.notifyMessageArriving(topic, queueId, offset);
} catch (Throwable e) {
@@ -124,7 +124,7 @@ public class PullRequestHoldService extends ServiceThread {
for (PullRequest request : requestList) {
long newestOffset = maxOffset;
if (newestOffset <= request.getPullFromThisOffset()) {
- newestOffset = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, queueId);
+ newestOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, queueId);
}
if (newestOffset > request.getPullFromThisOffset()) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
index bdcf30c..769c4ad 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
@@ -73,7 +73,7 @@ public class ConsumerOffsetManager extends ConfigManager {
while (it.hasNext() && result) {
Entry<Integer, Long> next = it.next();
- long minOffsetInStore = this.brokerController.getMessageStore().getMinOffsetInQuque(topic, next.getKey());
+ long minOffsetInStore = this.brokerController.getMessageStore().getMinOffsetInQueue(topic, next.getKey());
long offsetInPersist = next.getValue();
result = offsetInPersist <= minOffsetInStore;
}
@@ -201,7 +201,7 @@ public class ConsumerOffsetManager extends ConfigManager {
String[] topicGroupArr = topicGroup.split(TOPIC_GROUP_SEPARATOR);
if (topic.equals(topicGroupArr[0])) {
for (Entry<Integer, Long> entry : offSetEntry.getValue().entrySet()) {
- long minOffset = this.brokerController.getMessageStore().getMinOffsetInQuque(topic, entry.getKey());
+ long minOffset = this.brokerController.getMessageStore().getMinOffsetInQueue(topic, entry.getKey());
if (entry.getValue() >= minOffset) {
Long offset = queueMinOffset.get(entry.getKey());
if (offset == null) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java b/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
index 8ded973..690f70b 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
@@ -92,18 +92,18 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
}
@Override
- public long getMaxOffsetInQuque(String topic, int queueId) {
- return next.getMaxOffsetInQuque(topic, queueId);
+ public long getMaxOffsetInQueue(String topic, int queueId) {
+ return next.getMaxOffsetInQueue(topic, queueId);
}
@Override
- public long getMinOffsetInQuque(String topic, int queueId) {
- return next.getMinOffsetInQuque(topic, queueId);
+ public long getMinOffsetInQueue(String topic, int queueId) {
+ return next.getMinOffsetInQueue(topic, queueId);
}
@Override
- public long getCommitLogOffsetInQueue(String topic, int queueId, long cqOffset) {
- return next.getCommitLogOffsetInQueue(topic, queueId, cqOffset);
+ public long getCommitLogOffsetInQueue(String topic, int queueId, long consumeQueueOffset) {
+ return next.getCommitLogOffsetInQueue(topic, queueId, consumeQueueOffset);
}
@Override
@@ -152,8 +152,8 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
}
@Override
- public long getMessageStoreTimeStamp(String topic, int queueId, long offset) {
- return next.getMessageStoreTimeStamp(topic, queueId, offset);
+ public long getMessageStoreTimeStamp(String topic, int queueId, long consumeQueueOffset) {
+ return next.getMessageStoreTimeStamp(topic, queueId, consumeQueueOffset);
}
@Override
@@ -172,8 +172,8 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
}
@Override
- public void excuteDeleteFilesManualy() {
- next.excuteDeleteFilesManualy();
+ public void executeDeleteFilesManually() {
+ next.executeDeleteFilesManually();
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index daea53c..f59d295 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -376,7 +376,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
final GetMaxOffsetRequestHeader requestHeader =
(GetMaxOffsetRequestHeader) request.decodeCommandCustomHeader(GetMaxOffsetRequestHeader.class);
- long offset = this.brokerController.getMessageStore().getMaxOffsetInQuque(requestHeader.getTopic(), requestHeader.getQueueId());
+ long offset = this.brokerController.getMessageStore().getMaxOffsetInQueue(requestHeader.getTopic(), requestHeader.getQueueId());
responseHeader.setOffset(offset);
@@ -391,7 +391,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
final GetMinOffsetRequestHeader requestHeader =
(GetMinOffsetRequestHeader) request.decodeCommandCustomHeader(GetMinOffsetRequestHeader.class);
- long offset = this.brokerController.getMessageStore().getMinOffsetInQuque(requestHeader.getTopic(), requestHeader.getQueueId());
+ long offset = this.brokerController.getMessageStore().getMinOffsetInQueue(requestHeader.getTopic(), requestHeader.getQueueId());
responseHeader.setOffset(offset);
response.setCode(ResponseCode.SUCCESS);
@@ -537,11 +537,11 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
mq.setQueueId(i);
TopicOffset topicOffset = new TopicOffset();
- long min = this.brokerController.getMessageStore().getMinOffsetInQuque(topic, i);
+ long min = this.brokerController.getMessageStore().getMinOffsetInQueue(topic, i);
if (min < 0)
min = 0;
- long max = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
+ long max = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, i);
if (max < 0)
max = 0;
@@ -679,7 +679,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
OffsetWrapper offsetWrapper = new OffsetWrapper();
- long brokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
+ long brokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, i);
if (brokerOffset < 0)
brokerOffset = 0;
@@ -862,7 +862,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
long minTime = this.brokerController.getMessageStore().getEarliestMessageTime(topic, i);
timeSpan.setMinTimeStamp(minTime);
- long max = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
+ long max = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, i);
long maxTime = this.brokerController.getMessageStore().getMessageStoreTimeStamp(topic, i, max - 1);
timeSpan.setMaxTimeStamp(maxTime);
@@ -876,7 +876,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
}
timeSpan.setConsumeTimeStamp(consumeTime);
- long maxBrokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQuque(requestHeader.getTopic(), i);
+ long maxBrokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(requestHeader.getTopic(), i);
if (consumerOffset < maxBrokerOffset) {
long nextTime = this.brokerController.getMessageStore().getMessageStoreTimeStamp(topic, i, consumerOffset);
timeSpan.setDelayTime(System.currentTimeMillis() - nextTime);
@@ -1126,7 +1126,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
mq.setBrokerName(this.brokerController.getBrokerConfig().getBrokerName());
mq.setQueueId(i);
OffsetWrapper offsetWrapper = new OffsetWrapper();
- long brokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQuque(topic, i);
+ long brokerOffset = this.brokerController.getMessageStore().getMaxOffsetInQueue(topic, i);
if (brokerOffset < 0)
brokerOffset = 0;
long consumerOffset = this.brokerController.getConsumerOffsetManager().queryOffset(//
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
index 2c1029c..bb42705 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/ConsumerManageProcessor.java
@@ -135,7 +135,7 @@ public class ConsumerManageProcessor implements NettyRequestProcessor {
response.setRemark(null);
} else {
long minOffset =
- this.brokerController.getMessageStore().getMinOffsetInQuque(requestHeader.getTopic(),
+ this.brokerController.getMessageStore().getMinOffsetInQueue(requestHeader.getTopic(),
requestHeader.getQueueId());
if (minOffset <= 0
&& !this.brokerController.getMessageStore().checkInDiskByConsumeOffset(
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
index 7bed62c..931edc7 100644
--- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
@@ -580,7 +580,7 @@ public class DefaultMessageStore implements MessageStore {
/**
*/
- public long getMaxOffsetInQuque(String topic, int queueId) {
+ public long getMaxOffsetInQueue(String topic, int queueId) {
ConsumeQueue logic = this.findConsumeQueue(topic, queueId);
if (logic != null) {
long offset = logic.getMaxOffsetInQueue();
@@ -593,7 +593,7 @@ public class DefaultMessageStore implements MessageStore {
/**
*/
- public long getMinOffsetInQuque(String topic, int queueId) {
+ public long getMinOffsetInQueue(String topic, int queueId) {
ConsumeQueue logic = this.findConsumeQueue(topic, queueId);
if (logic != null) {
return logic.getMinOffsetInQueue();
@@ -603,10 +603,10 @@ public class DefaultMessageStore implements MessageStore {
}
@Override
- public long getCommitLogOffsetInQueue(String topic, int queueId, long cqOffset) {
+ public long getCommitLogOffsetInQueue(String topic, int queueId, long consumeQueueOffset) {
ConsumeQueue consumeQueue = findConsumeQueue(topic, queueId);
if (consumeQueue != null) {
- SelectMappedBufferResult bufferConsumeQueue = consumeQueue.getIndexBuffer(cqOffset);
+ SelectMappedBufferResult bufferConsumeQueue = consumeQueue.getIndexBuffer(consumeQueueOffset);
if (bufferConsumeQueue != null) {
try {
long offsetPy = bufferConsumeQueue.getByteBuffer().getLong();
@@ -740,10 +740,10 @@ public class DefaultMessageStore implements MessageStore {
}
@Override
- public long getMessageStoreTimeStamp(String topic, int queueId, long offset) {
+ public long getMessageStoreTimeStamp(String topic, int queueId, long consumeQueueOffset) {
ConsumeQueue logicQueue = this.findConsumeQueue(topic, queueId);
if (logicQueue != null) {
- SelectMappedBufferResult result = logicQueue.getIndexBuffer(offset);
+ SelectMappedBufferResult result = logicQueue.getIndexBuffer(consumeQueueOffset);
if (result != null) {
try {
final long phyOffset = result.getByteBuffer().getLong();
@@ -798,7 +798,7 @@ public class DefaultMessageStore implements MessageStore {
}
@Override
- public void excuteDeleteFilesManualy() {
+ public void executeDeleteFilesManually() {
this.cleanCommitLogService.excuteDeleteFilesManualy();
}
@@ -1434,7 +1434,7 @@ public class DefaultMessageStore implements MessageStore {
public void excuteDeleteFilesManualy() {
this.manualDeleteFileSeveralTimes = MAX_MANUAL_DELETE_FILE_TIMES;
- DefaultMessageStore.log.info("excuteDeleteFilesManualy was invoked");
+ DefaultMessageStore.log.info("executeDeleteFilesManually was invoked");
}
public void run() {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/MessageStore.java b/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
index e841c08..55572ce 100644
--- a/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/MessageStore.java
@@ -22,91 +22,304 @@ import java.util.Set;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageExtBatch;
+/**
+ * This class defines contracting interfaces to implement, allowing third-party vendor to use customized message store.
+ */
public interface MessageStore {
+ /**
+ * Load previously stored messages.
+ * @return true if success; false otherwise.
+ */
boolean load();
+ /**
+ * Launch this message store.
+ * @throws Exception if there is any error.
+ */
void start() throws Exception;
+ /**
+ * Shutdown this message store.
+ */
void shutdown();
+ /**
+ * Destroy this message store. Generally, all persistent files should be removed after invocation.
+ */
void destroy();
+ /**
+ * Store a message into store.
+ * @param msg Message instance to store
+ * @return result of store operation.
+ */
PutMessageResult putMessage(final MessageExtBrokerInner msg);
+ /**
+ * Store a batch of messages.
+ * @param messageExtBatch Message batch.
+ * @return result of storing batch messages.
+ */
PutMessageResult putMessages(final MessageExtBatch messageExtBatch);
+ /**
+ * Query at most <code>maxMsgNums</code> messages belonging to <code>topic</code> at <code>queueId</code> starting
+ * from given <code>offset</code>. Resulting messages will further be screened using provided message filter.
+ *
+ * @param group Consumer group that launches this query.
+ * @param topic Topic to query.
+ * @param queueId Queue ID to query.
+ * @param offset Logical offset to start from.
+ * @param maxMsgNums Maximum count of messages to query.
+ * @param messageFilter Message filter used to screen desired messages.
+ * @return Matched messages.
+ */
GetMessageResult getMessage(final String group, final String topic, final int queueId,
final long offset, final int maxMsgNums, final MessageFilter messageFilter);
- long getMaxOffsetInQuque(final String topic, final int queueId);
-
- long getMinOffsetInQuque(final String topic, final int queueId);
-
- long getCommitLogOffsetInQueue(final String topic, final int queueId, final long cqOffset);
-
+ /**
+ * Get maximum offset of the topic queue.
+ * @param topic Topic name.
+ * @param queueId Queue ID.
+ * @return Maximum offset at present.
+ */
+ long getMaxOffsetInQueue(final String topic, final int queueId);
+
+ /**
+ * Get the minimum offset of the topic queue.
+ * @param topic Topic name.
+ * @param queueId Queue ID.
+ * @return Minimum offset at present.
+ */
+ long getMinOffsetInQueue(final String topic, final int queueId);
+
+ /**
+ * Get the offset of the message in the commit log, which is also known as physical offset.
+ * @param topic Topic of the message to lookup.
+ * @param queueId Queue ID.
+ * @param consumeQueueOffset offset of consume queue.
+ * @return physical offset.
+ */
+ long getCommitLogOffsetInQueue(final String topic, final int queueId, final long consumeQueueOffset);
+
+ /**
+ * Look up the physical offset of the message whose store timestamp is as specified.
+ * @param topic Topic of the message.
+ * @param queueId Queue ID.
+ * @param timestamp Timestamp to look up.
+ * @return physical offset which matches.
+ */
long getOffsetInQueueByTime(final String topic, final int queueId, final long timestamp);
+ /**
+ * Look up the message by given commit log offset.
+ * @param commitLogOffset physical offset.
+ * @return Message whose physical offset is as specified.
+ */
MessageExt lookMessageByOffset(final long commitLogOffset);
+ /**
+ * Get one message from the specified commit log offset.
+ * @param commitLogOffset commit log offset.
+ * @return wrapped result of the message.
+ */
SelectMappedBufferResult selectOneMessageByOffset(final long commitLogOffset);
+ /**
+ * Get one message from the specified commit log offset.
+ * @param commitLogOffset commit log offset.
+ * @param msgSize message size.
+ * @return wrapped result of the message.
+ */
SelectMappedBufferResult selectOneMessageByOffset(final long commitLogOffset, final int msgSize);
+ /**
+ * Get the running information of this store.
+ * @return message store running info.
+ */
String getRunningDataInfo();
+ /**
+ * Message store runtime information, which should generally contains various statistical information.
+ * @return runtime information of the message store in format of key-value pairs.
+ */
HashMap<String, String> getRuntimeInfo();
+ /**
+ * Get the maximum commit log offset.
+ * @return maximum commit log offset.
+ */
long getMaxPhyOffset();
+ /**
+ * Get the minimum commit log offset.
+ * @return minimum commit log offset.
+ */
long getMinPhyOffset();
+ /**
+ * Get the store time of the earliest message in the given queue.
+ * @param topic Topic of the messages to query.
+ * @param queueId Queue ID to find.
+ * @return store time of the earliest message.
+ */
long getEarliestMessageTime(final String topic, final int queueId);
+ /**
+ * Get the store time of the earliest message in this store.
+ * @return timestamp of the earliest message in this store.
+ */
long getEarliestMessageTime();
- long getMessageStoreTimeStamp(final String topic, final int queueId, final long offset);
-
+ /**
+ * Get the store time of the message specified.
+ * @param topic message topic.
+ * @param queueId queue ID.
+ * @param consumeQueueOffset consume queue offset.
+ * @return store timestamp of the message.
+ */
+ long getMessageStoreTimeStamp(final String topic, final int queueId, final long consumeQueueOffset);
+
+ /**
+ * Get the total number of the messages in the specified queue.
+ * @param topic Topic
+ * @param queueId Queue ID.
+ * @return total number.
+ */
long getMessageTotalInQueue(final String topic, final int queueId);
+ /**
+ * Get the raw commit log data starting from the given offset, which should used for replication purpose.
+ * @param offset starting offset.
+ * @return commit log data.
+ */
SelectMappedBufferResult getCommitLogData(final long offset);
+ /**
+ * Append data to commit log.
+ * @param startOffset starting offset.
+ * @param data data to append.
+ * @return true if success; false otherwise.
+ */
boolean appendToCommitLog(final long startOffset, final byte[] data);
- void excuteDeleteFilesManualy();
-
- QueryMessageResult queryMessage(final String topic, final String key, final int maxNum,
- final long begin, final long end);
-
+ /**
+ * Execute file deletion manually.
+ */
+ void executeDeleteFilesManually();
+
+ /**
+ * Query messages by given key.
+ * @param topic topic of the message.
+ * @param key message key.
+ * @param maxNum maximum number of the messages possible.
+ * @param begin begin timestamp.
+ * @param end end timestamp.
+ * @return
+ */
+ QueryMessageResult queryMessage(final String topic, final String key, final int maxNum, final long begin,
+ final long end);
+
+ /**
+ * Update HA master address.
+ * @param newAddr new address.
+ */
void updateHaMasterAddress(final String newAddr);
+ /**
+ * Return how much the slave falls behind.
+ * @return number of bytes that slave falls behind.
+ */
long slaveFallBehindMuch();
+ /**
+ * Return the current timestamp of the store.
+ * @return current time in milliseconds since 1970-01-01.
+ */
long now();
+ /**
+ * Clean unused topics.
+ * @param topics all valid topics.
+ * @return number of the topics deleted.
+ */
int cleanUnusedTopic(final Set<String> topics);
+ /**
+ * Clean expired consume queues.
+ */
void cleanExpiredConsumerQueue();
+ /**
+ * Check if the given message has been swapped out of the memory.
+ * @param topic topic.
+ * @param queueId queue ID.
+ * @param consumeOffset consume queue offset.
+ * @return true if the message is no longer in memory; false otherwise.
+ */
boolean checkInDiskByConsumeOffset(final String topic, final int queueId, long consumeOffset);
+ /**
+ * Get number of the bytes that have been stored in commit log and not yet dispatched to consume queue.
+ * @return number of the bytes to dispatch.
+ */
long dispatchBehindBytes();
+ /**
+ * Flush the message store to persist all data.
+ * @return maximum offset flushed to persistent storage device.
+ */
long flush();
+ /**
+ * Reset written offset.
+ * @param phyOffset new offset.
+ * @return true if success; false otherwise.
+ */
boolean resetWriteOffset(long phyOffset);
+ /**
+ * Get confirm offset.
+ * @return confirm offset.
+ */
long getConfirmOffset();
+ /**
+ * Set confirm offset.
+ * @param phyOffset confirm offset to set.
+ */
void setConfirmOffset(long phyOffset);
+ /**
+ * Check if the operation system page cache is busy or not.
+ * @return true if the OS page cache is busy; false otherwise.
+ */
boolean isOSPageCacheBusy();
+ /**
+ * Get lock time in milliseconds of the store by far.
+ * @return lock time in milliseconds.
+ */
long lockTimeMills();
+ /**
+ * Check if the transient store pool is deficient.
+ * @return true if the transient store pool is running out; false otherwise.
+ */
boolean isTransientStorePoolDeficient();
+ /**
+ * Get the dispatcher list.
+ * @return list of the dispatcher.
+ */
LinkedList<CommitLogDispatcher> getDispatcherList();
+ /**
+ * Get consume queue of the topic/queue.
+ * @param topic Topic.
+ * @param queueId Queue ID.
+ * @return Consume queue.
+ */
ConsumeQueue getConsumeQueue(String topic, int queueId);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e9814ad4/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
index d45b994..501876e 100644
--- a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
+++ b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
@@ -79,7 +79,7 @@ public class ScheduleMessageService extends ConfigManager {
Entry<Integer, Long> next = it.next();
int queueId = delayLevel2QueueId(next.getKey());
long delayOffset = next.getValue();
- long maxOffset = this.defaultMessageStore.getMaxOffsetInQuque(SCHEDULE_TOPIC, queueId);
+ long maxOffset = this.defaultMessageStore.getMaxOffsetInQueue(SCHEDULE_TOPIC, queueId);
String value = String.format("%d,%d", delayOffset, maxOffset);
String key = String.format("%s_%d", RunningStats.scheduleMessageOffset.name(), next.getKey());
stats.put(key, value);
[18/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-187] Measure
the code coverage for Integration Tests, and add sonar-apache profile,
closes apache/incubator-rocketmq#96
Posted by do...@apache.org.
[ROCKETMQ-187] Measure the code coverage for Integration Tests, and add sonar-apache profile, closes apache/incubator-rocketmq#96
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/f5a2ee0a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/f5a2ee0a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/f5a2ee0a
Branch: refs/heads/release-4.1.0-incubating
Commit: f5a2ee0a8fecff48064f19ea242c233475e9635f
Parents: e9814ad
Author: dongeforever <zh...@yeah.net>
Authored: Tue May 9 23:38:56 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Tue May 9 23:38:56 2017 +0800
----------------------------------------------------------------------
.travis.yml | 2 +-
pom.xml | 13 ++++++++++---
2 files changed, 11 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f5a2ee0a/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 916cac5..2bc2296 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -40,4 +40,4 @@ script:
after_success:
- mvn clean install -Pit-test
- - mvn sonar:sonar
+ - mvn sonar:sonar -Psonar-apache
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f5a2ee0a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 6fd59ac..05ead63 100644
--- a/pom.xml
+++ b/pom.xml
@@ -161,10 +161,10 @@
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
- <!-- URL of the ASF SonarQube server -->
- <sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
<!-- Exclude all generated code -->
- <sonar.exclusions>file:**/generated-sources/**</sonar.exclusions>
+ <sonar.jacoco.itReportPath>${project.basedir}/../test/target/jacoco-it.exec</sonar.jacoco.itReportPath>
+ <sonar.exclusions>file:**/generated-sources/**,**/test/**</sonar.exclusions>
+
</properties>
<modules>
@@ -475,6 +475,13 @@
</plugins>
</build>
</profile>
+ <profile>
+ <id>sonar-apache</id>
+ <properties>
+ <!-- URL of the ASF SonarQube server -->
+ <sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
+ </properties>
+ </profile>
</profiles>
<dependencies>
[44/50] [abbrv] incubator-rocketmq git commit: Remove develops from
pom
Posted by do...@apache.org.
Remove develops from pom
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/e068ec17
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/e068ec17
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/e068ec17
Branch: refs/heads/release-4.1.0-incubating
Commit: e068ec17ad994b4fad68ebb239be6652e419d1f5
Parents: 96cd2e4
Author: dongeforever <zh...@yeah.net>
Authored: Tue Jun 6 16:07:41 2017 +0800
Committer: dongeforever <do...@apache.org>
Committed: Tue Jun 6 16:28:15 2017 +0800
----------------------------------------------------------------------
pom.xml | 71 +++++-------------------------------------------------------
1 file changed, 5 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/e068ec17/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 75dbf5b..851a6cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,8 +43,8 @@
<connection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-rocketmq.git</connection>
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-rocketmq.git
</developerConnection>
- <tag>HEAD</tag>
- </scm>
+ <tag>HEAD</tag>
+ </scm>
<mailingLists>
<mailingList>
@@ -69,71 +69,10 @@
<developers>
<developer>
- <id>vintagewang</id>
- <name>vintagewang</name>
- <roles>
- <role>architect</role>
- <role>committer</role>
- </roles>
- <email>vintagewang@apache.org</email>
- <timezone>+8</timezone>
+ <id>Apache RocketMQ</id>
+ <name>Apache RocketMQ of ASF</name>
+ <url>https://rocketmq.apache.org/</url>
</developer>
- <developer>
- <id>vongosling@apache.org</id>
- <name>vongosling@apache.org</name>
- <roles>
- <role>architect</role>
- <role>committer</role>
- </roles>
- <email>vongosling@apache.org</email>
- <timezone>+8</timezone>
- </developer>
- <developer>
- <id>yukon</id>
- <name>Xinyu Zhou</name>
- <email>yukon@@apache.org</email>
- <roles>
- <role>committer</role>
- </roles>
- <timezone>+8</timezone>
- </developer>
- <developer>
- <id>stevenschew</id>
- <name>Wei Zhou</name>
- <email>stevenschew@@apache.org</email>
- <roles>
- <role>committer</role>
- </roles>
- <timezone>+8</timezone>
- </developer>
- <developer>
- <id>lollipop</id>
- <name>Jixiang Jin</name>
- <email>lollipop@apache.org</email>
- <roles>
- <role>committer</role>
- </roles>
- <timezone>+8</timezone>
- </developer>
- <developer>
- <id>lizhanhui</id>
- <name>Zhanhui Li</name>
- <email>lizhanhui@apache.org</email>
- <roles>
- <role>committer</role>
- </roles>
- <timezone>+8</timezone>
- </developer>
- <developer>
- <id>dongeforever</id>
- <name>dongeforever</name>
- <email>dongeforever@apache.org</email>
- <roles>
- <role>committer</role>
- </roles>
- <timezone>+8</timezone>
- </developer>
-
</developers>
<licenses>
[03/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-176] Use new
maven central badge with the newest release version info in README.
Posted by do...@apache.org.
[ROCKETMQ-176] Use new maven central badge with the newest release version info in README.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/deb08207
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/deb08207
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/deb08207
Branch: refs/heads/release-4.1.0-incubating
Commit: deb082071779563f7698090f9154e0e69200ac89
Parents: f508f13
Author: yukon <yu...@apache.org>
Authored: Thu Apr 20 11:36:46 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu Apr 20 11:36:46 2017 +0800
----------------------------------------------------------------------
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/deb08207/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 81eded4..7a9abb1 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
## Apache RocketMQ [![Build Status](https://travis-ci.org/apache/incubator-rocketmq.svg?branch=master)](https://travis-ci.org/apache/incubator-rocketmq) [![Coverage Status](https://coveralls.io/repos/github/apache/incubator-rocketmq/badge.svg?branch=master)](https://coveralls.io/github/apache/incubator-rocketmq?branch=master)
-[![Maven Central](https://img.shields.io/badge/maven--center-stable--version-green.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.rocketmq)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.rocketmq/rocketmq-all/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Corg.apache.rocketmq)
[![GitHub release](https://img.shields.io/badge/release-download-orange.svg)](https://github.org/apache/rocketmqreleases)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[43/50] [abbrv] incubator-rocketmq git commit:
[ROCKETMQ-208]incompatibility problem found in enviroment of JDK 1.7 when
running client closes apache/incubator-rocketmq#10
Posted by do...@apache.org.
[ROCKETMQ-208]incompatibility problem found in enviroment of JDK 1.7 when running client closes apache/incubator-rocketmq#10
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/96cd2e4e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/96cd2e4e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/96cd2e4e
Branch: refs/heads/release-4.1.0-incubating
Commit: 96cd2e4ed03e2c47a7d79d7e10980d154d2acb93
Parents: 2c28baa
Author: Jaskey <li...@gmail.com>
Authored: Tue Jun 6 16:06:46 2017 +0800
Committer: dongeforever <do...@apache.org>
Committed: Tue Jun 6 16:28:15 2017 +0800
----------------------------------------------------------------------
.../broker/client/ConsumerGroupInfo.java | 9 ++--
.../rocketmq/broker/client/ConsumerManager.java | 7 +--
.../broker/client/net/Broker2Client.java | 6 +--
.../client/rebalance/RebalanceLockManager.java | 3 +-
.../broker/filter/ConsumerFilterManager.java | 9 ++--
.../broker/filtersrv/FilterServerManager.java | 3 +-
.../longpolling/PullRequestHoldService.java | 3 +-
.../broker/offset/ConsumerOffsetManager.java | 31 +++++++------
.../broker/processor/AdminBrokerProcessor.java | 4 +-
.../subscription/SubscriptionGroupManager.java | 5 +-
.../broker/topic/TopicConfigManager.java | 5 +-
.../consumer/MQPullConsumerScheduleService.java | 7 +--
.../consumer/store/LocalFileOffsetStore.java | 3 +-
.../consumer/store/OffsetSerializeWrapper.java | 7 +--
.../consumer/store/RemoteBrokerOffsetStore.java | 3 +-
.../rocketmq/client/impl/MQClientManager.java | 3 +-
.../consumer/DefaultMQPullConsumerImpl.java | 4 +-
.../consumer/DefaultMQPushConsumerImpl.java | 6 +--
.../client/impl/consumer/MessageQueueLock.java | 3 +-
.../client/impl/consumer/PullAPIWrapper.java | 5 +-
.../client/impl/consumer/RebalanceImpl.java | 13 +++---
.../client/impl/factory/MQClientInstance.java | 17 +++----
.../impl/producer/DefaultMQProducerImpl.java | 5 +-
.../protocol/body/ConsumerConnection.java | 5 +-
.../body/ConsumerOffsetSerializeWrapper.java | 9 ++--
.../protocol/body/SubscriptionGroupWrapper.java | 7 +--
.../body/TopicConfigSerializeWrapper.java | 7 +--
.../common/stats/MomentStatsItemSet.java | 5 +-
.../rocketmq/common/stats/StatsItemSet.java | 3 +-
.../filtersrv/filter/FilterClassManager.java | 3 +-
.../namesrv/routeinfo/RouteInfoManager.java | 4 +-
.../remoting/netty/NettyRemotingAbstract.java | 3 +-
.../remoting/netty/NettyRemotingClient.java | 3 +-
.../store/AllocateMappedFileService.java | 3 +-
.../rocketmq/store/DefaultMessageStore.java | 49 ++++++++++----------
.../schedule/DelayOffsetSerializeWrapper.java | 7 +--
.../store/schedule/ScheduleMessageService.java | 5 +-
37 files changed, 153 insertions(+), 121 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
index 6ce542a..91b6c81 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupInfo.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
@@ -34,9 +35,9 @@ import org.slf4j.LoggerFactory;
public class ConsumerGroupInfo {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private final String groupName;
- private final ConcurrentHashMap<String/* Topic */, SubscriptionData> subscriptionTable =
+ private final ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
new ConcurrentHashMap<String, SubscriptionData>();
- private final ConcurrentHashMap<Channel, ClientChannelInfo> channelInfoTable =
+ private final ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
new ConcurrentHashMap<Channel, ClientChannelInfo>(16);
private volatile ConsumeType consumeType;
private volatile MessageModel messageModel;
@@ -63,11 +64,11 @@ public class ConsumerGroupInfo {
return null;
}
- public ConcurrentHashMap<String, SubscriptionData> getSubscriptionTable() {
+ public ConcurrentMap<String, SubscriptionData> getSubscriptionTable() {
return subscriptionTable;
}
- public ConcurrentHashMap<Channel, ClientChannelInfo> getChannelInfoTable() {
+ public ConcurrentMap<Channel, ClientChannelInfo> getChannelInfoTable() {
return channelInfoTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
index a5ddec8..4a262e5 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
@@ -22,6 +22,7 @@ import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.constant.LoggerName;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
@@ -35,7 +36,7 @@ import org.slf4j.LoggerFactory;
public class ConsumerManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private static final long CHANNEL_EXPIRED_TIMEOUT = 1000 * 120;
- private final ConcurrentHashMap<String/* Group */, ConsumerGroupInfo> consumerTable =
+ private final ConcurrentMap<String/* Group */, ConsumerGroupInfo> consumerTable =
new ConcurrentHashMap<String, ConsumerGroupInfo>(1024);
private final ConsumerIdsChangeListener consumerIdsChangeListener;
@@ -145,7 +146,7 @@ public class ConsumerManager {
Entry<String, ConsumerGroupInfo> next = it.next();
String group = next.getKey();
ConsumerGroupInfo consumerGroupInfo = next.getValue();
- ConcurrentHashMap<Channel, ClientChannelInfo> channelInfoTable =
+ ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
consumerGroupInfo.getChannelInfoTable();
Iterator<Entry<Channel, ClientChannelInfo>> itChannel = channelInfoTable.entrySet().iterator();
@@ -176,7 +177,7 @@ public class ConsumerManager {
Iterator<Entry<String, ConsumerGroupInfo>> it = this.consumerTable.entrySet().iterator();
while (it.hasNext()) {
Entry<String, ConsumerGroupInfo> entry = it.next();
- ConcurrentHashMap<String, SubscriptionData> subscriptionTable =
+ ConcurrentMap<String, SubscriptionData> subscriptionTable =
entry.getValue().getSubscriptionTable();
if (subscriptionTable.containsKey(topic)) {
groups.add(entry.getKey());
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
index 863da62..65b444e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/net/Broker2Client.java
@@ -25,7 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
@@ -189,7 +189,7 @@ public class Broker2Client {
this.brokerController.getConsumerManager().getConsumerGroupInfo(group);
if (consumerGroupInfo != null && !consumerGroupInfo.getAllChannel().isEmpty()) {
- ConcurrentHashMap<Channel, ClientChannelInfo> channelInfoTable =
+ ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
consumerGroupInfo.getChannelInfoTable();
for (Map.Entry<Channel, ClientChannelInfo> entry : channelInfoTable.entrySet()) {
int version = entry.getValue().getVersion();
@@ -252,7 +252,7 @@ public class Broker2Client {
Map<String, Map<MessageQueue, Long>> consumerStatusTable =
new HashMap<String, Map<MessageQueue, Long>>();
- ConcurrentHashMap<Channel, ClientChannelInfo> channelInfoTable =
+ ConcurrentMap<Channel, ClientChannelInfo> channelInfoTable =
this.brokerController.getConsumerManager().getConsumerGroupInfo(group).getChannelInfoTable();
if (null == channelInfoTable || channelInfoTable.isEmpty()) {
result.setCode(ResponseCode.SYSTEM_ERROR);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/client/rebalance/RebalanceLockManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/rebalance/RebalanceLockManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/rebalance/RebalanceLockManager.java
index 98aceb6..ed5a875 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/rebalance/RebalanceLockManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/rebalance/RebalanceLockManager.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.broker.client.rebalance;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -31,7 +32,7 @@ public class RebalanceLockManager {
private final static long REBALANCE_LOCK_MAX_LIVE_TIME = Long.parseLong(System.getProperty(
"rocketmq.broker.rebalance.lockMaxLiveTime", "60000"));
private final Lock lock = new ReentrantLock();
- private final ConcurrentHashMap<String/* group */, ConcurrentHashMap<MessageQueue, LockEntry>> mqLockTable =
+ private final ConcurrentMap<String/* group */, ConcurrentHashMap<MessageQueue, LockEntry>> mqLockTable =
new ConcurrentHashMap<String, ConcurrentHashMap<MessageQueue, LockEntry>>(1024);
public boolean tryLock(final String group, final MessageQueue mq, final String clientId) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
index 7f790af..f50db86 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.broker.filter;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
import org.apache.rocketmq.common.ConfigManager;
@@ -45,7 +46,7 @@ public class ConsumerFilterManager extends ConfigManager {
private static final long MS_24_HOUR = 24 * 3600 * 1000;
- private ConcurrentHashMap<String/*Topic*/, FilterDataMapByTopic>
+ private ConcurrentMap<String/*Topic*/, FilterDataMapByTopic>
filterDataByTopic = new ConcurrentHashMap<String/*consumer group*/, FilterDataMapByTopic>(256);
private transient BrokerController brokerController;
@@ -316,7 +317,7 @@ public class ConsumerFilterManager extends ConfigManager {
}
}
- public ConcurrentHashMap<String, FilterDataMapByTopic> getFilterDataByTopic() {
+ public ConcurrentMap<String, FilterDataMapByTopic> getFilterDataByTopic() {
return filterDataByTopic;
}
@@ -326,7 +327,7 @@ public class ConsumerFilterManager extends ConfigManager {
public static class FilterDataMapByTopic {
- private ConcurrentHashMap<String/*consumer group*/, ConsumerFilterData>
+ private ConcurrentMap<String/*consumer group*/, ConsumerFilterData>
groupFilterData = new ConcurrentHashMap<String, ConsumerFilterData>();
private String topic;
@@ -452,7 +453,7 @@ public class ConsumerFilterManager extends ConfigManager {
return this.groupFilterData.get(consumerGroup);
}
- public final ConcurrentHashMap<String, ConsumerFilterData> getGroupFilterData() {
+ public final ConcurrentMap<String, ConsumerFilterData> getGroupFilterData() {
return this.groupFilterData;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/filtersrv/FilterServerManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filtersrv/FilterServerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/filtersrv/FilterServerManager.java
index b935bc8..52cb919 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/filtersrv/FilterServerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filtersrv/FilterServerManager.java
@@ -23,6 +23,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -38,7 +39,7 @@ public class FilterServerManager {
public static final long FILTER_SERVER_MAX_IDLE_TIME_MILLS = 30000;
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
- private final ConcurrentHashMap<Channel, FilterServerInfo> filterServerTable =
+ private final ConcurrentMap<Channel, FilterServerInfo> filterServerTable =
new ConcurrentHashMap<Channel, FilterServerInfo>(16);
private final BrokerController brokerController;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
index 71f56a4..b1bd86f 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.ServiceThread;
import org.apache.rocketmq.common.SystemClock;
@@ -33,7 +34,7 @@ public class PullRequestHoldService extends ServiceThread {
private static final String TOPIC_QUEUEID_SEPARATOR = "@";
private final BrokerController brokerController;
private final SystemClock systemClock = new SystemClock();
- private ConcurrentHashMap<String/* topic@queueId */, ManyPullRequest> pullRequestTable =
+ private ConcurrentMap<String/* topic@queueId */, ManyPullRequest> pullRequestTable =
new ConcurrentHashMap<String, ManyPullRequest>(1024);
public PullRequestHoldService(final BrokerController brokerController) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
index 769c4ad..57565a6 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/offset/ConsumerOffsetManager.java
@@ -23,6 +23,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
import org.apache.rocketmq.common.ConfigManager;
@@ -36,8 +37,8 @@ public class ConsumerOffsetManager extends ConfigManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private static final String TOPIC_GROUP_SEPARATOR = "@";
- private ConcurrentHashMap<String/* topic@group */, ConcurrentHashMap<Integer, Long>> offsetTable =
- new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>>(512);
+ private ConcurrentMap<String/* topic@group */, ConcurrentMap<Integer, Long>> offsetTable =
+ new ConcurrentHashMap<String, ConcurrentMap<Integer, Long>>(512);
private transient BrokerController brokerController;
@@ -49,9 +50,9 @@ public class ConsumerOffsetManager extends ConfigManager {
}
public void scanUnsubscribedTopic() {
- Iterator<Entry<String, ConcurrentHashMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, Long>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
String topicAtGroup = next.getKey();
String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
if (arrays.length == 2) {
@@ -67,7 +68,7 @@ public class ConsumerOffsetManager extends ConfigManager {
}
}
- private boolean offsetBehindMuchThanData(final String topic, ConcurrentHashMap<Integer, Long> table) {
+ private boolean offsetBehindMuchThanData(final String topic, ConcurrentMap<Integer, Long> table) {
Iterator<Entry<Integer, Long>> it = table.entrySet().iterator();
boolean result = !table.isEmpty();
@@ -84,9 +85,9 @@ public class ConsumerOffsetManager extends ConfigManager {
public Set<String> whichTopicByConsumer(final String group) {
Set<String> topics = new HashSet<String>();
- Iterator<Entry<String, ConcurrentHashMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, Long>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
String topicAtGroup = next.getKey();
String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
if (arrays.length == 2) {
@@ -102,9 +103,9 @@ public class ConsumerOffsetManager extends ConfigManager {
public Set<String> whichGroupByTopic(final String topic) {
Set<String> groups = new HashSet<String>();
- Iterator<Entry<String, ConcurrentHashMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, Long>>> it = this.offsetTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, Long>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, Long>> next = it.next();
String topicAtGroup = next.getKey();
String[] arrays = topicAtGroup.split(TOPIC_GROUP_SEPARATOR);
if (arrays.length == 2) {
@@ -124,7 +125,7 @@ public class ConsumerOffsetManager extends ConfigManager {
}
private void commitOffset(final String clientHost, final String key, final int queueId, final long offset) {
- ConcurrentHashMap<Integer, Long> map = this.offsetTable.get(key);
+ ConcurrentMap<Integer, Long> map = this.offsetTable.get(key);
if (null == map) {
map = new ConcurrentHashMap<Integer, Long>(32);
map.put(queueId, offset);
@@ -140,7 +141,7 @@ public class ConsumerOffsetManager extends ConfigManager {
public long queryOffset(final String group, final String topic, final int queueId) {
// topic@group
String key = topic + TOPIC_GROUP_SEPARATOR + group;
- ConcurrentHashMap<Integer, Long> map = this.offsetTable.get(key);
+ ConcurrentMap<Integer, Long> map = this.offsetTable.get(key);
if (null != map) {
Long offset = map.get(queueId);
if (offset != null)
@@ -173,11 +174,11 @@ public class ConsumerOffsetManager extends ConfigManager {
return RemotingSerializable.toJson(this, prettyFormat);
}
- public ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>> getOffsetTable() {
+ public ConcurrentMap<String, ConcurrentMap<Integer, Long>> getOffsetTable() {
return offsetTable;
}
- public void setOffsetTable(ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>> offsetTable) {
+ public void setOffsetTable(ConcurrentHashMap<String, ConcurrentMap<Integer, Long>> offsetTable) {
this.offsetTable = offsetTable;
}
@@ -196,7 +197,7 @@ public class ConsumerOffsetManager extends ConfigManager {
}
}
- for (Map.Entry<String, ConcurrentHashMap<Integer, Long>> offSetEntry : this.offsetTable.entrySet()) {
+ for (Map.Entry<String, ConcurrentMap<Integer, Long>> offSetEntry : this.offsetTable.entrySet()) {
String topicGroup = offSetEntry.getKey();
String[] topicGroupArr = topicGroup.split(TOPIC_GROUP_SEPARATOR);
if (topic.equals(topicGroupArr[0])) {
@@ -224,7 +225,7 @@ public class ConsumerOffsetManager extends ConfigManager {
}
public void cloneOffset(final String srcGroup, final String destGroup, final String topic) {
- ConcurrentHashMap<Integer, Long> offsets = this.offsetTable.get(topic + TOPIC_GROUP_SEPARATOR + srcGroup);
+ ConcurrentMap<Integer, Long> offsets = this.offsetTable.get(topic + TOPIC_GROUP_SEPARATOR + srcGroup);
if (offsets != null) {
this.offsetTable.put(topic + TOPIC_GROUP_SEPARATOR + destGroup, new ConcurrentHashMap<Integer, Long>(offsets));
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index f59d295..71fdda9 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -29,7 +29,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
@@ -1084,7 +1084,7 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
GetConsumeStatsInBrokerHeader requestHeader =
(GetConsumeStatsInBrokerHeader) request.decodeCommandCustomHeader(GetConsumeStatsInBrokerHeader.class);
boolean isOrder = requestHeader.isOrder();
- ConcurrentHashMap<String, SubscriptionGroupConfig> subscriptionGroups =
+ ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroups =
brokerController.getSubscriptionGroupManager().getSubscriptionGroupTable();
List<Map<String/* subscriptionGroupName */, List<ConsumeStats>>> brokerConsumeStatsList =
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
index bdf2a01..bd4a26e 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/subscription/SubscriptionGroupManager.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.broker.subscription;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.BrokerPathConfigHelper;
import org.apache.rocketmq.common.ConfigManager;
@@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
public class SubscriptionGroupManager extends ConfigManager {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
- private final ConcurrentHashMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
+ private final ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
new ConcurrentHashMap<String, SubscriptionGroupConfig>(1024);
private final DataVersion dataVersion = new DataVersion();
private transient BrokerController brokerController;
@@ -169,7 +170,7 @@ public class SubscriptionGroupManager extends ConfigManager {
}
}
- public ConcurrentHashMap<String, SubscriptionGroupConfig> getSubscriptionGroupTable() {
+ public ConcurrentMap<String, SubscriptionGroupConfig> getSubscriptionGroupTable() {
return subscriptionGroupTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
index 93a631a..3bcafc0 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/topic/TopicConfigManager.java
@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -44,7 +45,7 @@ public class TopicConfigManager extends ConfigManager {
private static final long LOCK_TIMEOUT_MILLIS = 3000;
private transient final Lock lockTopicConfigTable = new ReentrantLock();
- private final ConcurrentHashMap<String, TopicConfig> topicConfigTable =
+ private final ConcurrentMap<String, TopicConfig> topicConfigTable =
new ConcurrentHashMap<String, TopicConfig>(1024);
private final DataVersion dataVersion = new DataVersion();
private final Set<String> systemTopicList = new HashSet<String>();
@@ -416,7 +417,7 @@ public class TopicConfigManager extends ConfigManager {
return dataVersion;
}
- public ConcurrentHashMap<String, TopicConfig> getTopicConfigTable() {
+ public ConcurrentMap<String, TopicConfig> getTopicConfigTable() {
return topicConfigTable;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/consumer/MQPullConsumerScheduleService.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPullConsumerScheduleService.java b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPullConsumerScheduleService.java
index 6bae85a..e0b546d 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/MQPullConsumerScheduleService.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/MQPullConsumerScheduleService.java
@@ -20,6 +20,7 @@ import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.client.exception.MQClientException;
@@ -35,11 +36,11 @@ import org.slf4j.Logger;
public class MQPullConsumerScheduleService {
private final Logger log = ClientLogger.getLog();
private final MessageQueueListener messageQueueListener = new MessageQueueListenerImpl();
- private final ConcurrentHashMap<MessageQueue, PullTaskImpl> taskTable =
+ private final ConcurrentMap<MessageQueue, PullTaskImpl> taskTable =
new ConcurrentHashMap<MessageQueue, PullTaskImpl>();
private DefaultMQPullConsumer defaultMQPullConsumer;
private int pullThreadNums = 20;
- private ConcurrentHashMap<String /* topic */, PullTaskCallback> callbackTable =
+ private ConcurrentMap<String /* topic */, PullTaskCallback> callbackTable =
new ConcurrentHashMap<String, PullTaskCallback>();
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
@@ -100,7 +101,7 @@ public class MQPullConsumerScheduleService {
}
}
- public ConcurrentHashMap<String, PullTaskCallback> getCallbackTable() {
+ public ConcurrentMap<String, PullTaskCallback> getCallbackTable() {
return callbackTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
index 6c81516..d4b19b2 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/LocalFileOffsetStore.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
@@ -45,7 +46,7 @@ public class LocalFileOffsetStore implements OffsetStore {
private final MQClientInstance mQClientFactory;
private final String groupName;
private final String storePath;
- private ConcurrentHashMap<MessageQueue, AtomicLong> offsetTable =
+ private ConcurrentMap<MessageQueue, AtomicLong> offsetTable =
new ConcurrentHashMap<MessageQueue, AtomicLong>();
public LocalFileOffsetStore(MQClientInstance mQClientFactory, String groupName) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
index 32bcc9f..7dfd97a 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/OffsetSerializeWrapper.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.client.consumer.store;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
@@ -25,14 +26,14 @@ import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
* Wrapper class for offset serialization
*/
public class OffsetSerializeWrapper extends RemotingSerializable {
- private ConcurrentHashMap<MessageQueue, AtomicLong> offsetTable =
+ private ConcurrentMap<MessageQueue, AtomicLong> offsetTable =
new ConcurrentHashMap<MessageQueue, AtomicLong>();
- public ConcurrentHashMap<MessageQueue, AtomicLong> getOffsetTable() {
+ public ConcurrentMap<MessageQueue, AtomicLong> getOffsetTable() {
return offsetTable;
}
- public void setOffsetTable(ConcurrentHashMap<MessageQueue, AtomicLong> offsetTable) {
+ public void setOffsetTable(ConcurrentMap<MessageQueue, AtomicLong> offsetTable) {
this.offsetTable = offsetTable;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
index 60ad101..5bd5749 100644
--- a/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
+++ b/client/src/main/java/org/apache/rocketmq/client/consumer/store/RemoteBrokerOffsetStore.java
@@ -21,6 +21,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
@@ -42,7 +43,7 @@ public class RemoteBrokerOffsetStore implements OffsetStore {
private final static Logger log = ClientLogger.getLog();
private final MQClientInstance mQClientFactory;
private final String groupName;
- private ConcurrentHashMap<MessageQueue, AtomicLong> offsetTable =
+ private ConcurrentMap<MessageQueue, AtomicLong> offsetTable =
new ConcurrentHashMap<MessageQueue, AtomicLong>();
public RemoteBrokerOffsetStore(MQClientInstance mQClientFactory, String groupName) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
index f596b83..25877d7 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/MQClientManager.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.client.impl;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.rocketmq.client.ClientConfig;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
@@ -28,7 +29,7 @@ public class MQClientManager {
private final static Logger log = ClientLogger.getLog();
private static MQClientManager instance = new MQClientManager();
private AtomicInteger factoryIndexGenerator = new AtomicInteger();
- private ConcurrentHashMap<String/* clientId */, MQClientInstance> factoryTable =
+ private ConcurrentMap<String/* clientId */, MQClientInstance> factoryTable =
new ConcurrentHashMap<String, MQClientInstance>();
private MQClientManager() {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
index 7d43b37..35ee16f 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPullConsumerImpl.java
@@ -22,7 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.Validators;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
@@ -115,7 +115,7 @@ public class DefaultMQPullConsumerImpl implements MQConsumerInner {
throw new IllegalArgumentException("topic is null");
}
- ConcurrentHashMap<MessageQueue, ProcessQueue> mqTable = this.rebalanceImpl.getProcessQueueTable();
+ ConcurrentMap<MessageQueue, ProcessQueue> mqTable = this.rebalanceImpl.getProcessQueueTable();
Set<MessageQueue> mqResult = new HashSet<MessageQueue>();
for (MessageQueue mq : mqTable.keySet()) {
if (mq.getTopic().equals(topic)) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
index 8767964..9bf34be 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
@@ -26,7 +26,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.Validators;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
@@ -805,7 +805,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
}
}
- public ConcurrentHashMap<String, SubscriptionData> getSubscriptionInner() {
+ public ConcurrentMap<String, SubscriptionData> getSubscriptionInner() {
return this.rebalanceImpl.getSubscriptionInner();
}
@@ -1060,7 +1060,7 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
private long computeAccumulationTotal() {
long msgAccTotal = 0;
- ConcurrentHashMap<MessageQueue, ProcessQueue> processQueueTable = this.rebalanceImpl.getProcessQueueTable();
+ ConcurrentMap<MessageQueue, ProcessQueue> processQueueTable = this.rebalanceImpl.getProcessQueueTable();
Iterator<Entry<MessageQueue, ProcessQueue>> it = processQueueTable.entrySet().iterator();
while (it.hasNext()) {
Entry<MessageQueue, ProcessQueue> next = it.next();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/consumer/MessageQueueLock.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/MessageQueueLock.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/MessageQueueLock.java
index c25e41b..a02f1b6 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/MessageQueueLock.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/MessageQueueLock.java
@@ -17,13 +17,14 @@
package org.apache.rocketmq.client.impl.consumer;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.message.MessageQueue;
/**
* Message lock,strictly ensure the single queue only one thread at a time consuming
*/
public class MessageQueueLock {
- private ConcurrentHashMap<MessageQueue, Object> mqLockTable =
+ private ConcurrentMap<MessageQueue, Object> mqLockTable =
new ConcurrentHashMap<MessageQueue, Object>();
public Object fetchLockObject(final MessageQueue mq) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
index 304a44a..bbdf27d 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/PullAPIWrapper.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.rocketmq.client.consumer.PullCallback;
import org.apache.rocketmq.client.consumer.PullResult;
@@ -53,7 +54,7 @@ public class PullAPIWrapper {
private final MQClientInstance mQClientFactory;
private final String consumerGroup;
private final boolean unitMode;
- private ConcurrentHashMap<MessageQueue, AtomicLong/* brokerId */> pullFromWhichNodeTable =
+ private ConcurrentMap<MessageQueue, AtomicLong/* brokerId */> pullFromWhichNodeTable =
new ConcurrentHashMap<MessageQueue, AtomicLong>(32);
private volatile boolean connectBrokerByUser = false;
private volatile long defaultBrokerId = MixAll.MASTER_ID;
@@ -247,7 +248,7 @@ public class PullAPIWrapper {
private String computPullFromWhichFilterServer(final String topic, final String brokerAddr)
throws MQClientException {
- ConcurrentHashMap<String, TopicRouteData> topicRouteTable = this.mQClientFactory.getTopicRouteTable();
+ ConcurrentMap<String, TopicRouteData> topicRouteTable = this.mQClientFactory.getTopicRouteTable();
if (topicRouteTable != null) {
TopicRouteData topicRouteData = topicRouteTable.get(topic);
List<String> list = topicRouteData.getFilterServerTable().get(brokerAddr);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java
index 6b12221..634e0f0 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalanceImpl.java
@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.client.consumer.AllocateMessageQueueStrategy;
import org.apache.rocketmq.client.impl.FindBrokerResult;
import org.apache.rocketmq.client.impl.factory.MQClientInstance;
@@ -44,10 +45,10 @@ import org.slf4j.Logger;
*/
public abstract class RebalanceImpl {
protected static final Logger log = ClientLogger.getLog();
- protected final ConcurrentHashMap<MessageQueue, ProcessQueue> processQueueTable = new ConcurrentHashMap<MessageQueue, ProcessQueue>(64);
- protected final ConcurrentHashMap<String/* topic */, Set<MessageQueue>> topicSubscribeInfoTable =
+ protected final ConcurrentMap<MessageQueue, ProcessQueue> processQueueTable = new ConcurrentHashMap<MessageQueue, ProcessQueue>(64);
+ protected final ConcurrentMap<String/* topic */, Set<MessageQueue>> topicSubscribeInfoTable =
new ConcurrentHashMap<String, Set<MessageQueue>>();
- protected final ConcurrentHashMap<String /* topic */, SubscriptionData> subscriptionInner =
+ protected final ConcurrentMap<String /* topic */, SubscriptionData> subscriptionInner =
new ConcurrentHashMap<String, SubscriptionData>();
protected String consumerGroup;
protected MessageModel messageModel;
@@ -232,7 +233,7 @@ public abstract class RebalanceImpl {
this.truncateMessageQueueNotMyTopic();
}
- public ConcurrentHashMap<String, SubscriptionData> getSubscriptionInner() {
+ public ConcurrentMap<String, SubscriptionData> getSubscriptionInner() {
return subscriptionInner;
}
@@ -421,11 +422,11 @@ public abstract class RebalanceImpl {
}
}
- public ConcurrentHashMap<MessageQueue, ProcessQueue> getProcessQueueTable() {
+ public ConcurrentMap<MessageQueue, ProcessQueue> getProcessQueueTable() {
return processQueueTable;
}
- public ConcurrentHashMap<String, Set<MessageQueue>> getTopicSubscribeInfoTable() {
+ public ConcurrentMap<String, Set<MessageQueue>> getTopicSubscribeInfoTable() {
return topicSubscribeInfoTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index 1b075ee..f146be9 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -28,6 +28,7 @@ import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
@@ -88,18 +89,18 @@ public class MQClientInstance {
private final int instanceIndex;
private final String clientId;
private final long bootTimestamp = System.currentTimeMillis();
- private final ConcurrentHashMap<String/* group */, MQProducerInner> producerTable = new ConcurrentHashMap<String, MQProducerInner>();
- private final ConcurrentHashMap<String/* group */, MQConsumerInner> consumerTable = new ConcurrentHashMap<String, MQConsumerInner>();
- private final ConcurrentHashMap<String/* group */, MQAdminExtInner> adminExtTable = new ConcurrentHashMap<String, MQAdminExtInner>();
+ private final ConcurrentMap<String/* group */, MQProducerInner> producerTable = new ConcurrentHashMap<String, MQProducerInner>();
+ private final ConcurrentMap<String/* group */, MQConsumerInner> consumerTable = new ConcurrentHashMap<String, MQConsumerInner>();
+ private final ConcurrentMap<String/* group */, MQAdminExtInner> adminExtTable = new ConcurrentHashMap<String, MQAdminExtInner>();
private final NettyClientConfig nettyClientConfig;
private final MQClientAPIImpl mQClientAPIImpl;
private final MQAdminImpl mQAdminImpl;
- private final ConcurrentHashMap<String/* Topic */, TopicRouteData> topicRouteTable = new ConcurrentHashMap<String, TopicRouteData>();
+ private final ConcurrentMap<String/* Topic */, TopicRouteData> topicRouteTable = new ConcurrentHashMap<String, TopicRouteData>();
private final Lock lockNamesrv = new ReentrantLock();
private final Lock lockHeartbeat = new ReentrantLock();
- private final ConcurrentHashMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> brokerAddrTable =
+ private final ConcurrentMap<String/* Broker Name */, HashMap<Long/* brokerId */, String/* address */>> brokerAddrTable =
new ConcurrentHashMap<String, HashMap<Long, String>>();
- private final ConcurrentHashMap<String/* Broker Name */, HashMap<String/* address */, Integer>> brokerVersionTable =
+ private final ConcurrentMap<String/* Broker Name */, HashMap<String/* address */, Integer>> brokerVersionTable =
new ConcurrentHashMap<String, HashMap<String, Integer>>();
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
@@ -1088,7 +1089,7 @@ public class MQClientInstance {
}
consumer.suspend();
- ConcurrentHashMap<MessageQueue, ProcessQueue> processQueueTable = consumer.getRebalanceImpl().getProcessQueueTable();
+ ConcurrentMap<MessageQueue, ProcessQueue> processQueueTable = consumer.getRebalanceImpl().getProcessQueueTable();
for (Map.Entry<MessageQueue, ProcessQueue> entry : processQueueTable.entrySet()) {
MessageQueue mq = entry.getKey();
if (topic.equals(mq.getTopic()) && offsetTable.containsKey(mq)) {
@@ -1166,7 +1167,7 @@ public class MQClientInstance {
return defaultMQProducer;
}
- public ConcurrentHashMap<String, TopicRouteData> getTopicRouteTable() {
+ public ConcurrentMap<String, TopicRouteData> getTopicRouteTable() {
return topicRouteTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
index d828875..12f8a36 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/producer/DefaultMQProducerImpl.java
@@ -26,6 +26,7 @@ import java.util.Random;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@@ -84,7 +85,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
private final Logger log = ClientLogger.getLog();
private final Random random = new Random();
private final DefaultMQProducer defaultMQProducer;
- private final ConcurrentHashMap<String/* topic */, TopicPublishInfo> topicPublishInfoTable =
+ private final ConcurrentMap<String/* topic */, TopicPublishInfo> topicPublishInfoTable =
new ConcurrentHashMap<String, TopicPublishInfo>();
private final ArrayList<SendMessageHook> sendMessageHookList = new ArrayList<SendMessageHook>();
private final RPCHook rpcHook;
@@ -1057,7 +1058,7 @@ public class DefaultMQProducerImpl implements MQProducerInner {
return this.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout);
}
- public ConcurrentHashMap<String, TopicPublishInfo> getTopicPublishInfoTable() {
+ public ConcurrentMap<String, TopicPublishInfo> getTopicPublishInfoTable() {
return topicPublishInfoTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
index 7478dd2..3a0356c 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerConnection.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.common.protocol.body;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
@@ -27,7 +28,7 @@ import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class ConsumerConnection extends RemotingSerializable {
private HashSet<Connection> connectionSet = new HashSet<Connection>();
- private ConcurrentHashMap<String/* Topic */, SubscriptionData> subscriptionTable =
+ private ConcurrentMap<String/* Topic */, SubscriptionData> subscriptionTable =
new ConcurrentHashMap<String, SubscriptionData>();
private ConsumeType consumeType;
private MessageModel messageModel;
@@ -52,7 +53,7 @@ public class ConsumerConnection extends RemotingSerializable {
this.connectionSet = connectionSet;
}
- public ConcurrentHashMap<String, SubscriptionData> getSubscriptionTable() {
+ public ConcurrentMap<String, SubscriptionData> getSubscriptionTable() {
return subscriptionTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
index 02bf811..5b08d78 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumerOffsetSerializeWrapper.java
@@ -18,17 +18,18 @@
package org.apache.rocketmq.common.protocol.body;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class ConsumerOffsetSerializeWrapper extends RemotingSerializable {
- private ConcurrentHashMap<String/* topic@group */, ConcurrentHashMap<Integer, Long>> offsetTable =
- new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>>(512);
+ private ConcurrentMap<String/* topic@group */, ConcurrentMap<Integer, Long>> offsetTable =
+ new ConcurrentHashMap<String, ConcurrentMap<Integer, Long>>(512);
- public ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>> getOffsetTable() {
+ public ConcurrentMap<String, ConcurrentMap<Integer, Long>> getOffsetTable() {
return offsetTable;
}
- public void setOffsetTable(ConcurrentHashMap<String, ConcurrentHashMap<Integer, Long>> offsetTable) {
+ public void setOffsetTable(ConcurrentMap<String, ConcurrentMap<Integer, Long>> offsetTable) {
this.offsetTable = offsetTable;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
index 92c15eb..e05f759 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/SubscriptionGroupWrapper.java
@@ -18,21 +18,22 @@
package org.apache.rocketmq.common.protocol.body;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.DataVersion;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class SubscriptionGroupWrapper extends RemotingSerializable {
- private ConcurrentHashMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
+ private ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable =
new ConcurrentHashMap<String, SubscriptionGroupConfig>(1024);
private DataVersion dataVersion = new DataVersion();
- public ConcurrentHashMap<String, SubscriptionGroupConfig> getSubscriptionGroupTable() {
+ public ConcurrentMap<String, SubscriptionGroupConfig> getSubscriptionGroupTable() {
return subscriptionGroupTable;
}
public void setSubscriptionGroupTable(
- ConcurrentHashMap<String, SubscriptionGroupConfig> subscriptionGroupTable) {
+ ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable) {
this.subscriptionGroupTable = subscriptionGroupTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
index c471d1a..ce12302 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/TopicConfigSerializeWrapper.java
@@ -18,20 +18,21 @@
package org.apache.rocketmq.common.protocol.body;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.DataVersion;
import org.apache.rocketmq.common.TopicConfig;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class TopicConfigSerializeWrapper extends RemotingSerializable {
- private ConcurrentHashMap<String, TopicConfig> topicConfigTable =
+ private ConcurrentMap<String, TopicConfig> topicConfigTable =
new ConcurrentHashMap<String, TopicConfig>();
private DataVersion dataVersion = new DataVersion();
- public ConcurrentHashMap<String, TopicConfig> getTopicConfigTable() {
+ public ConcurrentMap<String, TopicConfig> getTopicConfigTable() {
return topicConfigTable;
}
- public void setTopicConfigTable(ConcurrentHashMap<String, TopicConfig> topicConfigTable) {
+ public void setTopicConfigTable(ConcurrentMap<String, TopicConfig> topicConfigTable) {
this.topicConfigTable = topicConfigTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/stats/MomentStatsItemSet.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/stats/MomentStatsItemSet.java b/common/src/main/java/org/apache/rocketmq/common/stats/MomentStatsItemSet.java
index 5498d34..57dfc38 100644
--- a/common/src/main/java/org/apache/rocketmq/common/stats/MomentStatsItemSet.java
+++ b/common/src/main/java/org/apache/rocketmq/common/stats/MomentStatsItemSet.java
@@ -20,13 +20,14 @@ package org.apache.rocketmq.common.stats;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.UtilAll;
import org.slf4j.Logger;
public class MomentStatsItemSet {
- private final ConcurrentHashMap<String/* key */, MomentStatsItem> statsItemTable =
+ private final ConcurrentMap<String/* key */, MomentStatsItem> statsItemTable =
new ConcurrentHashMap<String, MomentStatsItem>(128);
private final String statsName;
private final ScheduledExecutorService scheduledExecutorService;
@@ -39,7 +40,7 @@ public class MomentStatsItemSet {
this.init();
}
- public ConcurrentHashMap<String, MomentStatsItem> getStatsItemTable() {
+ public ConcurrentMap<String, MomentStatsItem> getStatsItemTable() {
return statsItemTable;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/common/src/main/java/org/apache/rocketmq/common/stats/StatsItemSet.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/stats/StatsItemSet.java b/common/src/main/java/org/apache/rocketmq/common/stats/StatsItemSet.java
index 8633d68..17dbf0d 100644
--- a/common/src/main/java/org/apache/rocketmq/common/stats/StatsItemSet.java
+++ b/common/src/main/java/org/apache/rocketmq/common/stats/StatsItemSet.java
@@ -20,13 +20,14 @@ package org.apache.rocketmq.common.stats;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.rocketmq.common.UtilAll;
import org.slf4j.Logger;
public class StatsItemSet {
- private final ConcurrentHashMap<String/* key */, StatsItem> statsItemTable =
+ private final ConcurrentMap<String/* key */, StatsItem> statsItemTable =
new ConcurrentHashMap<String, StatsItem>(128);
private final String statsName;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/FilterClassManager.java
----------------------------------------------------------------------
diff --git a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/FilterClassManager.java b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/FilterClassManager.java
index 2c31538..490c582 100644
--- a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/FilterClassManager.java
+++ b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/filter/FilterClassManager.java
@@ -20,6 +20,7 @@ package org.apache.rocketmq.filtersrv.filter;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -40,7 +41,7 @@ public class FilterClassManager {
private final ScheduledExecutorService scheduledExecutorService = Executors
.newSingleThreadScheduledExecutor(new ThreadFactoryImpl("FSGetClassScheduledThread"));
- private ConcurrentHashMap<String/* topic@consumerGroup */, FilterClassInfo> filterClassTable =
+ private ConcurrentMap<String/* topic@consumerGroup */, FilterClassInfo> filterClassTable =
new ConcurrentHashMap<String, FilterClassInfo>(128);
private FilterClassFetchMethod filterClassFetchMethod;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
----------------------------------------------------------------------
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
index 5a953a9..7479fcc 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
@@ -25,7 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.rocketmq.common.DataVersion;
@@ -135,7 +135,7 @@ public class RouteInfoManager {
&& MixAll.MASTER_ID == brokerId) {
if (this.isBrokerTopicConfigChanged(brokerAddr, topicConfigWrapper.getDataVersion())//
|| registerFirst) {
- ConcurrentHashMap<String, TopicConfig> tcTable =
+ ConcurrentMap<String, TopicConfig> tcTable =
topicConfigWrapper.getTopicConfigTable();
if (tcTable != null) {
for (Map.Entry<String, TopicConfig> entry : tcTable.entrySet()) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index 15586cb..0ba714a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -27,6 +27,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
@@ -67,7 +68,7 @@ public abstract class NettyRemotingAbstract {
/**
* This map caches all on-going requests.
*/
- protected final ConcurrentHashMap<Integer /* opaque */, ResponseFuture> responseTable =
+ protected final ConcurrentMap<Integer /* opaque */, ResponseFuture> responseTable =
new ConcurrentHashMap<Integer, ResponseFuture>(256);
/**
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
index 52ca47e..1c3da9a 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
@@ -41,6 +41,7 @@ import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
@@ -73,7 +74,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
private final Bootstrap bootstrap = new Bootstrap();
private final EventLoopGroup eventLoopGroupWorker;
private final Lock lockChannelTables = new ReentrantLock();
- private final ConcurrentHashMap<String /* addr */, ChannelWrapper> channelTables = new ConcurrentHashMap<String, ChannelWrapper>();
+ private final ConcurrentMap<String /* addr */, ChannelWrapper> channelTables = new ConcurrentHashMap<String, ChannelWrapper>();
private final Timer timer = new Timer("ClientHouseKeepingService", true);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/store/src/main/java/org/apache/rocketmq/store/AllocateMappedFileService.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/AllocateMappedFileService.java b/store/src/main/java/org/apache/rocketmq/store/AllocateMappedFileService.java
index 0993a5f..abb8385 100644
--- a/store/src/main/java/org/apache/rocketmq/store/AllocateMappedFileService.java
+++ b/store/src/main/java/org/apache/rocketmq/store/AllocateMappedFileService.java
@@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -36,7 +37,7 @@ import org.slf4j.LoggerFactory;
public class AllocateMappedFileService extends ServiceThread {
private static final Logger log = LoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);
private static int waitTimeOut = 1000 * 5;
- private ConcurrentHashMap<String, AllocateRequest> requestTable =
+ private ConcurrentMap<String, AllocateRequest> requestTable =
new ConcurrentHashMap<String, AllocateRequest>();
private PriorityBlockingQueue<AllocateRequest> requestQueue =
new PriorityBlockingQueue<AllocateRequest>();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
index 931edc7..4549f1e 100644
--- a/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
+++ b/store/src/main/java/org/apache/rocketmq/store/DefaultMessageStore.java
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -64,7 +65,7 @@ public class DefaultMessageStore implements MessageStore {
// CommitLog
private final CommitLog commitLog;
- private final ConcurrentHashMap<String/* topic */, ConcurrentHashMap<Integer/* queueId */, ConsumeQueue>> consumeQueueTable;
+ private final ConcurrentMap<String/* topic */, ConcurrentMap<Integer/* queueId */, ConsumeQueue>> consumeQueueTable;
private final FlushConsumeQueueService flushConsumeQueueService;
@@ -140,9 +141,9 @@ public class DefaultMessageStore implements MessageStore {
}
public void truncateDirtyLogicFiles(long phyOffset) {
- ConcurrentHashMap<String, ConcurrentHashMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
+ ConcurrentMap<String, ConcurrentMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : tables.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : tables.values()) {
for (ConsumeQueue logic : maps.values()) {
logic.truncateDirtyLogicFiles(phyOffset);
}
@@ -267,7 +268,7 @@ public class DefaultMessageStore implements MessageStore {
}
public void destroyLogics() {
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
for (ConsumeQueue logic : maps.values()) {
logic.destroy();
}
@@ -885,13 +886,13 @@ public class DefaultMessageStore implements MessageStore {
@Override
public int cleanUnusedTopic(Set<String> topics) {
- Iterator<Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, ConsumeQueue>> next = it.next();
String topic = next.getKey();
if (!topics.contains(topic) && !topic.equals(ScheduleMessageService.SCHEDULE_TOPIC)) {
- ConcurrentHashMap<Integer, ConsumeQueue> queueTable = next.getValue();
+ ConcurrentMap<Integer, ConsumeQueue> queueTable = next.getValue();
for (ConsumeQueue cq : queueTable.values()) {
cq.destroy();
log.info("cleanUnusedTopic: {} {} ConsumeQueue cleaned", //
@@ -913,12 +914,12 @@ public class DefaultMessageStore implements MessageStore {
public void cleanExpiredConsumerQueue() {
long minCommitLogOffset = this.commitLog.getMinOffset();
- Iterator<Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, ConsumeQueue>> next = it.next();
String topic = next.getKey();
if (!topic.equals(ScheduleMessageService.SCHEDULE_TOPIC)) {
- ConcurrentHashMap<Integer, ConsumeQueue> queueTable = next.getValue();
+ ConcurrentMap<Integer, ConsumeQueue> queueTable = next.getValue();
Iterator<Entry<Integer, ConsumeQueue>> itQT = queueTable.entrySet().iterator();
while (itQT.hasNext()) {
Entry<Integer, ConsumeQueue> nextQT = itQT.next();
@@ -1061,10 +1062,10 @@ public class DefaultMessageStore implements MessageStore {
}
public ConsumeQueue findConsumeQueue(String topic, int queueId) {
- ConcurrentHashMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
+ ConcurrentMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
if (null == map) {
- ConcurrentHashMap<Integer, ConsumeQueue> newMap = new ConcurrentHashMap<Integer, ConsumeQueue>(128);
- ConcurrentHashMap<Integer, ConsumeQueue> oldMap = consumeQueueTable.putIfAbsent(topic, newMap);
+ ConcurrentMap<Integer, ConsumeQueue> newMap = new ConcurrentHashMap<Integer, ConsumeQueue>(128);
+ ConcurrentMap<Integer, ConsumeQueue> oldMap = consumeQueueTable.putIfAbsent(topic, newMap);
if (oldMap != null) {
map = oldMap;
} else {
@@ -1205,9 +1206,9 @@ public class DefaultMessageStore implements MessageStore {
private void checkSelf() {
this.commitLog.checkSelf();
- Iterator<Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
+ Iterator<Entry<String, ConcurrentMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
while (it.hasNext()) {
- Entry<String, ConcurrentHashMap<Integer, ConsumeQueue>> next = it.next();
+ Entry<String, ConcurrentMap<Integer, ConsumeQueue>> next = it.next();
Iterator<Entry<Integer, ConsumeQueue>> itNext = next.getValue().entrySet().iterator();
while (itNext.hasNext()) {
Entry<Integer, ConsumeQueue> cq = itNext.next();
@@ -1280,7 +1281,7 @@ public class DefaultMessageStore implements MessageStore {
}
private void putConsumeQueue(final String topic, final int queueId, final ConsumeQueue consumeQueue) {
- ConcurrentHashMap<Integer/* queueId */, ConsumeQueue> map = this.consumeQueueTable.get(topic);
+ ConcurrentMap<Integer/* queueId */, ConsumeQueue> map = this.consumeQueueTable.get(topic);
if (null == map) {
map = new ConcurrentHashMap<Integer/* queueId */, ConsumeQueue>();
map.put(queueId, consumeQueue);
@@ -1291,7 +1292,7 @@ public class DefaultMessageStore implements MessageStore {
}
private void recoverConsumeQueue() {
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
for (ConsumeQueue logic : maps.values()) {
logic.recover();
}
@@ -1301,7 +1302,7 @@ public class DefaultMessageStore implements MessageStore {
private void recoverTopicQueueTable() {
HashMap<String/* topic-queueid */, Long/* offset */> table = new HashMap<String, Long>(1024);
long minPhyOffset = this.commitLog.getMinOffset();
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : this.consumeQueueTable.values()) {
for (ConsumeQueue logic : maps.values()) {
String key = logic.getTopic() + "-" + logic.getQueueId();
table.put(key, logic.getMaxOffsetInQueue());
@@ -1324,7 +1325,7 @@ public class DefaultMessageStore implements MessageStore {
return runningFlags;
}
- public ConcurrentHashMap<String, ConcurrentHashMap<Integer, ConsumeQueue>> getConsumeQueueTable() {
+ public ConcurrentMap<String, ConcurrentMap<Integer, ConsumeQueue>> getConsumeQueueTable() {
return consumeQueueTable;
}
@@ -1375,7 +1376,7 @@ public class DefaultMessageStore implements MessageStore {
@Override
public ConsumeQueue getConsumeQueue(String topic, int queueId) {
- ConcurrentHashMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
+ ConcurrentMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
if (map == null) {
return null;
}
@@ -1594,9 +1595,9 @@ public class DefaultMessageStore implements MessageStore {
if (minOffset > this.lastPhysicalMinOffset) {
this.lastPhysicalMinOffset = minOffset;
- ConcurrentHashMap<String, ConcurrentHashMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
+ ConcurrentMap<String, ConcurrentMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : tables.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : tables.values()) {
for (ConsumeQueue logic : maps.values()) {
int deleteCount = logic.deleteExpiredFile(minOffset);
@@ -1639,9 +1640,9 @@ public class DefaultMessageStore implements MessageStore {
logicsMsgTimestamp = DefaultMessageStore.this.getStoreCheckpoint().getLogicsMsgTimestamp();
}
- ConcurrentHashMap<String, ConcurrentHashMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
+ ConcurrentMap<String, ConcurrentMap<Integer, ConsumeQueue>> tables = DefaultMessageStore.this.consumeQueueTable;
- for (ConcurrentHashMap<Integer, ConsumeQueue> maps : tables.values()) {
+ for (ConcurrentMap<Integer, ConsumeQueue> maps : tables.values()) {
for (ConsumeQueue cq : maps.values()) {
boolean result = false;
for (int i = 0; i < retryTimes && !result; i++) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java b/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
index efb6aa8..7021992 100644
--- a/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
+++ b/store/src/main/java/org/apache/rocketmq/store/schedule/DelayOffsetSerializeWrapper.java
@@ -17,17 +17,18 @@
package org.apache.rocketmq.store.schedule;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
public class DelayOffsetSerializeWrapper extends RemotingSerializable {
- private ConcurrentHashMap<Integer /* level */, Long/* offset */> offsetTable =
+ private ConcurrentMap<Integer /* level */, Long/* offset */> offsetTable =
new ConcurrentHashMap<Integer, Long>(32);
- public ConcurrentHashMap<Integer, Long> getOffsetTable() {
+ public ConcurrentMap<Integer, Long> getOffsetTable() {
return offsetTable;
}
- public void setOffsetTable(ConcurrentHashMap<Integer, Long> offsetTable) {
+ public void setOffsetTable(ConcurrentMap<Integer, Long> offsetTable) {
this.offsetTable = offsetTable;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/96cd2e4e/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
----------------------------------------------------------------------
diff --git a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
index 501876e..172954d 100644
--- a/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
+++ b/store/src/main/java/org/apache/rocketmq/store/schedule/ScheduleMessageService.java
@@ -23,6 +23,7 @@ import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.rocketmq.common.ConfigManager;
import org.apache.rocketmq.common.TopicFilterType;
import org.apache.rocketmq.common.constant.LoggerName;
@@ -49,10 +50,10 @@ public class ScheduleMessageService extends ConfigManager {
private static final long DELAY_FOR_A_WHILE = 100L;
private static final long DELAY_FOR_A_PERIOD = 10000L;
- private final ConcurrentHashMap<Integer /* level */, Long/* delay timeMillis */> delayLevelTable =
+ private final ConcurrentMap<Integer /* level */, Long/* delay timeMillis */> delayLevelTable =
new ConcurrentHashMap<Integer, Long>(32);
- private final ConcurrentHashMap<Integer /* level */, Long/* offset */> offsetTable =
+ private final ConcurrentMap<Integer /* level */, Long/* offset */> offsetTable =
new ConcurrentHashMap<Integer, Long>(32);
private final Timer timer = new Timer("ScheduleMessageTimerThread", true);
[37/50] [abbrv] incubator-rocketmq git commit:
[ROCKETMQ-160]SendHeartBeat may not be logged in the expected period closes
apache/incubator-rocketmq#86
Posted by do...@apache.org.
[ROCKETMQ-160]SendHeartBeat may not be logged in the expected period closes apache/incubator-rocketmq#86
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/04c8925d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/04c8925d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/04c8925d
Branch: refs/heads/release-4.1.0-incubating
Commit: 04c8925d6da77a41cef746a9c6478a407c4c9edd
Parents: adae162
Author: Jaskey <li...@gmail.com>
Authored: Sat May 27 12:38:00 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 12:38:00 2017 +0800
----------------------------------------------------------------------
.../client/impl/factory/MQClientInstance.java | 66 ++++++++++----------
1 file changed, 34 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/04c8925d/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
index a8c65b2..1b075ee 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/factory/MQClientInstance.java
@@ -112,7 +112,7 @@ public class MQClientInstance {
private final RebalanceService rebalanceService;
private final DefaultMQProducer defaultMQProducer;
private final ConsumerStatsManager consumerStatsManager;
- private final AtomicLong storeTimesTotal = new AtomicLong(0);
+ private final AtomicLong sendHeartbeatTimesTotal = new AtomicLong(0);
private ServiceState serviceState = ServiceState.CREATE_JUST;
private DatagramSocket datagramSocket;
private Random random = new Random();
@@ -517,38 +517,40 @@ public class MQClientInstance {
return;
}
- long times = this.storeTimesTotal.getAndIncrement();
- Iterator<Entry<String, HashMap<Long, String>>> it = this.brokerAddrTable.entrySet().iterator();
- while (it.hasNext()) {
- Entry<String, HashMap<Long, String>> entry = it.next();
- String brokerName = entry.getKey();
- HashMap<Long, String> oneTable = entry.getValue();
- if (oneTable != null) {
- for (Map.Entry<Long, String> entry1 : oneTable.entrySet()) {
- Long id = entry1.getKey();
- String addr = entry1.getValue();
- if (addr != null) {
- if (consumerEmpty) {
- if (id != MixAll.MASTER_ID)
- continue;
- }
-
- try {
- int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
- if (!this.brokerVersionTable.containsKey(brokerName)) {
- this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
- }
- this.brokerVersionTable.get(brokerName).put(addr, version);
- if (times % 20 == 0) {
- log.info("send heart beat to broker[{} {} {}] success", brokerName, id, addr);
- log.info(heartbeatData.toString());
+ if (!this.brokerAddrTable.isEmpty()) {
+ long times = this.sendHeartbeatTimesTotal.getAndIncrement();
+ Iterator<Entry<String, HashMap<Long, String>>> it = this.brokerAddrTable.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<String, HashMap<Long, String>> entry = it.next();
+ String brokerName = entry.getKey();
+ HashMap<Long, String> oneTable = entry.getValue();
+ if (oneTable != null) {
+ for (Map.Entry<Long, String> entry1 : oneTable.entrySet()) {
+ Long id = entry1.getKey();
+ String addr = entry1.getValue();
+ if (addr != null) {
+ if (consumerEmpty) {
+ if (id != MixAll.MASTER_ID)
+ continue;
}
- } catch (Exception e) {
- if (this.isBrokerInNameServer(addr)) {
- log.error("send heart beat to broker exception", e);
- } else {
- log.info("send heart beat to broker[{} {} {}] exception, because the broker not up, forget it", brokerName,
- id, addr);
+
+ try {
+ int version = this.mQClientAPIImpl.sendHearbeat(addr, heartbeatData, 3000);
+ if (!this.brokerVersionTable.containsKey(brokerName)) {
+ this.brokerVersionTable.put(brokerName, new HashMap<String, Integer>(4));
+ }
+ this.brokerVersionTable.get(brokerName).put(addr, version);
+ if (times % 20 == 0) {
+ log.info("send heart beat to broker[{} {} {}] success", brokerName, id, addr);
+ log.info(heartbeatData.toString());
+ }
+ } catch (Exception e) {
+ if (this.isBrokerInNameServer(addr)) {
+ log.info("send heart beat to broker[{} {} {}] failed", brokerName, id, addr);
+ } else {
+ log.info("send heart beat to broker[{} {} {}] exception, because the broker not up, forget it", brokerName,
+ id, addr);
+ }
}
}
}
[07/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserConstants.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserConstants.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserConstants.java
new file mode 100644
index 0000000..915658c
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserConstants.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. SelectorParserConstants.java */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
+public interface SelectorParserConstants {
+
+ /**
+ * End of File.
+ */
+ int EOF = 0;
+ /**
+ * RegularExpression Id.
+ */
+ int LINE_COMMENT = 6;
+ /**
+ * RegularExpression Id.
+ */
+ int BLOCK_COMMENT = 7;
+ /**
+ * RegularExpression Id.
+ */
+ int NOT = 8;
+ /**
+ * RegularExpression Id.
+ */
+ int AND = 9;
+ /**
+ * RegularExpression Id.
+ */
+ int OR = 10;
+ /**
+ * RegularExpression Id.
+ */
+ int BETWEEN = 11;
+ /**
+ * RegularExpression Id.
+ */
+ int IN = 12;
+ /**
+ * RegularExpression Id.
+ */
+ int TRUE = 13;
+ /**
+ * RegularExpression Id.
+ */
+ int FALSE = 14;
+ /**
+ * RegularExpression Id.
+ */
+ int NULL = 15;
+ /**
+ * RegularExpression Id.
+ */
+ int IS = 16;
+ /**
+ * RegularExpression Id.
+ */
+ int DECIMAL_LITERAL = 17;
+ /**
+ * RegularExpression Id.
+ */
+ int FLOATING_POINT_LITERAL = 18;
+ /**
+ * RegularExpression Id.
+ */
+ int EXPONENT = 19;
+ /**
+ * RegularExpression Id.
+ */
+ int STRING_LITERAL = 20;
+ /**
+ * RegularExpression Id.
+ */
+ int ID = 21;
+
+ /**
+ * Lexical state.
+ */
+ int DEFAULT = 0;
+
+ /**
+ * Literal token values.
+ */
+ String[] TOKEN_IMAGE = {
+ "<EOF>",
+ "\" \"",
+ "\"\\t\"",
+ "\"\\n\"",
+ "\"\\r\"",
+ "\"\\f\"",
+ "<LINE_COMMENT>",
+ "<BLOCK_COMMENT>",
+ "\"NOT\"",
+ "\"AND\"",
+ "\"OR\"",
+ "\"BETWEEN\"",
+ "\"IN\"",
+ "\"TRUE\"",
+ "\"FALSE\"",
+ "\"NULL\"",
+ "\"IS\"",
+ "<DECIMAL_LITERAL>",
+ "<FLOATING_POINT_LITERAL>",
+ "<EXPONENT>",
+ "<STRING_LITERAL>",
+ "<ID>",
+ "\"=\"",
+ "\"<>\"",
+ "\">\"",
+ "\">=\"",
+ "\"<\"",
+ "\"<=\"",
+ "\"(\"",
+ "\",\"",
+ "\")\"",
+ "\"+\"",
+ "\"-\"",
+ };
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserTokenManager.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserTokenManager.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserTokenManager.java
new file mode 100644
index 0000000..354f5ba
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SelectorParserTokenManager.java
@@ -0,0 +1,919 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. SelectorParserTokenManager.java */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * Token Manager.
+ */
+public class SelectorParserTokenManager implements SelectorParserConstants {
+
+ /**
+ * Debug output.
+ */
+ public java.io.PrintStream debugStream = System.out;
+
+ /**
+ * Set debug output.
+ */
+ public void setDebugStream(java.io.PrintStream ds) {
+ debugStream = ds;
+ }
+
+ private int jjStopAtPos(int pos, int kind) {
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+ }
+
+ private int jjMoveStringLiteralDfa0_0() {
+ switch (curChar) {
+ case 9:
+ jjmatchedKind = 2;
+ return jjMoveNfa_0(5, 0);
+ case 10:
+ jjmatchedKind = 3;
+ return jjMoveNfa_0(5, 0);
+ case 12:
+ jjmatchedKind = 5;
+ return jjMoveNfa_0(5, 0);
+ case 13:
+ jjmatchedKind = 4;
+ return jjMoveNfa_0(5, 0);
+ case 32:
+ jjmatchedKind = 1;
+ return jjMoveNfa_0(5, 0);
+ case 40:
+ jjmatchedKind = 28;
+ return jjMoveNfa_0(5, 0);
+ case 41:
+ jjmatchedKind = 30;
+ return jjMoveNfa_0(5, 0);
+ case 43:
+ jjmatchedKind = 31;
+ return jjMoveNfa_0(5, 0);
+ case 44:
+ jjmatchedKind = 29;
+ return jjMoveNfa_0(5, 0);
+ case 45:
+ jjmatchedKind = 32;
+ return jjMoveNfa_0(5, 0);
+ case 60:
+ jjmatchedKind = 26;
+ return jjMoveStringLiteralDfa1_0(0x8800000L);
+ case 61:
+ jjmatchedKind = 22;
+ return jjMoveNfa_0(5, 0);
+ case 62:
+ jjmatchedKind = 24;
+ return jjMoveStringLiteralDfa1_0(0x2000000L);
+ case 65:
+ return jjMoveStringLiteralDfa1_0(0x200L);
+ case 66:
+ return jjMoveStringLiteralDfa1_0(0x800L);
+ case 70:
+ return jjMoveStringLiteralDfa1_0(0x4000L);
+ case 73:
+ return jjMoveStringLiteralDfa1_0(0x11000L);
+ case 78:
+ return jjMoveStringLiteralDfa1_0(0x8100L);
+ case 79:
+ return jjMoveStringLiteralDfa1_0(0x400L);
+ case 84:
+ return jjMoveStringLiteralDfa1_0(0x2000L);
+ case 97:
+ return jjMoveStringLiteralDfa1_0(0x200L);
+ case 98:
+ return jjMoveStringLiteralDfa1_0(0x800L);
+ case 102:
+ return jjMoveStringLiteralDfa1_0(0x4000L);
+ case 105:
+ return jjMoveStringLiteralDfa1_0(0x11000L);
+ case 110:
+ return jjMoveStringLiteralDfa1_0(0x8100L);
+ case 111:
+ return jjMoveStringLiteralDfa1_0(0x400L);
+ case 116:
+ return jjMoveStringLiteralDfa1_0(0x2000L);
+ default:
+ return jjMoveNfa_0(5, 0);
+ }
+ }
+
+ private int jjMoveStringLiteralDfa1_0(long active0) {
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 0);
+ }
+ switch (curChar) {
+ case 61:
+ if ((active0 & 0x2000000L) != 0L) {
+ jjmatchedKind = 25;
+ jjmatchedPos = 1;
+ } else if ((active0 & 0x8000000L) != 0L) {
+ jjmatchedKind = 27;
+ jjmatchedPos = 1;
+ }
+ break;
+ case 62:
+ if ((active0 & 0x800000L) != 0L) {
+ jjmatchedKind = 23;
+ jjmatchedPos = 1;
+ }
+ break;
+ case 65:
+ return jjMoveStringLiteralDfa2_0(active0, 0x4000L);
+ case 69:
+ return jjMoveStringLiteralDfa2_0(active0, 0x800L);
+ case 78:
+ if ((active0 & 0x1000L) != 0L) {
+ jjmatchedKind = 12;
+ jjmatchedPos = 1;
+ }
+ return jjMoveStringLiteralDfa2_0(active0, 0x200L);
+ case 79:
+ return jjMoveStringLiteralDfa2_0(active0, 0x100L);
+ case 82:
+ if ((active0 & 0x400L) != 0L) {
+ jjmatchedKind = 10;
+ jjmatchedPos = 1;
+ }
+ return jjMoveStringLiteralDfa2_0(active0, 0x2000L);
+ case 83:
+ if ((active0 & 0x10000L) != 0L) {
+ jjmatchedKind = 16;
+ jjmatchedPos = 1;
+ }
+ break;
+ case 85:
+ return jjMoveStringLiteralDfa2_0(active0, 0x8000L);
+ case 97:
+ return jjMoveStringLiteralDfa2_0(active0, 0x4000L);
+ case 101:
+ return jjMoveStringLiteralDfa2_0(active0, 0x800L);
+ case 110:
+ if ((active0 & 0x1000L) != 0L) {
+ jjmatchedKind = 12;
+ jjmatchedPos = 1;
+ }
+ return jjMoveStringLiteralDfa2_0(active0, 0x200L);
+ case 111:
+ return jjMoveStringLiteralDfa2_0(active0, 0x100L);
+ case 114:
+ if ((active0 & 0x400L) != 0L) {
+ jjmatchedKind = 10;
+ jjmatchedPos = 1;
+ }
+ return jjMoveStringLiteralDfa2_0(active0, 0x2000L);
+ case 115:
+ if ((active0 & 0x10000L) != 0L) {
+ jjmatchedKind = 16;
+ jjmatchedPos = 1;
+ }
+ break;
+ case 117:
+ return jjMoveStringLiteralDfa2_0(active0, 0x8000L);
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 1);
+ }
+
+ private int jjMoveStringLiteralDfa2_0(long old0, long active0) {
+ if (((active0 &= old0)) == 0L)
+ return jjMoveNfa_0(5, 1);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 1);
+ }
+ switch (curChar) {
+ case 68:
+ if ((active0 & 0x200L) != 0L) {
+ jjmatchedKind = 9;
+ jjmatchedPos = 2;
+ }
+ break;
+ case 76:
+ return jjMoveStringLiteralDfa3_0(active0, 0xc000L);
+ case 84:
+ if ((active0 & 0x100L) != 0L) {
+ jjmatchedKind = 8;
+ jjmatchedPos = 2;
+ }
+ return jjMoveStringLiteralDfa3_0(active0, 0x800L);
+ case 85:
+ return jjMoveStringLiteralDfa3_0(active0, 0x2000L);
+ case 100:
+ if ((active0 & 0x200L) != 0L) {
+ jjmatchedKind = 9;
+ jjmatchedPos = 2;
+ }
+ break;
+ case 108:
+ return jjMoveStringLiteralDfa3_0(active0, 0xc000L);
+ case 116:
+ if ((active0 & 0x100L) != 0L) {
+ jjmatchedKind = 8;
+ jjmatchedPos = 2;
+ }
+ return jjMoveStringLiteralDfa3_0(active0, 0x800L);
+ case 117:
+ return jjMoveStringLiteralDfa3_0(active0, 0x2000L);
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 2);
+ }
+
+ private int jjMoveStringLiteralDfa3_0(long old0, long active0) {
+ if (((active0 &= old0)) == 0L)
+ return jjMoveNfa_0(5, 2);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 2);
+ }
+ switch (curChar) {
+ case 69:
+ if ((active0 & 0x2000L) != 0L) {
+ jjmatchedKind = 13;
+ jjmatchedPos = 3;
+ }
+ break;
+ case 76:
+ if ((active0 & 0x8000L) != 0L) {
+ jjmatchedKind = 15;
+ jjmatchedPos = 3;
+ }
+ break;
+ case 83:
+ return jjMoveStringLiteralDfa4_0(active0, 0x4000L);
+ case 87:
+ return jjMoveStringLiteralDfa4_0(active0, 0x800L);
+ case 101:
+ if ((active0 & 0x2000L) != 0L) {
+ jjmatchedKind = 13;
+ jjmatchedPos = 3;
+ }
+ break;
+ case 108:
+ if ((active0 & 0x8000L) != 0L) {
+ jjmatchedKind = 15;
+ jjmatchedPos = 3;
+ }
+ break;
+ case 115:
+ return jjMoveStringLiteralDfa4_0(active0, 0x4000L);
+ case 119:
+ return jjMoveStringLiteralDfa4_0(active0, 0x800L);
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 3);
+ }
+
+ private int jjMoveStringLiteralDfa4_0(long old0, long active0) {
+ if (((active0 &= old0)) == 0L)
+ return jjMoveNfa_0(5, 3);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 3);
+ }
+ switch (curChar) {
+ case 69:
+ if ((active0 & 0x4000L) != 0L) {
+ jjmatchedKind = 14;
+ jjmatchedPos = 4;
+ }
+ return jjMoveStringLiteralDfa5_0(active0, 0x800L);
+ case 101:
+ if ((active0 & 0x4000L) != 0L) {
+ jjmatchedKind = 14;
+ jjmatchedPos = 4;
+ }
+ return jjMoveStringLiteralDfa5_0(active0, 0x800L);
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 4);
+ }
+
+ private int jjMoveStringLiteralDfa5_0(long old0, long active0) {
+ if (((active0 &= old0)) == 0L)
+ return jjMoveNfa_0(5, 4);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 4);
+ }
+ switch (curChar) {
+ case 69:
+ return jjMoveStringLiteralDfa6_0(active0, 0x800L);
+ case 101:
+ return jjMoveStringLiteralDfa6_0(active0, 0x800L);
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 5);
+ }
+
+ private int jjMoveStringLiteralDfa6_0(long old0, long active0) {
+ if (((active0 &= old0)) == 0L)
+ return jjMoveNfa_0(5, 5);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ return jjMoveNfa_0(5, 5);
+ }
+ switch (curChar) {
+ case 78:
+ if ((active0 & 0x800L) != 0L) {
+ jjmatchedKind = 11;
+ jjmatchedPos = 6;
+ }
+ break;
+ case 110:
+ if ((active0 & 0x800L) != 0L) {
+ jjmatchedKind = 11;
+ jjmatchedPos = 6;
+ }
+ break;
+ default:
+ break;
+ }
+ return jjMoveNfa_0(5, 6);
+ }
+
+ static final long[] JJ_BIT_VEC_0 = {
+ 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL
+ };
+ static final long[] JJ_BIT_VEC_2 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+ };
+
+ private int jjMoveNfa_0(int startState, int curPos) {
+ int strKind = jjmatchedKind;
+ int strPos = jjmatchedPos;
+ int seenUpto;
+ inputStream.backup(seenUpto = curPos + 1);
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ throw new Error("Internal Error");
+ }
+ curPos = 0;
+ int startsAt = 0;
+ jjnewStateCnt = 40;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;) {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64) {
+ long l = 1L << curChar;
+ do {
+ switch (jjstateSet[--i]) {
+ case 5:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(0, 3);
+ else if (curChar == 36) {
+ if (kind > 21)
+ kind = 21;
+ jjCheckNAdd(28);
+ } else if (curChar == 39)
+ jjCheckNAddStates(4, 6);
+ else if (curChar == 46)
+ jjCheckNAdd(18);
+ else if (curChar == 47)
+ jjstateSet[jjnewStateCnt++] = 6;
+ else if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 0;
+ if ((0x3fe000000000000L & l) != 0L) {
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAddTwoStates(15, 16);
+ } else if (curChar == 48) {
+ if (kind > 17)
+ kind = 17;
+ }
+ break;
+ case 0:
+ if (curChar == 45)
+ jjCheckNAddStates(7, 9);
+ break;
+ case 1:
+ if ((0xffffffffffffdbffL & l) != 0L)
+ jjCheckNAddStates(7, 9);
+ break;
+ case 2:
+ if ((0x2400L & l) != 0L && kind > 6)
+ kind = 6;
+ break;
+ case 3:
+ if (curChar == 10 && kind > 6)
+ kind = 6;
+ break;
+ case 4:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 3;
+ break;
+ case 6:
+ if (curChar == 42)
+ jjCheckNAddTwoStates(7, 8);
+ break;
+ case 7:
+ if ((0xfffffbffffffffffL & l) != 0L)
+ jjCheckNAddTwoStates(7, 8);
+ break;
+ case 8:
+ if (curChar == 42)
+ jjCheckNAddStates(10, 12);
+ break;
+ case 9:
+ if ((0xffff7bffffffffffL & l) != 0L)
+ jjCheckNAddTwoStates(10, 8);
+ break;
+ case 10:
+ if ((0xfffffbffffffffffL & l) != 0L)
+ jjCheckNAddTwoStates(10, 8);
+ break;
+ case 11:
+ if (curChar == 47 && kind > 7)
+ kind = 7;
+ break;
+ case 12:
+ if (curChar == 47)
+ jjstateSet[jjnewStateCnt++] = 6;
+ break;
+ case 13:
+ if (curChar == 48 && kind > 17)
+ kind = 17;
+ break;
+ case 14:
+ if ((0x3fe000000000000L & l) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAddTwoStates(15, 16);
+ break;
+ case 15:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 17)
+ kind = 17;
+ jjCheckNAddTwoStates(15, 16);
+ break;
+ case 17:
+ if (curChar == 46)
+ jjCheckNAdd(18);
+ break;
+ case 18:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAddTwoStates(18, 19);
+ break;
+ case 20:
+ if ((0x280000000000L & l) != 0L)
+ jjCheckNAdd(21);
+ break;
+ case 21:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAdd(21);
+ break;
+ case 22:
+ case 23:
+ if (curChar == 39)
+ jjCheckNAddStates(4, 6);
+ break;
+ case 24:
+ if (curChar == 39)
+ jjstateSet[jjnewStateCnt++] = 23;
+ break;
+ case 25:
+ if ((0xffffff7fffffffffL & l) != 0L)
+ jjCheckNAddStates(4, 6);
+ break;
+ case 26:
+ if (curChar == 39 && kind > 20)
+ kind = 20;
+ break;
+ case 27:
+ if (curChar != 36)
+ break;
+ if (kind > 21)
+ kind = 21;
+ jjCheckNAdd(28);
+ break;
+ case 28:
+ if ((0x3ff001000000000L & l) == 0L)
+ break;
+ if (kind > 21)
+ kind = 21;
+ jjCheckNAdd(28);
+ break;
+ case 29:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(0, 3);
+ break;
+ case 30:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(30, 31);
+ break;
+ case 31:
+ if (curChar != 46)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAddTwoStates(32, 33);
+ break;
+ case 32:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAddTwoStates(32, 33);
+ break;
+ case 34:
+ if ((0x280000000000L & l) != 0L)
+ jjCheckNAdd(35);
+ break;
+ case 35:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAdd(35);
+ break;
+ case 36:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(36, 37);
+ break;
+ case 38:
+ if ((0x280000000000L & l) != 0L)
+ jjCheckNAdd(39);
+ break;
+ case 39:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 18)
+ kind = 18;
+ jjCheckNAdd(39);
+ break;
+ default:
+ break;
+ }
+ } while (i != startsAt);
+ } else if (curChar < 128) {
+ long l = 1L << (curChar & 077);
+ do {
+ switch (jjstateSet[--i]) {
+ case 5:
+ case 28:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 21)
+ kind = 21;
+ jjCheckNAdd(28);
+ break;
+ case 1:
+ jjAddStates(7, 9);
+ break;
+ case 7:
+ jjCheckNAddTwoStates(7, 8);
+ break;
+ case 9:
+ case 10:
+ jjCheckNAddTwoStates(10, 8);
+ break;
+ case 16:
+ if ((0x100000001000L & l) != 0L && kind > 17)
+ kind = 17;
+ break;
+ case 19:
+ if ((0x2000000020L & l) != 0L)
+ jjAddStates(13, 14);
+ break;
+ case 25:
+ jjAddStates(4, 6);
+ break;
+ case 33:
+ if ((0x2000000020L & l) != 0L)
+ jjAddStates(15, 16);
+ break;
+ case 37:
+ if ((0x2000000020L & l) != 0L)
+ jjAddStates(17, 18);
+ break;
+ default:
+ break;
+ }
+ } while (i != startsAt);
+ } else {
+ int hiByte = (int) (curChar >> 8);
+ int i1 = hiByte >> 6;
+ long l1 = 1L << (hiByte & 077);
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do {
+ switch (jjstateSet[--i]) {
+ case 1:
+ if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+ jjAddStates(7, 9);
+ break;
+ case 7:
+ if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+ jjCheckNAddTwoStates(7, 8);
+ break;
+ case 9:
+ case 10:
+ if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+ jjCheckNAddTwoStates(10, 8);
+ break;
+ case 25:
+ if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+ jjAddStates(4, 6);
+ break;
+ default:
+ break;
+ }
+ } while (i != startsAt);
+ }
+ if (kind != 0x7fffffff) {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 40 - (jjnewStateCnt = startsAt)))
+ break;
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ break;
+ }
+ }
+ if (jjmatchedPos > strPos)
+ return curPos;
+
+ int toRet = Math.max(curPos, seenUpto);
+
+ if (curPos < toRet)
+ for (i = toRet - Math.min(curPos, seenUpto); i-- > 0; )
+ try {
+ curChar = inputStream.readChar();
+ } catch (java.io.IOException e) {
+ throw new Error("Internal Error : Please send a bug report.");
+ }
+
+ if (jjmatchedPos < strPos) {
+ jjmatchedKind = strKind;
+ jjmatchedPos = strPos;
+ } else if (jjmatchedPos == strPos && jjmatchedKind > strKind)
+ jjmatchedKind = strKind;
+
+ return toRet;
+ }
+
+ static final int[] JJ_NEXT_STATES = {
+ 30, 31, 36, 37, 24, 25, 26, 1, 2, 4, 8, 9, 11, 20, 21, 34,
+ 35, 38, 39,
+ };
+
+ private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) {
+ switch (hiByte) {
+ case 0:
+ return (JJ_BIT_VEC_2[i2] & l2) != 0L;
+ default:
+ if ((JJ_BIT_VEC_0[i1] & l1) != 0L)
+ return true;
+ return false;
+ }
+ }
+
+ /**
+ * Token literal values.
+ */
+ public static final String[] JJ_STR_LITERAL_IMAGES = {
+ "", null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, "\75", "\74\76", "\76",
+ "\76\75", "\74", "\74\75", "\50", "\54", "\51", "\53", "\55"};
+
+ /**
+ * Lexer state names.
+ */
+ public static final String[] LEX_STATE_NAMES = {
+ "DEFAULT",
+ };
+ static final long[] JJ_TO_TOKEN = {
+ 0x1fff7ff01L,
+ };
+ static final long[] JJ_TO_SKIP = {
+ 0xfeL,
+ };
+ static final long[] JJ_TO_SPECIAL = {
+ 0x3eL,
+ };
+ protected SimpleCharStream inputStream;
+ private final int[] jjrounds = new int[40];
+ private final int[] jjstateSet = new int[80];
+ protected char curChar;
+
+ /**
+ * Constructor.
+ */
+ public SelectorParserTokenManager(SimpleCharStream stream) {
+ if (SimpleCharStream.STATIC_FLAG)
+ throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
+ inputStream = stream;
+ }
+
+ /**
+ * Constructor.
+ */
+ public SelectorParserTokenManager(SimpleCharStream stream, int lexState) {
+ this(stream);
+ SwitchTo(lexState);
+ }
+
+ /**
+ * Reinitialise parser.
+ */
+ public void ReInit(SimpleCharStream stream) {
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ inputStream = stream;
+ ReInitRounds();
+ }
+
+ private void ReInitRounds() {
+ int i;
+ jjround = 0x80000001;
+ for (i = 40; i-- > 0; )
+ jjrounds[i] = 0x80000000;
+ }
+
+ /**
+ * Reinitialise parser.
+ */
+ public void ReInit(SimpleCharStream stream, int lexState) {
+ ReInit(stream);
+ SwitchTo(lexState);
+ }
+
+ /**
+ * Switch to specified lex state.
+ */
+ public void SwitchTo(int lexState) {
+ if (lexState >= 1 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.",
+ TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+ }
+
+ protected Token jjFillToken() {
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = JJ_STR_LITERAL_IMAGES[jjmatchedKind];
+ curTokenImage = (im == null) ? inputStream.GetImage() : im;
+ beginLine = inputStream.getBeginLine();
+ beginColumn = inputStream.getBeginColumn();
+ endLine = inputStream.getEndLine();
+ endColumn = inputStream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
+
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
+
+ return t;
+ }
+
+ int curLexState = 0;
+ int defaultLexState = 0;
+ int jjnewStateCnt;
+ int jjround;
+ int jjmatchedPos;
+ int jjmatchedKind;
+
+ /**
+ * Get the next Token.
+ */
+ public Token getNextToken() {
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
+
+ EOFLoop:
+ for (;;) {
+ try {
+ curChar = inputStream.BeginToken();
+ } catch (java.io.IOException e) {
+ jjmatchedKind = 0;
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ if (jjmatchedKind != 0x7fffffff) {
+ if (jjmatchedPos + 1 < curPos)
+ inputStream.backup(curPos - jjmatchedPos - 1);
+ if ((JJ_TO_TOKEN[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) {
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ } else {
+ if ((JJ_TO_SPECIAL[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) {
+ matchedToken = jjFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else {
+ matchedToken.specialToken = specialToken;
+ specialToken = specialToken.next = matchedToken;
+ }
+ }
+ continue EOFLoop;
+ }
+ }
+ int errorLine = inputStream.getEndLine();
+ int errorColumn = inputStream.getEndColumn();
+ String errorAfter = null;
+ boolean eofSeen = false;
+ try {
+ inputStream.readChar();
+ inputStream.backup(1);
+ } catch (java.io.IOException e1) {
+ eofSeen = true;
+ errorAfter = curPos <= 1 ? "" : inputStream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ errorLine++;
+ errorColumn = 0;
+ } else
+ errorColumn++;
+ }
+ if (!eofSeen) {
+ inputStream.backup(1);
+ errorAfter = curPos <= 1 ? "" : inputStream.GetImage();
+ }
+ throw new TokenMgrError(eofSeen, curLexState, errorLine, errorColumn, errorAfter, curChar,
+ TokenMgrError.LEXICAL_ERROR);
+ }
+ }
+
+ private void jjCheckNAdd(int state) {
+ if (jjrounds[state] != jjround) {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+ }
+
+ private void jjAddStates(int start, int end) {
+ do {
+ jjstateSet[jjnewStateCnt++] = JJ_NEXT_STATES[start];
+ } while (start++ != end);
+ }
+
+ private void jjCheckNAddTwoStates(int state1, int state2) {
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+ }
+
+ private void jjCheckNAddStates(int start, int end) {
+ do {
+ jjCheckNAdd(JJ_NEXT_STATES[start]);
+ } while (start++ != end);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/SimpleCharStream.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/SimpleCharStream.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/SimpleCharStream.java
new file mode 100644
index 0000000..94a54b4
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/SimpleCharStream.java
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 5.0 */
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (without unicode processing).
+ */
+
+public class SimpleCharStream {
+ /**
+ * Whether parser is static.
+ */
+ public static final boolean STATIC_FLAG = false;
+ int bufsize;
+ int available;
+ int tokenBegin;
+ /**
+ * Position in buffer.
+ */
+ public int bufpos = -1;
+ protected int bufline[];
+ protected int bufcolumn[];
+
+ protected int column = 0;
+ protected int line = 1;
+
+ protected boolean prevCharIsCR = false;
+ protected boolean prevCharIsLF = false;
+
+ protected java.io.Reader inputStream;
+
+ protected char[] buffer;
+ protected int maxNextCharInd = 0;
+ protected int inBuf = 0;
+ protected int tabSize = 8;
+
+ protected void setTabSize(int i) {
+ tabSize = i;
+ }
+
+ protected int getTabSize(int i) {
+ return tabSize;
+ }
+
+ protected void ExpandBuff(boolean wrapAround) {
+ char[] newbuffer = new char[bufsize + 2048];
+ int newbufline[] = new int[bufsize + 2048];
+ int newbufcolumn[] = new int[bufsize + 2048];
+
+ try {
+ if (wrapAround) {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = bufpos += bufsize - tokenBegin;
+ } else {
+ System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
+ buffer = newbuffer;
+
+ System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
+ bufline = newbufline;
+
+ System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
+ bufcolumn = newbufcolumn;
+
+ maxNextCharInd = bufpos -= tokenBegin;
+ }
+ } catch (Throwable t) {
+ throw new Error(t.getMessage());
+ }
+
+ bufsize += 2048;
+ available = bufsize;
+ tokenBegin = 0;
+ }
+
+ protected void FillBuff() throws java.io.IOException {
+ if (maxNextCharInd == available) {
+ if (available == bufsize) {
+ if (tokenBegin > 2048) {
+ bufpos = maxNextCharInd = 0;
+ available = tokenBegin;
+ } else if (tokenBegin < 0)
+ bufpos = maxNextCharInd = 0;
+ else
+ ExpandBuff(false);
+ } else if (available > tokenBegin)
+ available = bufsize;
+ else if ((tokenBegin - available) < 2048)
+ ExpandBuff(true);
+ else
+ available = tokenBegin;
+ }
+
+ int i;
+ try {
+ if ((i = inputStream.read(buffer, maxNextCharInd, available - maxNextCharInd)) == -1) {
+ inputStream.close();
+ throw new java.io.IOException();
+ } else
+ maxNextCharInd += i;
+ return;
+ } catch (java.io.IOException e) {
+ --bufpos;
+ backup(0);
+ if (tokenBegin == -1)
+ tokenBegin = bufpos;
+ throw e;
+ }
+ }
+
+ /**
+ * Start.
+ */
+ public char BeginToken() throws java.io.IOException {
+ tokenBegin = -1;
+ char c = readChar();
+ tokenBegin = bufpos;
+
+ return c;
+ }
+
+ protected void UpdateLineColumn(char c) {
+ column++;
+
+ if (prevCharIsLF) {
+ prevCharIsLF = false;
+ line += column = 1;
+ } else if (prevCharIsCR) {
+ prevCharIsCR = false;
+ if (c == '\n') {
+ prevCharIsLF = true;
+ } else
+ line += column = 1;
+ }
+
+ switch (c) {
+ case '\r':
+ prevCharIsCR = true;
+ break;
+ case '\n':
+ prevCharIsLF = true;
+ break;
+ case '\t':
+ column--;
+ column += tabSize - (column % tabSize);
+ break;
+ default:
+ break;
+ }
+
+ bufline[bufpos] = line;
+ bufcolumn[bufpos] = column;
+ }
+
+ /**
+ * Read a character.
+ */
+ public char readChar() throws java.io.IOException {
+ if (inBuf > 0) {
+ --inBuf;
+
+ if (++bufpos == bufsize)
+ bufpos = 0;
+
+ return buffer[bufpos];
+ }
+
+ if (++bufpos >= maxNextCharInd)
+ FillBuff();
+
+ char c = buffer[bufpos];
+
+ UpdateLineColumn(c);
+ return c;
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndColumn
+ */
+
+ public int getColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ @Deprecated
+ /**
+ * @deprecated
+ * @see #getEndLine
+ */
+
+ public int getLine() {
+ return bufline[bufpos];
+ }
+
+ /**
+ * Get token end column number.
+ */
+ public int getEndColumn() {
+ return bufcolumn[bufpos];
+ }
+
+ /**
+ * Get token end line number.
+ */
+ public int getEndLine() {
+ return bufline[bufpos];
+ }
+
+ /**
+ * Get token beginning column number.
+ */
+ public int getBeginColumn() {
+ return bufcolumn[tokenBegin];
+ }
+
+ /**
+ * Get token beginning line number.
+ */
+ public int getBeginLine() {
+ return bufline[tokenBegin];
+ }
+
+ /**
+ * Backup a number of characters.
+ */
+ public void backup(int amount) {
+
+ inBuf += amount;
+ if ((bufpos -= amount) < 0)
+ bufpos += bufsize;
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize) {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.Reader dstream, int startline,
+ int startcolumn) {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.Reader dstream) {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn, int buffersize) {
+ inputStream = dstream;
+ line = startline;
+ column = startcolumn - 1;
+
+ if (buffer == null || buffersize != buffer.length) {
+ available = bufsize = buffersize;
+ buffer = new char[buffersize];
+ bufline = new int[buffersize];
+ bufcolumn = new int[buffersize];
+ }
+ prevCharIsLF = prevCharIsCR = false;
+ tokenBegin = inBuf = maxNextCharInd = 0;
+ bufpos = -1;
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.Reader dstream, int startline,
+ int startcolumn) {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.Reader dstream) {
+ ReInit(dstream, 1, 1, 4096);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException {
+ this(encoding == null ?
+ new java.io.InputStreamReader(dstream) :
+ new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize) {
+ this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException {
+ this(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream, int startline,
+ int startcolumn) {
+ this(dstream, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException {
+ this(dstream, encoding, 1, 1, 4096);
+ }
+
+ /**
+ * Constructor.
+ */
+ public SimpleCharStream(java.io.InputStream dstream) {
+ this(dstream, 1, 1, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException {
+ ReInit(encoding == null ?
+ new java.io.InputStreamReader(dstream) :
+ new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn, int buffersize) {
+ ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException {
+ ReInit(dstream, encoding, 1, 1, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream) {
+ ReInit(dstream, 1, 1, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream, String encoding, int startline,
+ int startcolumn) throws java.io.UnsupportedEncodingException {
+ ReInit(dstream, encoding, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Reinitialise.
+ */
+ public void ReInit(java.io.InputStream dstream, int startline,
+ int startcolumn) {
+ ReInit(dstream, startline, startcolumn, 4096);
+ }
+
+ /**
+ * Get token literal value.
+ */
+ public String GetImage() {
+ if (bufpos >= tokenBegin)
+ return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+ else
+ return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+ new String(buffer, 0, bufpos + 1);
+ }
+
+ /**
+ * Get the suffix.
+ */
+ public char[] GetSuffix(int len) {
+ char[] ret = new char[len];
+
+ if ((bufpos + 1) >= len)
+ System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+ else {
+ System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+ len - bufpos - 1);
+ System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+ }
+
+ return ret;
+ }
+
+ /**
+ * Reset buffer when finished.
+ */
+ public void Done() {
+ buffer = null;
+ bufline = null;
+ bufcolumn = null;
+ }
+
+ /**
+ * Method to adjust line and column numbers for the start of a token.
+ */
+ public void adjustBeginLineColumn(int newLine, int newCol) {
+ int start = tokenBegin;
+ int len;
+
+ if (bufpos >= tokenBegin) {
+ len = bufpos - tokenBegin + inBuf + 1;
+ } else {
+ len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+ }
+
+ int i = 0, j = 0, k = 0;
+ int nextColDiff = 0, columnDiff = 0;
+
+ while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) {
+ bufline[j] = newLine;
+ nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+ bufcolumn[j] = newCol + columnDiff;
+ columnDiff = nextColDiff;
+ i++;
+ }
+
+ if (i < len) {
+ bufline[j] = newLine++;
+ bufcolumn[j] = newCol + columnDiff;
+
+ while (i++ < len) {
+ if (bufline[j = start % bufsize] != bufline[++start % bufsize])
+ bufline[j] = newLine++;
+ else
+ bufline[j] = newLine;
+ }
+ }
+
+ line = bufline[j];
+ column = bufcolumn[j];
+ }
+
+}
+/* JavaCC - OriginalChecksum=af79bfe4b18b4b4ea9720ffeb7e52fc5 (do not edit this line) */
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/Token.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/Token.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/Token.java
new file mode 100644
index 0000000..8e6a48a
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/Token.java
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 5.0 */
+/* JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COL=null,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * Describes the input token stream.
+ */
+
+public class Token implements java.io.Serializable {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the <i>serialized</i> form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * An integer that describes the kind of this token. This numbering
+ * system is determined by JavaCCParser, and a table of these numbers is
+ * stored in the file ...Constants.java.
+ */
+ public int kind;
+
+ /**
+ * The line number of the first character of this Token.
+ */
+ public int beginLine;
+ /**
+ * The column number of the first character of this Token.
+ */
+ public int beginColumn;
+ /**
+ * The line number of the last character of this Token.
+ */
+ public int endLine;
+ /**
+ * The column number of the last character of this Token.
+ */
+ public int endColumn;
+
+ /**
+ * The string image of the token.
+ */
+ public String image;
+
+ /**
+ * A reference to the next regular (non-special) token from the input
+ * stream. If this is the last token from the input stream, or if the
+ * token manager has not read tokens beyond this one, this field is
+ * set to null. This is true only if this token is also a regular
+ * token. Otherwise, see below for a description of the contents of
+ * this field.
+ */
+ public Token next;
+
+ /**
+ * This field is used to access special tokens that occur prior to this
+ * token, but after the immediately preceding regular (non-special) token.
+ * If there are no such special tokens, this field is set to null.
+ * When there are more than one such special token, this field refers
+ * to the last of these special tokens, which in turn refers to the next
+ * previous special token through its specialToken field, and so on
+ * until the first special token (whose specialToken field is null).
+ * The next fields of special tokens refer to other special tokens that
+ * immediately follow it (without an intervening regular token). If there
+ * is no such token, this field is null.
+ */
+ public Token specialToken;
+
+ /**
+ * An optional attribute value of the Token.
+ * Tokens which are not used as syntactic sugar will often contain
+ * meaningful values that will be used later on by the compiler or
+ * interpreter. This attribute value is often different from the image.
+ * Any subclass of Token that actually wants to return a non-null value can
+ * override this method as appropriate.
+ */
+ public Object getValue() {
+ return null;
+ }
+
+ /**
+ * No-argument constructor
+ */
+ public Token() {
+ }
+
+ /**
+ * Constructs a new token for the specified Image.
+ */
+ public Token(int kind) {
+ this(kind, null);
+ }
+
+ /**
+ * Constructs a new token for the specified Image and Kind.
+ */
+ public Token(int kind, String image) {
+ this.kind = kind;
+ this.image = image;
+ }
+
+ /**
+ * Returns the image.
+ */
+ public String toString() {
+ return image;
+ }
+
+ /**
+ * Returns a new Token object, by default. However, if you want, you
+ * can create and return subclass objects based on the value of ofKind.
+ * Simply add the cases to the switch for all those special cases.
+ * For example, if you have a subclass of Token called IDToken that
+ * you want to create if ofKind is ID, simply add something like :
+ * <p/>
+ * case MyParserConstants.ID : return new IDToken(ofKind, image);
+ * <p/>
+ * to the following switch statement. Then you can cast matchedToken
+ * variable to the appropriate type and use sit in your lexical actions.
+ */
+ public static Token newToken(int ofKind, String image) {
+ switch (ofKind) {
+ default:
+ return new Token(ofKind, image);
+ }
+ }
+
+ public static Token newToken(int ofKind) {
+ return newToken(ofKind, null);
+ }
+
+}
+/* JavaCC - OriginalChecksum=6b0af88eb45a551d929d3cdd9582f827 (do not edit this line) */
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/parser/TokenMgrError.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/parser/TokenMgrError.java b/filter/src/main/java/org/apache/rocketmq/filter/parser/TokenMgrError.java
new file mode 100644
index 0000000..75d83e5
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/parser/TokenMgrError.java
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 5.0 */
+/* JavaCCOptions: */
+package org.apache.rocketmq.filter.parser;
+
+/**
+ * Token Manager Error.
+ */
+public class TokenMgrError extends Error {
+
+ /**
+ * The version identifier for this Serializable class.
+ * Increment only if the <i>serialized</i> form of the
+ * class changes.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /*
+ * Ordinals for various reasons why an Error of this type can be thrown.
+ */
+
+ /**
+ * Lexical error occurred.
+ */
+ static final int LEXICAL_ERROR = 0;
+
+ /**
+ * An attempt was made to create a second instance of a static token manager.
+ */
+ static final int STATIC_LEXER_ERROR = 1;
+
+ /**
+ * Tried to change to an invalid lexical state.
+ */
+ static final int INVALID_LEXICAL_STATE = 2;
+
+ /**
+ * Detected (and bailed out of) an infinite loop in the token manager.
+ */
+ static final int LOOP_DETECTED = 3;
+
+ /**
+ * Indicates the reason why the exception is thrown. It will have
+ * one of the above 4 values.
+ */
+ int errorCode;
+
+ /**
+ * Replaces unprintable characters by their escaped (or unicode escaped)
+ * equivalents in the given string
+ */
+ protected static final String addEscapes(String str) {
+ StringBuffer retval = new StringBuffer();
+ char ch;
+ for (int i = 0; i < str.length(); i++) {
+ switch (str.charAt(i)) {
+ case 0:
+ continue;
+ case '\b':
+ retval.append("\\b");
+ continue;
+ case '\t':
+ retval.append("\\t");
+ continue;
+ case '\n':
+ retval.append("\\n");
+ continue;
+ case '\f':
+ retval.append("\\f");
+ continue;
+ case '\r':
+ retval.append("\\r");
+ continue;
+ case '\"':
+ retval.append("\\\"");
+ continue;
+ case '\'':
+ retval.append("\\\'");
+ continue;
+ case '\\':
+ retval.append("\\\\");
+ continue;
+ default:
+ if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+ String s = "0000" + Integer.toString(ch, 16);
+ retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+ } else {
+ retval.append(ch);
+ }
+ continue;
+ }
+ }
+ return retval.toString();
+ }
+
+ /**
+ * Returns a detailed message for the Error when it is thrown by the
+ * token manager to indicate a lexical error.
+ * Parameters :
+ * eofSeen : indicates if EOF caused the lexical error
+ * curLexState : lexical state in which this error occurred
+ * errorLine : line number when the error occurred
+ * errorColumn : column number when the error occurred
+ * errorAfter : prefix that was seen before this error occurred
+ * curchar : the offending character
+ * Note: You can customize the lexical error message by modifying this method.
+ */
+ protected static String LexicalError(boolean eofSeen, int lexState, int errorLine, int errorColumn,
+ String errorAfter, char curChar) {
+ return "Lexical error at line " +
+ errorLine + ", column " +
+ errorColumn + ". Encountered: " +
+ (eofSeen ?
+ "<EOF> " :
+ ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int) curChar + "), ") +
+ "after : \"" + addEscapes(errorAfter) + "\"";
+ }
+
+ /**
+ * You can also modify the body of this method to customize your error messages.
+ * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+ * of end-users concern, so you can return something like :
+ * <p/>
+ * "Internal Error : Please file a bug report .... "
+ * <p/>
+ * from this method for such cases in the release version of your parser.
+ */
+ public String getMessage() {
+ return super.getMessage();
+ }
+
+ /*
+ * Constructors of various flavors follow.
+ */
+
+ /**
+ * No arg constructor.
+ */
+ public TokenMgrError() {
+ }
+
+ /**
+ * Constructor with message and reason.
+ */
+ public TokenMgrError(String message, int reason) {
+ super(message);
+ errorCode = reason;
+ }
+
+ /**
+ * Full Constructor.
+ */
+ public TokenMgrError(boolean eofSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar,
+ int reason) {
+ this(LexicalError(eofSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
+ }
+}
+/* JavaCC - OriginalChecksum=e960778c8dcd73e167ed5bfddd59f288 (do not edit this line) */
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/util/BitsArray.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/util/BitsArray.java b/filter/src/main/java/org/apache/rocketmq/filter/util/BitsArray.java
new file mode 100644
index 0000000..9866854
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/util/BitsArray.java
@@ -0,0 +1,260 @@
+/*
+ * 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.filter.util;
+
+/**
+ * Wrapper of bytes array, in order to operate single bit easily.
+ */
+public class BitsArray implements Cloneable {
+
+ private byte[] bytes;
+ private int bitLength;
+
+ public static BitsArray create(int bitLength) {
+ return new BitsArray(bitLength);
+ }
+
+ public static BitsArray create(byte[] bytes, int bitLength) {
+ return new BitsArray(bytes, bitLength);
+ }
+
+ public static BitsArray create(byte[] bytes) {
+ return new BitsArray(bytes);
+ }
+
+ private BitsArray(int bitLength) {
+ this.bitLength = bitLength;
+ // init bytes
+ int temp = bitLength / Byte.SIZE;
+ if (bitLength % Byte.SIZE > 0) {
+ temp++;
+ }
+ bytes = new byte[temp];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) 0x00;
+ }
+ }
+
+ private BitsArray(byte[] bytes, int bitLength) {
+ if (bytes == null || bytes.length < 1) {
+ throw new IllegalArgumentException("Bytes is empty!");
+ }
+
+ if (bitLength < 1) {
+ throw new IllegalArgumentException("Bit is less than 1.");
+ }
+
+ if (bitLength < bytes.length * Byte.SIZE) {
+ throw new IllegalArgumentException("BitLength is less than bytes.length() * " + Byte.SIZE);
+ }
+
+ this.bytes = new byte[bytes.length];
+ System.arraycopy(bytes, 0, this.bytes, 0, this.bytes.length);
+ this.bitLength = bitLength;
+ }
+
+ private BitsArray(byte[] bytes) {
+ if (bytes == null || bytes.length < 1) {
+ throw new IllegalArgumentException("Bytes is empty!");
+ }
+
+ this.bitLength = bytes.length * Byte.SIZE;
+ this.bytes = new byte[bytes.length];
+ System.arraycopy(bytes, 0, this.bytes, 0, this.bytes.length);
+ }
+
+ public int bitLength() {
+ return this.bitLength;
+ }
+
+ public int byteLength() {
+ return this.bytes.length;
+ }
+
+ public byte[] bytes() {
+ return this.bytes;
+ }
+
+ public void xor(final BitsArray other) {
+ checkInitialized(this);
+ checkInitialized(other);
+
+ int minByteLength = Math.min(this.byteLength(), other.byteLength());
+
+ for (int i = 0; i < minByteLength; i++) {
+ this.bytes[i] = (byte) (this.bytes[i] ^ other.getByte(i));
+ }
+ }
+
+ public void xor(int bitPos, boolean set) {
+ checkBitPosition(bitPos, this);
+
+ boolean value = getBit(bitPos);
+ if (value ^ set) {
+ setBit(bitPos, true);
+ } else {
+ setBit(bitPos, false);
+ }
+ }
+
+ public void or(final BitsArray other) {
+ checkInitialized(this);
+ checkInitialized(other);
+
+ int minByteLength = Math.min(this.byteLength(), other.byteLength());
+
+ for (int i = 0; i < minByteLength; i++) {
+ this.bytes[i] = (byte) (this.bytes[i] | other.getByte(i));
+ }
+ }
+
+ public void or(int bitPos, boolean set) {
+ checkBitPosition(bitPos, this);
+
+ if (set) {
+ setBit(bitPos, true);
+ }
+ }
+
+ public void and(final BitsArray other) {
+ checkInitialized(this);
+ checkInitialized(other);
+
+ int minByteLength = Math.min(this.byteLength(), other.byteLength());
+
+ for (int i = 0; i < minByteLength; i++) {
+ this.bytes[i] = (byte) (this.bytes[i] & other.getByte(i));
+ }
+ }
+
+ public void and(int bitPos, boolean set) {
+ checkBitPosition(bitPos, this);
+
+ if (!set) {
+ setBit(bitPos, false);
+ }
+ }
+
+ public void not(int bitPos) {
+ checkBitPosition(bitPos, this);
+
+ setBit(bitPos, !getBit(bitPos));
+ }
+
+ public void setBit(int bitPos, boolean set) {
+ checkBitPosition(bitPos, this);
+ int sub = subscript(bitPos);
+ int pos = position(bitPos);
+ if (set) {
+ this.bytes[sub] = (byte) (this.bytes[sub] | pos);
+ } else {
+ this.bytes[sub] = (byte) (this.bytes[sub] & ~pos);
+ }
+ }
+
+ public void setByte(int bytePos, byte set) {
+ checkBytePosition(bytePos, this);
+
+ this.bytes[bytePos] = set;
+ }
+
+ public boolean getBit(int bitPos) {
+ checkBitPosition(bitPos, this);
+
+ return (this.bytes[subscript(bitPos)] & position(bitPos)) != 0;
+ }
+
+ public byte getByte(int bytePos) {
+ checkBytePosition(bytePos, this);
+
+ return this.bytes[bytePos];
+ }
+
+ protected int subscript(int bitPos) {
+ return bitPos / Byte.SIZE;
+ }
+
+ protected int position(int bitPos) {
+ return 1 << bitPos % Byte.SIZE;
+ }
+
+ protected void checkBytePosition(int bytePos, BitsArray bitsArray) {
+ checkInitialized(bitsArray);
+ if (bytePos > bitsArray.byteLength()) {
+ throw new IllegalArgumentException("BytePos is greater than " + bytes.length);
+ }
+ if (bytePos < 0) {
+ throw new IllegalArgumentException("BytePos is less than 0");
+ }
+ }
+
+ protected void checkBitPosition(int bitPos, BitsArray bitsArray) {
+ checkInitialized(bitsArray);
+ if (bitPos > bitsArray.bitLength()) {
+ throw new IllegalArgumentException("BitPos is greater than " + bitLength);
+ }
+ if (bitPos < 0) {
+ throw new IllegalArgumentException("BitPos is less than 0");
+ }
+ }
+
+ protected void checkInitialized(BitsArray bitsArray) {
+ if (bitsArray.bytes() == null) {
+ throw new RuntimeException("Not initialized!");
+ }
+ }
+
+ public BitsArray clone() {
+ byte[] clone = new byte[this.byteLength()];
+
+ System.arraycopy(this.bytes, 0, clone, 0, this.byteLength());
+
+ return create(clone, bitLength());
+ }
+
+ @Override
+ public String toString() {
+ if (this.bytes == null) {
+ return "null";
+ }
+ StringBuilder stringBuilder = new StringBuilder(this.bytes.length * Byte.SIZE);
+ for (int i = this.bytes.length - 1; i >= 0; i--) {
+
+ int j = Byte.SIZE - 1;
+ if (i == this.bytes.length - 1 && this.bitLength % Byte.SIZE > 0) {
+ // not full byte
+ j = this.bitLength % Byte.SIZE;
+ }
+
+ for (; j >= 0; j--) {
+
+ byte mask = (byte) (1 << j);
+ if ((this.bytes[i] & mask) == mask) {
+ stringBuilder.append("1");
+ } else {
+ stringBuilder.append("0");
+ }
+ }
+ if (i % 8 == 0) {
+ stringBuilder.append("\n");
+ }
+ }
+
+ return stringBuilder.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilter.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilter.java b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilter.java
new file mode 100644
index 0000000..f610906
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilter.java
@@ -0,0 +1,338 @@
+/*
+ * 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.filter.util;
+
+import com.google.common.hash.Hashing;
+
+import java.nio.charset.Charset;
+
+/**
+ * Simple implement of bloom filter.
+ */
+public class BloomFilter {
+
+ public static final Charset UTF_8 = Charset.forName("UTF-8");
+
+ // as error rate, 10/100 = 0.1
+ private int f = 10;
+ private int n = 128;
+
+ // hash function num, by calculation.
+ private int k;
+ // bit count, by calculation.
+ private int m;
+
+ /**
+ * Create bloom filter by error rate and mapping num.
+ *
+ * @param f error rate
+ * @param n num will mapping to bit
+ * @return
+ */
+ public static BloomFilter createByFn(int f, int n) {
+ return new BloomFilter(f, n);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param f error rate
+ * @param n num will mapping to bit
+ */
+ private BloomFilter(int f, int n) {
+ if (f < 1 || f >= 100) {
+ throw new IllegalArgumentException("f must be greater or equal than 1 and less than 100");
+ }
+ if (n < 1) {
+ throw new IllegalArgumentException("n must be greater than 0");
+ }
+
+ this.f = f;
+ this.n = n;
+
+ // set p = e^(-kn/m)
+ // f = (1 - p)^k = e^(kln(1-p))
+ // when p = 0.5, k = ln2 * (m/n), f = (1/2)^k = (0.618)^(m/n)
+ double errorRate = f / 100.0;
+ this.k = (int) Math.ceil(logMN(0.5, errorRate));
+
+ if (this.k < 1) {
+ throw new IllegalArgumentException("Hash function num is less than 1, maybe you should change the value of error rate or bit num!");
+ }
+
+ // m >= n*log2(1/f)*log2(e)
+ this.m = (int) Math.ceil(this.n * logMN(2, 1 / errorRate) * logMN(2, Math.E));
+ // m%8 = 0
+ this.m = (int) (Byte.SIZE * Math.ceil(this.m / (Byte.SIZE * 1.0)));
+ }
+
+ /**
+ * Calculate bit positions of {@code str}.
+ * <p>
+ * See "Less Hashing, Same Performance: Building a Better Bloom Filter" by Adam Kirsch and Michael
+ * Mitzenmacher.
+ * </p>
+ *
+ * @param str
+ * @return
+ */
+ public int[] calcBitPositions(String str) {
+ int[] bitPositions = new int[this.k];
+
+ long hash64 = Hashing.murmur3_128().hashString(str, UTF_8).asLong();
+
+ int hash1 = (int) hash64;
+ int hash2 = (int) (hash64 >>> 32);
+
+ for (int i = 1; i <= this.k; i++) {
+ int combinedHash = hash1 + (i * hash2);
+ // Flip all the bits if it's negative (guaranteed positive number)
+ if (combinedHash < 0) {
+ combinedHash = ~combinedHash;
+ }
+ bitPositions[i - 1] = combinedHash % this.m;
+ }
+
+ return bitPositions;
+ }
+
+ /**
+ * Calculate bit positions of {@code str} to construct {@code BloomFilterData}
+ *
+ * @param str
+ * @return
+ */
+ public BloomFilterData generate(String str) {
+ int[] bitPositions = calcBitPositions(str);
+
+ return new BloomFilterData(bitPositions, this.m);
+ }
+
+ /**
+ * Calculate bit positions of {@code str}, then set the related {@code bits} positions to 1.
+ *
+ * @param str
+ * @param bits
+ */
+ public void hashTo(String str, BitsArray bits) {
+ hashTo(calcBitPositions(str), bits);
+ }
+
+ /**
+ * Set the related {@code bits} positions to 1.
+ *
+ * @param bitPositions
+ * @param bits
+ */
+ public void hashTo(int[] bitPositions, BitsArray bits) {
+ check(bits);
+
+ for (int i : bitPositions) {
+ bits.setBit(i, true);
+ }
+ }
+
+ /**
+ * Extra check:
+ * <li>1. check {@code filterData} belong to this bloom filter.</li>
+ * <p>
+ * Then set the related {@code bits} positions to 1.
+ * </p>
+ *
+ * @param filterData
+ * @param bits
+ */
+ public void hashTo(BloomFilterData filterData, BitsArray bits) {
+ if (!isValid(filterData)) {
+ throw new IllegalArgumentException(
+ String.format("Bloom filter data may not belong to this filter! %s, %s",
+ filterData, this.toString())
+ );
+ }
+ hashTo(filterData.getBitPos(), bits);
+ }
+
+ /**
+ * Calculate bit positions of {@code str}, then check all the related {@code bits} positions is 1.
+ *
+ * @param str
+ * @param bits
+ * @return true: all the related {@code bits} positions is 1
+ */
+ public boolean isHit(String str, BitsArray bits) {
+ return isHit(calcBitPositions(str), bits);
+ }
+
+ /**
+ * Check all the related {@code bits} positions is 1.
+ *
+ * @param bitPositions
+ * @param bits
+ * @return true: all the related {@code bits} positions is 1
+ */
+ public boolean isHit(int[] bitPositions, BitsArray bits) {
+ check(bits);
+ boolean ret = bits.getBit(bitPositions[0]);
+ for (int i = 1; i < bitPositions.length; i++) {
+ ret &= bits.getBit(bitPositions[i]);
+ }
+ return ret;
+ }
+
+ /**
+ * Check all the related {@code bits} positions is 1.
+ *
+ * @param filterData
+ * @param bits
+ * @return true: all the related {@code bits} positions is 1
+ */
+ public boolean isHit(BloomFilterData filterData, BitsArray bits) {
+ if (!isValid(filterData)) {
+ throw new IllegalArgumentException(
+ String.format("Bloom filter data may not belong to this filter! %s, %s",
+ filterData, this.toString())
+ );
+ }
+ return isHit(filterData.getBitPos(), bits);
+ }
+
+ /**
+ * Check whether one of {@code bitPositions} has been occupied.
+ *
+ * @param bitPositions
+ * @param bits
+ * @return true: if all positions have been occupied.
+ */
+ public boolean checkFalseHit(int[] bitPositions, BitsArray bits) {
+ for (int j = 0; j < bitPositions.length; j++) {
+ int pos = bitPositions[j];
+
+ // check position of bits has been set.
+ // that mean no one occupy the position.
+ if (!bits.getBit(pos)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ protected void check(BitsArray bits) {
+ if (bits.bitLength() != this.m) {
+ throw new IllegalArgumentException(
+ String.format("Length(%d) of bits in BitsArray is not equal to %d!", bits.bitLength(), this.m)
+ );
+ }
+ }
+
+ /**
+ * Check {@code BloomFilterData} is valid, and belong to this bloom filter.
+ * <li>1. not null</li>
+ * <li>2. {@link org.apache.rocketmq.filter.util.BloomFilterData#getBitNum} must be equal to {@code m} </li>
+ * <li>3. {@link org.apache.rocketmq.filter.util.BloomFilterData#getBitPos} is not null</li>
+ * <li>4. {@link org.apache.rocketmq.filter.util.BloomFilterData#getBitPos}'s length is equal to {@code k}</li>
+ *
+ * @param filterData
+ * @return
+ */
+ public boolean isValid(BloomFilterData filterData) {
+ if (filterData == null
+ || filterData.getBitNum() != this.m
+ || filterData.getBitPos() == null
+ || filterData.getBitPos().length != this.k) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * error rate.
+ *
+ * @return
+ */
+ public int getF() {
+ return f;
+ }
+
+ /**
+ * expect mapping num.
+ *
+ * @return
+ */
+ public int getN() {
+ return n;
+ }
+
+ /**
+ * hash function num.
+ *
+ * @return
+ */
+ public int getK() {
+ return k;
+ }
+
+ /**
+ * total bit num.
+ *
+ * @return
+ */
+ public int getM() {
+ return m;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (!(o instanceof BloomFilter))
+ return false;
+
+ BloomFilter that = (BloomFilter) o;
+
+ if (f != that.f)
+ return false;
+ if (k != that.k)
+ return false;
+ if (m != that.m)
+ return false;
+ if (n != that.n)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = f;
+ result = 31 * result + n;
+ result = 31 * result + k;
+ result = 31 * result + m;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("f: %d, n: %d, k: %d, m: %d", f, n, k, m);
+ }
+
+ protected double logMN(double m, double n) {
+ return Math.log(n) / Math.log(m);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilterData.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilterData.java b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilterData.java
new file mode 100644
index 0000000..de02d92
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/util/BloomFilterData.java
@@ -0,0 +1,83 @@
+/*
+ * 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.filter.util;
+
+import java.util.Arrays;
+
+/**
+ * Data generated by bloom filter, include:
+ * <li>1. Bit positions allocated to requester;</li>
+ * <li>2. Total bit num when allocating;</li>
+ */
+public class BloomFilterData {
+
+ private int[] bitPos;
+ private int bitNum;
+
+ public BloomFilterData() {
+ }
+
+ public BloomFilterData(int[] bitPos, int bitNum) {
+ this.bitPos = bitPos;
+ this.bitNum = bitNum;
+ }
+
+ public int[] getBitPos() {
+ return bitPos;
+ }
+
+ public int getBitNum() {
+ return bitNum;
+ }
+
+ public void setBitPos(final int[] bitPos) {
+ this.bitPos = bitPos;
+ }
+
+ public void setBitNum(final int bitNum) {
+ this.bitNum = bitNum;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (!(o instanceof BloomFilterData)) return false;
+
+ final BloomFilterData that = (BloomFilterData) o;
+
+ if (bitNum != that.bitNum) return false;
+ if (!Arrays.equals(bitPos, that.bitPos)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = bitPos != null ? Arrays.hashCode(bitPos) : 0;
+ result = 31 * result + bitNum;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "BloomFilterData{" +
+ "bitPos=" + Arrays.toString(bitPos) +
+ ", bitNum=" + bitNum +
+ '}';
+ }
+}
[25/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-39] avoid
duplicated codes closes apache/incubator-rocketmq#34
Posted by do...@apache.org.
[ROCKETMQ-39] avoid duplicated codes closes apache/incubator-rocketmq#34
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/c0fe02e1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/c0fe02e1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/c0fe02e1
Branch: refs/heads/release-4.1.0-incubating
Commit: c0fe02e1c6a0afd516c1323c8b5808fd7ddad72e
Parents: 4d12d11
Author: wu-sheng <wu...@foxmail.com>
Authored: Thu May 25 19:43:21 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Thu May 25 19:43:21 2017 +0800
----------------------------------------------------------------------
.../rocketmq/filtersrv/FiltersrvStartup.java | 24 ++-----
.../apache/rocketmq/namesrv/NamesrvStartup.java | 31 +++------
.../rocketmq/srvutil/ShutdownHookThread.java | 69 ++++++++++++++++++++
3 files changed, 85 insertions(+), 39 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c0fe02e1/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/FiltersrvStartup.java
----------------------------------------------------------------------
diff --git a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/FiltersrvStartup.java b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/FiltersrvStartup.java
index 5dd15dd..41169c9 100644
--- a/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/FiltersrvStartup.java
+++ b/filtersrv/src/main/java/org/apache/rocketmq/filtersrv/FiltersrvStartup.java
@@ -22,7 +22,7 @@ import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Callable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -34,6 +34,7 @@ import org.apache.rocketmq.remoting.netty.NettyServerConfig;
import org.apache.rocketmq.remoting.netty.NettySystemConfig;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.srvutil.ServerUtil;
+import org.apache.rocketmq.srvutil.ShutdownHookThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -135,24 +136,13 @@ public class FiltersrvStartup {
System.exit(-3);
}
- Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
- private volatile boolean hasShutdown = false;
- private AtomicInteger shutdownTimes = new AtomicInteger(0);
-
+ Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() {
@Override
- public void run() {
- synchronized (this) {
- log.info("shutdown hook was invoked, " + this.shutdownTimes.incrementAndGet());
- if (!this.hasShutdown) {
- this.hasShutdown = true;
- long begineTime = System.currentTimeMillis();
- controller.shutdown();
- long consumingTimeTotal = System.currentTimeMillis() - begineTime;
- log.info("shutdown hook over, consuming time total(ms): " + consumingTimeTotal);
- }
- }
+ public Void call() throws Exception {
+ controller.shutdown();
+ return null;
}
- }, "ShutdownHook"));
+ }));
return controller;
} catch (Throwable e) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c0fe02e1/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
----------------------------------------------------------------------
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
index 4fa97ad..f49d2b3 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/NamesrvStartup.java
@@ -22,7 +22,7 @@ import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.Callable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -35,6 +35,7 @@ import org.apache.rocketmq.remoting.netty.NettyServerConfig;
import org.apache.rocketmq.remoting.netty.NettySystemConfig;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.srvutil.ServerUtil;
+import org.apache.rocketmq.srvutil.ShutdownHookThread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,9 +62,7 @@ public class NamesrvStartup {
//PackageConflictDetect.detectFastjson();
Options options = ServerUtil.buildCommandlineOptions(new Options());
- commandLine =
- ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options),
- new PosixParser());
+ commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser());
if (null == commandLine) {
System.exit(-1);
return null;
@@ -97,8 +96,7 @@ public class NamesrvStartup {
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
if (null == namesrvConfig.getRocketmqHome()) {
- System.out.printf("Please set the " + MixAll.ROCKETMQ_HOME_ENV
- + " variable in your environment to match the location of the RocketMQ installation%n");
+ System.out.printf("Please set the " + MixAll.ROCKETMQ_HOME_ENV + " variable in your environment to match the location of the RocketMQ installation%n");
System.exit(-2);
}
@@ -123,24 +121,13 @@ public class NamesrvStartup {
System.exit(-3);
}
- Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
- private volatile boolean hasShutdown = false;
- private AtomicInteger shutdownTimes = new AtomicInteger(0);
-
+ Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() {
@Override
- public void run() {
- synchronized (this) {
- log.info("shutdown hook was invoked, " + this.shutdownTimes.incrementAndGet());
- if (!this.hasShutdown) {
- this.hasShutdown = true;
- long begineTime = System.currentTimeMillis();
- controller.shutdown();
- long consumingTimeTotal = System.currentTimeMillis() - begineTime;
- log.info("shutdown hook over, consuming time total(ms): " + consumingTimeTotal);
- }
- }
+ public Void call() throws Exception {
+ controller.shutdown();
+ return null;
}
- }, "ShutdownHook"));
+ }));
controller.start();
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c0fe02e1/srvutil/src/main/java/org/apache/rocketmq/srvutil/ShutdownHookThread.java
----------------------------------------------------------------------
diff --git a/srvutil/src/main/java/org/apache/rocketmq/srvutil/ShutdownHookThread.java b/srvutil/src/main/java/org/apache/rocketmq/srvutil/ShutdownHookThread.java
new file mode 100644
index 0000000..11f9b2c
--- /dev/null
+++ b/srvutil/src/main/java/org/apache/rocketmq/srvutil/ShutdownHookThread.java
@@ -0,0 +1,69 @@
+/*
+ * 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.srvutil;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.slf4j.Logger;
+
+/**
+ * {@link ShutdownHookThread} is the standard hook for filtersrv and namesrv modules.
+ * Through {@link Callable} interface, this hook can customization operations in anywhere.
+ */
+public class ShutdownHookThread extends Thread {
+ private volatile boolean hasShutdown = false;
+ private AtomicInteger shutdownTimes = new AtomicInteger(0);
+ private final Logger log;
+ private final Callable callback;
+
+ /**
+ * Create the standard hook thread, with a call back, by using {@link Callable} interface.
+ *
+ * @param log The log instance is used in hook thread.
+ * @param callback The call back function.
+ */
+ public ShutdownHookThread(Logger log, Callable callback) {
+ super("ShutdownHook");
+ this.log = log;
+ this.callback = callback;
+ }
+
+ /**
+ * Thread run method.
+ * Invoke when the jvm shutdown.
+ * 1. count the invocation times.
+ * 2. execute the {@link ShutdownHookThread#callback}, and time it.
+ */
+ @Override
+ public void run() {
+ synchronized (this) {
+ log.info("shutdown hook was invoked, " + this.shutdownTimes.incrementAndGet() + " times.");
+ if (!this.hasShutdown) {
+ this.hasShutdown = true;
+ long beginTime = System.currentTimeMillis();
+ try {
+ this.callback.call();
+ } catch (Exception e) {
+ log.error("shutdown hook callback invoked failure.", e);
+ }
+ long consumingTimeTotal = System.currentTimeMillis() - beginTime;
+ log.info("shutdown hook done, consuming time total(ms): " + consumingTimeTotal);
+ }
+ }
+ }
+}
[49/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-218] Polish
README.md, closes apache/incubator-rocketmq#113
Posted by do...@apache.org.
[ROCKETMQ-218] Polish README.md, closes apache/incubator-rocketmq#113
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/c4a3e0c1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/c4a3e0c1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/c4a3e0c1
Branch: refs/heads/release-4.1.0-incubating
Commit: c4a3e0c1325e67aec76aa94e9ade3a6ea1b682d2
Parents: f45a1bc
Author: zhoudiqiu <zh...@wustl.edu>
Authored: Thu Jun 8 11:29:33 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu Jun 8 11:29:33 2017 +0800
----------------------------------------------------------------------
README.md | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c4a3e0c1/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 7a9abb1..ab0a865 100644
--- a/README.md
+++ b/README.md
@@ -3,18 +3,25 @@
[![GitHub release](https://img.shields.io/badge/release-download-orange.svg)](https://github.org/apache/rocketmqreleases)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
-**[Apache RocketMQ](https://rocketmq.incubator.apache.org) is a low latency, reliable, scalable, easy to use message oriented middleware born from alibaba massive messaging business.**
+**[Apache RocketMQ](https://rocketmq.incubator.apache.org) is a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability.**
+
+It offers a variety of features:
+
+* Pub/Sub messaging model
+* Scheduled message delivery
+* Message retroactivity by time or offset
+* Log hub for streaming
+* Big data integration
+* Reliable FIFO and strict ordered messaging in the same queue
+* Efficient pull&push consumption model
+* Million-level message accumulation capacity in a single queue
+* Multiple messaging protocols like JMS and OpenMessaging
+* Flexible distributed scale-out deployment architecture
+* Lightning-fast batch message exchange system
+* Various message filter mechanics such as SQL and Tag
+* Docker images for isolated testing and cloud isolated clusters
+* Feature-rich administrative dashboard for configuration, metrics and monitoring
-It offers a variety of features as follows:
-
-* Pub/Sub and P2P messaging model
-* Reliable FIFO and strict sequential messaging in the same queue
-* Long pull queue model,also support push consumption style
-* Million message accumulation ability in single queue
-* Over a variety of messaging protocols.such as JMS,MQTT etc.
-* Distributed high available deploy architecture, meets at least once message delivery semantics
-* Docker images for isolated testing and cloud Isolated clusters
-* Feature-rich administrative dashboard for configuration,metrics and monitoring
----------
@@ -29,13 +36,12 @@ It offers a variety of features as follows:
----------
## Apache RocketMQ Community
-* [RocketMQ Community Incubator Projects](https://github.com/rocketmq)
* [RocketMQ Community Projects](https://github.com/apache/incubator-rocketmq-externals)
----------
## Contributing
-We are always very happy to have contributions, whether for trivial cleanups,big new features or other material rewards. more details see [here](CONTRIBUTING.md)
+We always welcome new contributions, whether for trivial cleanups, big new features or other material rewards. more details see [here](CONTRIBUTING.md)
----------
## License
[20/50] [abbrv] incubator-rocketmq git commit: This is to close issue
ROCKETMQ-198: Add language code for Go and PHP Thanks to StyleTang
Posted by do...@apache.org.
This is to close issue ROCKETMQ-198: Add language code for Go and PHP
Thanks to StyleTang
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/1630f277
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/1630f277
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/1630f277
Branch: refs/heads/release-4.1.0-incubating
Commit: 1630f277b9c9f8e85c9bdb09a323d39e13e797e4
Parents: 80aac13
Author: Li Zhanhui <li...@apache.org>
Authored: Tue May 16 14:34:56 2017 +0800
Committer: Li Zhanhui <li...@apache.org>
Committed: Tue May 16 14:34:56 2017 +0800
----------------------------------------------------------------------
.../java/org/apache/rocketmq/remoting/protocol/LanguageCode.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1630f277/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
index 669a383..17ce919 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/LanguageCode.java
@@ -26,7 +26,9 @@ public enum LanguageCode {
ERLANG((byte) 5),
RUBY((byte) 6),
OTHER((byte) 7),
- HTTP((byte) 8);
+ HTTP((byte) 8),
+ GO((byte) 9),
+ PHP((byte) 10);
private byte code;
[24/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-161] Update
runbroker.sh and runserver.sh to support user defined jvm mem flag closes
apache/incubator-rocketmq#87
Posted by do...@apache.org.
[ROCKETMQ-161] Update runbroker.sh and runserver.sh to support user defined jvm mem flag closes apache/incubator-rocketmq#87
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/4d12d112
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/4d12d112
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/4d12d112
Branch: refs/heads/release-4.1.0-incubating
Commit: 4d12d11249950468d2830cae31c0f8909ad14395
Parents: 1d966b5
Author: dongeforever <zh...@yeah.net>
Authored: Thu May 25 14:26:37 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Thu May 25 14:26:37 2017 +0800
----------------------------------------------------------------------
distribution/bin/runbroker.sh | 1 +
distribution/bin/runserver.sh | 1 +
2 files changed, 2 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/4d12d112/distribution/bin/runbroker.sh
----------------------------------------------------------------------
diff --git a/distribution/bin/runbroker.sh b/distribution/bin/runbroker.sh
index 3405d39..b0c490e 100644
--- a/distribution/bin/runbroker.sh
+++ b/distribution/bin/runbroker.sh
@@ -46,6 +46,7 @@ JAVA_OPT="${JAVA_OPT} -XX:MaxDirectMemorySize=15g"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages -XX:-UseBiasedLocking"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
numactl --interleave=all pwd > /dev/null 2>&1
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/4d12d112/distribution/bin/runserver.sh
----------------------------------------------------------------------
diff --git a/distribution/bin/runserver.sh b/distribution/bin/runserver.sh
index e85991c..7c41b0c 100644
--- a/distribution/bin/runserver.sh
+++ b/distribution/bin/runserver.sh
@@ -43,6 +43,7 @@ JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${BASE_DIR}/lib"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
+JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
$JAVA ${JAVA_OPT} $@
[50/50] [abbrv] incubator-rocketmq git commit: Add license for
OpenMessaging
Posted by do...@apache.org.
Add license for OpenMessaging
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/10933cc0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/10933cc0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/10933cc0
Branch: refs/heads/release-4.1.0-incubating
Commit: 10933cc0a9be43c418b5b9c0b78cd9e07674b099
Parents: c4a3e0c
Author: dongeforever <do...@apache.org>
Authored: Thu Jun 8 15:47:40 2017 +0800
Committer: dongeforever <do...@apache.org>
Committed: Thu Jun 8 15:47:40 2017 +0800
----------------------------------------------------------------------
distribution/LICENSE-BIN | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/10933cc0/distribution/LICENSE-BIN
----------------------------------------------------------------------
diff --git a/distribution/LICENSE-BIN b/distribution/LICENSE-BIN
index 32d0208..3726172 100644
--- a/distribution/LICENSE-BIN
+++ b/distribution/LICENSE-BIN
@@ -314,4 +314,21 @@ The source code of guava can be found at https://github.com/google/guava.
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.
+------
+This product has a bundle OpenMessaging, which is available under the ASL2 License.
+The source code of OpenMessaging can be found at https://github.com/openmessaging/openmessaging.
+
+ Copyright (C) 2017 The OpenMessaging authors.
+
+ Licensed 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.
[45/50] [abbrv] incubator-rocketmq git commit: Include guava
copyright announcement
Posted by do...@apache.org.
Include guava copyright announcement
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/2c28baad
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/2c28baad
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/2c28baad
Branch: refs/heads/release-4.1.0-incubating
Commit: 2c28baad8f6cb5f8273e8ec03ac45e453dd1f25a
Parents: 3d1ec32
Author: dongeforever <zh...@yeah.net>
Authored: Tue Jun 6 15:13:43 2017 +0800
Committer: dongeforever <do...@apache.org>
Committed: Tue Jun 6 16:28:15 2017 +0800
----------------------------------------------------------------------
distribution/LICENSE-BIN | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/2c28baad/distribution/LICENSE-BIN
----------------------------------------------------------------------
diff --git a/distribution/LICENSE-BIN b/distribution/LICENSE-BIN
index 9796b3c..32d0208 100644
--- a/distribution/LICENSE-BIN
+++ b/distribution/LICENSE-BIN
@@ -296,4 +296,22 @@ The source code of jna can be found at https://github.com/java-native-access/jna
A copy is also included in the downloadable source code package
containing JNA, in file "AL2.0", under the same directory
- as this file.
\ No newline at end of file
+ as this file.
+------
+This product has a bundle guava, which is available under the ASL2 License.
+The source code of guava can be found at https://github.com/google/guava.
+
+ Copyright (C) 2007 The Guava authors
+
+ Licensed 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.
+
[47/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-220] Add IT
test for Filter By SQL 92, closes apache/incubator-rocketmq#114
Posted by do...@apache.org.
[ROCKETMQ-220] Add IT test for Filter By SQL 92, closes
apache/incubator-rocketmq#114
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/703ac00b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/703ac00b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/703ac00b
Branch: refs/heads/release-4.1.0-incubating
Commit: 703ac00bd271583c0290daad14e45f97f9991f49
Parents: 7374914
Author: dongeforever <zh...@yeah.net>
Authored: Thu Jun 8 11:12:26 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu Jun 8 11:20:15 2017 +0800
----------------------------------------------------------------------
.../rocketmq/broker/BrokerController.java | 2 +-
.../rocketmq/example/filter/SqlConsumer.java | 1 -
.../test/client/rmq/RMQSqlConsumer.java | 42 +++++++++++
.../rocketmq/test/factory/ConsumerFactory.java | 12 ++++
.../test/listener/AbstractListener.java | 22 ++++++
.../rocketmq/test/base/IntegrationTestBase.java | 1 +
.../client/consumer/filter/SqlFilterIT.java | 74 ++++++++++++++++++++
7 files changed, 152 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index bacd25c..1416ebf 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -421,7 +421,7 @@ public class BrokerController {
this.fastRemotingServer.registerProcessor(RequestCode.HEART_BEAT, clientProcessor, this.clientManageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.UNREGISTER_CLIENT, clientProcessor, this.clientManageExecutor);
- this.remotingServer.registerProcessor(RequestCode.CHECK_CLIENT_CONFIG, clientProcessor, this.clientManageExecutor);
+ this.fastRemotingServer.registerProcessor(RequestCode.CHECK_CLIENT_CONFIG, clientProcessor, this.clientManageExecutor);
/**
* ConsumerManageProcessor
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
index 9a3b813..52c2474 100644
--- a/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
@@ -31,7 +31,6 @@ public class SqlConsumer {
public static void main(String[] args) {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
-
try {
consumer.subscribe("TopicTest",
MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))" +
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQSqlConsumer.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQSqlConsumer.java b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQSqlConsumer.java
new file mode 100644
index 0000000..cb0210f
--- /dev/null
+++ b/test/src/main/java/org/apache/rocketmq/test/client/rmq/RMQSqlConsumer.java
@@ -0,0 +1,42 @@
+/*
+ * 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.consumer.MessageSelector;
+import org.apache.rocketmq.test.listener.AbstractListener;
+
+public class RMQSqlConsumer extends RMQNormalConsumer {
+ private static Logger logger = Logger.getLogger(RMQSqlConsumer.class);
+ private MessageSelector selector;
+ public RMQSqlConsumer(String nsAddr, String topic, MessageSelector selector,
+ String consumerGroup, AbstractListener listener) {
+ super(nsAddr, topic, "*", consumerGroup, listener);
+ this.selector = selector;
+ }
+
+ @Override
+ public void create() {
+ super.create();
+ try {
+ consumer.subscribe(topic, selector);
+ } catch (Exception e) {
+ logger.error("Subscribe Sql Errored", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java b/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
index b5b3fdd..7dd747f 100644
--- a/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
+++ b/test/src/main/java/org/apache/rocketmq/test/factory/ConsumerFactory.java
@@ -17,8 +17,10 @@
package org.apache.rocketmq.test.factory;
+import org.apache.rocketmq.client.consumer.MessageSelector;
import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
import org.apache.rocketmq.test.client.rmq.RMQNormalConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQSqlConsumer;
import org.apache.rocketmq.test.listener.AbstractListener;
public class ConsumerFactory {
@@ -42,4 +44,14 @@ public class ConsumerFactory {
consumer.start();
return consumer;
}
+
+ public static RMQSqlConsumer getRMQSqlConsumer(String nsAddr, String consumerGroup,
+ String topic, MessageSelector selector,
+ AbstractListener listner) {
+ RMQSqlConsumer consumer = new RMQSqlConsumer(nsAddr, topic, selector,
+ consumerGroup, listner);
+ consumer.create();
+ consumer.start();
+ return consumer;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java b/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
index 974434a..14da397 100644
--- a/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
+++ b/test/src/main/java/org/apache/rocketmq/test/listener/AbstractListener.java
@@ -95,6 +95,28 @@ public class AbstractListener extends MQCollector implements MessageListener {
return sendMsgs;
}
+ public long waitForMessageConsume(int size,
+ int timeoutMills) {
+
+ long curTime = System.currentTimeMillis();
+ while (true) {
+ if (msgBodys.getDataSize() >= size) {
+ break;
+ }
+ if (System.currentTimeMillis() - curTime >= timeoutMills) {
+ logger.error(String.format("timeout but [%s] not recv all send messages!",
+ listnerName));
+ break;
+ } else {
+ logger.info(String.format("[%s] still [%s] msg not recv!", listnerName,
+ size - msgBodys.getDataSize()));
+ TestUtil.waitForMonment(500);
+ }
+ }
+
+ return msgBodys.getDataSize();
+ }
+
public void waitForMessageConsume(Map<Object, Object> sendMsgIndex, int timeoutMills) {
Collection<Object> notRecvMsgs = waitForMessageConsume(sendMsgIndex.keySet(), timeoutMills);
for (Object object : notRecvMsgs) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
index 9805eba..07af7aa 100644
--- a/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
+++ b/test/src/test/java/org/apache/rocketmq/test/base/IntegrationTestBase.java
@@ -127,6 +127,7 @@ public class IntegrationTestBase {
brokerConfig.setBrokerName(BROKER_NAME_PREFIX + BROKER_INDEX.getAndIncrement());
brokerConfig.setBrokerIP1("127.0.0.1");
brokerConfig.setNamesrvAddr(nsAddr);
+ brokerConfig.setEnablePropertyFilter(true);
storeConfig.setStorePathRootDir(baseDir);
storeConfig.setStorePathCommitLog(baseDir + SEP + "commitlog");
storeConfig.setHaListenPort(8000 + random.nextInt(1000));
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/703ac00b/test/src/test/java/org/apache/rocketmq/test/client/consumer/filter/SqlFilterIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/filter/SqlFilterIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/filter/SqlFilterIT.java
new file mode 100644
index 0000000..7eef2ab
--- /dev/null
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/filter/SqlFilterIT.java
@@ -0,0 +1,74 @@
+/*
+ * 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.consumer.filter;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.consumer.MessageSelector;
+import org.apache.rocketmq.test.base.BaseConf;
+import org.apache.rocketmq.test.client.consumer.broadcast.BaseBroadCastIT;
+import org.apache.rocketmq.test.client.consumer.broadcast.normal.NormalMsgTwoSameGroupConsumerIT;
+import org.apache.rocketmq.test.client.rmq.RMQBroadCastConsumer;
+import org.apache.rocketmq.test.client.rmq.RMQNormalProducer;
+import org.apache.rocketmq.test.client.rmq.RMQSqlConsumer;
+import org.apache.rocketmq.test.factory.ConsumerFactory;
+import org.apache.rocketmq.test.listener.rmq.concurrent.RMQNormalListner;
+import org.apache.rocketmq.test.util.VerifyUtils;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+public class SqlFilterIT extends BaseConf {
+ private static Logger logger = Logger.getLogger(SqlFilterIT.class);
+ private RMQNormalProducer producer = null;
+ private String topic = null;
+
+ @Before
+ public void setUp() {
+ topic = initTopic();
+ logger.info(String.format("use topic: %s;", topic));
+ producer = getProducer(nsAddr, topic);
+ }
+
+ @After
+ public void tearDown() {
+ super.shutDown();
+ }
+
+ @Test
+ public void testFilterConsumer() throws Exception {
+ int msgSize = 16;
+
+ String group = initConsumerGroup();
+ MessageSelector selector = MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))");
+ RMQSqlConsumer consumer = ConsumerFactory.getRMQSqlConsumer(nsAddr, group, topic, selector, new RMQNormalListner(group + "_1"));
+ Thread.sleep(3000);
+ producer.send("TagA", msgSize);
+ producer.send("TagB", msgSize);
+ producer.send("TagC", msgSize);
+ Assert.assertEquals("Not all sent succeeded", msgSize * 3, producer.getAllUndupMsgBody().size());
+ consumer.getListner().waitForMessageConsume(msgSize * 2, consumeTime);
+ assertThat(producer.getAllMsgBody())
+ .containsAllIn(VerifyUtils.getFilterdMessage(producer.getAllMsgBody(),
+ consumer.getListner().getAllMsgBody()));
+
+ assertThat(consumer.getListner().getAllMsgBody().size()).isEqualTo(msgSize * 2);
+ }
+}
[26/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-178] Fix -p
-m options closes apache/incubator-rocketmq#93
Posted by do...@apache.org.
[ROCKETMQ-178] Fix -p -m options closes apache/incubator-rocketmq#93
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/42826c41
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/42826c41
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/42826c41
Branch: refs/heads/release-4.1.0-incubating
Commit: 42826c4115d91ee48512df288b6fe3822af73f06
Parents: c0fe02e
Author: Li Zhanhui <li...@apache.org>
Authored: Fri May 26 14:42:23 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri May 26 14:42:23 2017 +0800
----------------------------------------------------------------------
.../apache/rocketmq/broker/BrokerStartup.java | 32 +++++++++++---------
.../rocketmq/common/constant/LoggerName.java | 1 +
distribution/conf/logback_broker.xml | 5 +++
3 files changed, 23 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/42826c41/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
index 98ff136..85d2e3a 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java
@@ -103,20 +103,6 @@ public class BrokerStartup {
messageStoreConfig.setAccessMessageInMemoryMaxRatio(ratio);
}
- if (commandLine.hasOption('p')) {
- MixAll.printObjectProperties(null, brokerConfig);
- MixAll.printObjectProperties(null, nettyServerConfig);
- MixAll.printObjectProperties(null, nettyClientConfig);
- MixAll.printObjectProperties(null, messageStoreConfig);
- System.exit(0);
- } else if (commandLine.hasOption('m')) {
- MixAll.printObjectProperties(null, brokerConfig, true);
- MixAll.printObjectProperties(null, nettyServerConfig, true);
- MixAll.printObjectProperties(null, nettyClientConfig, true);
- MixAll.printObjectProperties(null, messageStoreConfig, true);
- System.exit(0);
- }
-
if (commandLine.hasOption('c')) {
String file = commandLine.getOptionValue('c');
if (file != null) {
@@ -181,8 +167,24 @@ public class BrokerStartup {
configurator.setContext(lc);
lc.reset();
configurator.doConfigure(brokerConfig.getRocketmqHome() + "/conf/logback_broker.xml");
- log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
+ if (commandLine.hasOption('p')) {
+ Logger console = LoggerFactory.getLogger(LoggerName.BROKER_CONSOLE_NAME);
+ MixAll.printObjectProperties(console, brokerConfig);
+ MixAll.printObjectProperties(console, nettyServerConfig);
+ MixAll.printObjectProperties(console, nettyClientConfig);
+ MixAll.printObjectProperties(console, messageStoreConfig);
+ System.exit(0);
+ } else if (commandLine.hasOption('m')) {
+ Logger console = LoggerFactory.getLogger(LoggerName.BROKER_CONSOLE_NAME);
+ MixAll.printObjectProperties(console, brokerConfig, true);
+ MixAll.printObjectProperties(console, nettyServerConfig, true);
+ MixAll.printObjectProperties(console, nettyClientConfig, true);
+ MixAll.printObjectProperties(console, messageStoreConfig, true);
+ System.exit(0);
+ }
+
+ log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
MixAll.printObjectProperties(log, brokerConfig);
MixAll.printObjectProperties(log, nettyServerConfig);
MixAll.printObjectProperties(log, nettyClientConfig);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/42826c41/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
index 385c121..12070dd 100644
--- a/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
+++ b/common/src/main/java/org/apache/rocketmq/common/constant/LoggerName.java
@@ -20,6 +20,7 @@ public class LoggerName {
public static final String FILTERSRV_LOGGER_NAME = "RocketmqFiltersrv";
public static final String NAMESRV_LOGGER_NAME = "RocketmqNamesrv";
public static final String BROKER_LOGGER_NAME = "RocketmqBroker";
+ public static final String BROKER_CONSOLE_NAME = "RocketmqConsole";
public static final String CLIENT_LOGGER_NAME = "RocketmqClient";
public static final String TOOLS_LOGGER_NAME = "RocketmqTools";
public static final String COMMON_LOGGER_NAME = "RocketmqCommon";
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/42826c41/distribution/conf/logback_broker.xml
----------------------------------------------------------------------
diff --git a/distribution/conf/logback_broker.xml b/distribution/conf/logback_broker.xml
index dd5c63f..3945fac 100644
--- a/distribution/conf/logback_broker.xml
+++ b/distribution/conf/logback_broker.xml
@@ -349,6 +349,11 @@
<appender-ref ref="RocketmqFilterAppender"/>
</logger>
+ <logger name="RocketmqConsole" additivity="false">
+ <level value="INFO" />
+ <appender-ref ref="STDOUT" />
+ </logger>
+
<root>
<level value="INFO"/>
<appender-ref ref="DefaultAppender"/>
[42/50] [abbrv] incubator-rocketmq git commit: Fix error tests,
producer should wait a while for consumer to be ready
Posted by do...@apache.org.
Fix error tests, producer should wait a while for consumer to be ready
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/3d1ec328
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/3d1ec328
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/3d1ec328
Branch: refs/heads/release-4.1.0-incubating
Commit: 3d1ec3289d96bc8464e507b6a446506ca26cf7e0
Parents: 0fe9471
Author: dongeforever <zh...@yeah.net>
Authored: Tue Jun 6 10:44:55 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Tue Jun 6 10:44:55 2017 +0800
----------------------------------------------------------------------
.../consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java | 4 ++--
.../producer/async/AsyncSendWithMessageQueueSelectorIT.java | 1 +
2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/3d1ec328/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
index 65762fa..32b13fd 100644
--- a/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/client/consumer/broadcast/normal/BroadCastNormalMsgNotRecvIT.java
@@ -50,13 +50,13 @@ public class BroadCastNormalMsgNotRecvIT extends BaseBroadCastIT {
}
@Test
- public void testNotConsumeAfterConsume() {
+ public void testNotConsumeAfterConsume() throws Exception {
int msgSize = 16;
String group = initConsumerGroup();
RMQBroadCastConsumer consumer1 = getBroadCastConsumer(nsAddr, group, topic, "*",
new RMQNormalListner(group + "_1"));
-
+ Thread.sleep(3000);
producer.send(msgSize);
Assert.assertEquals("Not all sent succeeded", msgSize, producer.getAllUndupMsgBody().size());
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/3d1ec328/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
index 843441d..82012ea 100644
--- a/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
+++ b/test/src/test/java/org/apache/rocketmq/test/client/producer/async/AsyncSendWithMessageQueueSelectorIT.java
@@ -80,6 +80,7 @@ public class AsyncSendWithMessageQueueSelectorIT extends BaseConf {
producer.clearMsg();
consumer.clearMsg();
+ producer.getSuccessSendResult().clear();
producer.asyncSend(msgSize, new MessageQueueSelector() {
@Override
[11/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
[ROCKETMQ-121]Support message filtering based on SQL92 closes apache/incubator-rocketmq#82
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/58f1574b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/58f1574b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/58f1574b
Branch: refs/heads/release-4.1.0-incubating
Commit: 58f1574b28bf8bf18a795036545c7a700437ed0b
Parents: 42f78c2
Author: vsair <li...@gmail.com>
Authored: Fri Apr 21 18:17:58 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri Apr 21 18:17:58 2017 +0800
----------------------------------------------------------------------
broker/pom.xml | 4 +
.../rocketmq/broker/BrokerController.java | 27 +
.../rocketmq/broker/BrokerPathConfigHelper.java | 3 +
.../broker/client/ConsumerGroupEvent.java | 33 +
.../client/ConsumerIdsChangeListener.java | 6 +-
.../rocketmq/broker/client/ConsumerManager.java | 11 +-
.../DefaultConsumerIdsChangeListener.java | 37 +-
.../filter/CommitLogDispatcherCalcBitMap.java | 110 ++
.../broker/filter/ConsumerFilterData.java | 151 ++
.../broker/filter/ConsumerFilterManager.java | 471 ++++++
.../filter/ExpressionForRetryMessageFilter.java | 97 ++
.../broker/filter/ExpressionMessageFilter.java | 162 +++
.../broker/filter/MessageEvaluationContext.java | 58 +
.../NotifyMessageArrivingListener.java | 8 +-
.../broker/longpolling/PullRequest.java | 10 +-
.../longpolling/PullRequestHoldService.java | 19 +-
.../rocketmq/broker/out/BrokerOuterAPI.java | 2 +-
.../plugin/AbstractPluginMessageStore.java | 18 +-
.../broker/processor/AdminBrokerProcessor.java | 91 ++
.../broker/processor/ClientManageProcessor.java | 44 +
.../broker/processor/PullMessageProcessor.java | 59 +-
.../CommitLogDispatcherCalcBitMapTest.java | 192 +++
.../filter/ConsumerFilterManagerTest.java | 291 ++++
.../filter/MessageStoreWithFilterTest.java | 392 +++++
.../processor/PullMessageProcessorTest.java | 9 +-
.../client/consumer/DefaultMQPushConsumer.java | 15 +
.../client/consumer/MQPushConsumer.java | 21 +
.../client/consumer/MessageSelector.java | 77 +
.../rocketmq/client/impl/FindBrokerResult.java | 12 +
.../rocketmq/client/impl/MQClientAPIImpl.java | 57 +-
.../consumer/DefaultMQPushConsumerImpl.java | 40 +-
.../client/impl/consumer/PullAPIWrapper.java | 40 +
.../client/impl/factory/MQClientInstance.java | 60 +-
.../apache/rocketmq/common/BrokerConfig.java | 67 +
.../java/org/apache/rocketmq/common/MixAll.java | 14 +-
.../rocketmq/common/constant/LoggerName.java | 1 +
.../rocketmq/common/filter/ExpressionType.java | 67 +
.../rocketmq/common/filter/FilterAPI.java | 18 +
.../apache/rocketmq/common/message/Message.java | 6 +
.../rocketmq/common/message/MessageDecoder.java | 39 +
.../rocketmq/common/namesrv/TopAddressing.java | 2 +-
.../rocketmq/common/protocol/RequestCode.java | 4 +
.../rocketmq/common/protocol/ResponseCode.java | 4 +
.../protocol/body/CheckClientRequestBody.java | 52 +
.../common/protocol/body/ConsumeQueueData.java | 98 ++
.../body/QueryConsumeQueueResponseBody.java | 72 +
.../header/PullMessageRequestHeader.java | 9 +
.../header/QueryConsumeQueueRequestHeader.java | 75 +
.../protocol/heartbeat/SubscriptionData.java | 17 +-
.../rocketmq/common/filter/FilterAPITest.java | 49 +
.../common/message/MessageDecoderTest.java | 80 ++
distribution/conf/logback_broker.xml | 28 +
distribution/release.xml | 1 +
.../rocketmq/example/benchmark/Consumer.java | 31 +-
.../rocketmq/example/benchmark/Producer.java | 34 +-
.../rocketmq/example/filter/SqlConsumer.java | 62 +
.../rocketmq/example/filter/SqlProducer.java | 67 +
filter/pom.xml | 43 +
.../apache/rocketmq/filter/FilterFactory.java | 72 +
.../org/apache/rocketmq/filter/FilterSpi.java | 43 +
.../org/apache/rocketmq/filter/SqlFilter.java | 43 +
.../rocketmq/filter/constant/UnaryType.java | 26 +
.../filter/expression/BinaryExpression.java | 91 ++
.../filter/expression/BooleanExpression.java | 39 +
.../filter/expression/ComparisonExpression.java | 413 ++++++
.../filter/expression/ConstantExpression.java | 156 ++
.../expression/EmptyEvaluationContext.java | 35 +
.../filter/expression/EvaluationContext.java | 43 +
.../rocketmq/filter/expression/Expression.java | 38 +
.../filter/expression/LogicExpression.java | 94 ++
.../filter/expression/MQFilterException.java | 46 +
.../filter/expression/NowExpression.java | 36 +
.../filter/expression/PropertyExpression.java | 70 +
.../filter/expression/UnaryExpression.java | 267 ++++
.../filter/expression/UnaryInExpression.java | 61 +
.../rocketmq/filter/parser/ParseException.java | 204 +++
.../rocketmq/filter/parser/SelectorParser.java | 1354 ++++++++++++++++++
.../rocketmq/filter/parser/SelectorParser.jj | 524 +++++++
.../filter/parser/SelectorParserConstants.java | 140 ++
.../parser/SelectorParserTokenManager.java | 919 ++++++++++++
.../filter/parser/SimpleCharStream.java | 502 +++++++
.../apache/rocketmq/filter/parser/Token.java | 152 ++
.../rocketmq/filter/parser/TokenMgrError.java | 174 +++
.../apache/rocketmq/filter/util/BitsArray.java | 260 ++++
.../rocketmq/filter/util/BloomFilter.java | 338 +++++
.../rocketmq/filter/util/BloomFilterData.java | 83 ++
.../apache/rocketmq/filter/BitsArrayTest.java | 123 ++
.../apache/rocketmq/filter/BloomFilterTest.java | 172 +++
.../apache/rocketmq/filter/ExpressionTest.java | 594 ++++++++
.../apache/rocketmq/filter/FilterSpiTest.java | 84 ++
.../org/apache/rocketmq/filter/ParserTest.java | 129 ++
pom.xml | 11 +
srvutil/pom.xml | 4 +
.../org/apache/rocketmq/store/CommitLog.java | 8 +-
.../rocketmq/store/CommitLogDispatcher.java | 26 +
.../org/apache/rocketmq/store/ConsumeQueue.java | 122 +-
.../apache/rocketmq/store/ConsumeQueueExt.java | 638 +++++++++
.../rocketmq/store/DefaultMessageFilter.java | 29 +-
.../rocketmq/store/DefaultMessageStore.java | 132 +-
.../apache/rocketmq/store/DispatchRequest.java | 21 +-
.../org/apache/rocketmq/store/MappedFile.java | 25 +
.../apache/rocketmq/store/MappedFileQueue.java | 2 +-
.../rocketmq/store/MessageArrivingListener.java | 5 +-
.../apache/rocketmq/store/MessageFilter.java | 26 +-
.../org/apache/rocketmq/store/MessageStore.java | 8 +-
.../store/config/MessageStoreConfig.java | 31 +
.../store/config/StorePathConfigHelper.java | 4 +
.../store/schedule/ScheduleMessageService.java | 14 +
.../rocketmq/store/ConsumeQueueExtTest.java | 251 ++++
.../apache/rocketmq/store/ConsumeQueueTest.java | 226 +++
.../rocketmq/store/DefaultMessageStoreTest.java | 4 +-
.../rocketmq/tools/admin/DefaultMQAdminExt.java | 9 +
.../tools/admin/DefaultMQAdminExtImpl.java | 8 +
.../apache/rocketmq/tools/admin/MQAdminExt.java | 22 +
.../rocketmq/tools/command/MQAdminStartup.java | 3 +
.../command/queue/QueryConsumeQueueCommand.java | 159 ++
116 files changed, 12552 insertions(+), 128 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/pom.xml
----------------------------------------------------------------------
diff --git a/broker/pom.xml b/broker/pom.xml
index 8cdafea..0f8ad0a 100644
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -49,6 +49,10 @@
<artifactId>rocketmq-srvutil</artifactId>
</dependency>
<dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-filter</artifactId>
+ </dependency>
+ <dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
index 6acd40c..bacd25c 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerController.java
@@ -37,6 +37,8 @@ import org.apache.rocketmq.broker.client.DefaultConsumerIdsChangeListener;
import org.apache.rocketmq.broker.client.ProducerManager;
import org.apache.rocketmq.broker.client.net.Broker2Client;
import org.apache.rocketmq.broker.client.rebalance.RebalanceLockManager;
+import org.apache.rocketmq.broker.filter.CommitLogDispatcherCalcBitMap;
+import org.apache.rocketmq.broker.filter.ConsumerFilterManager;
import org.apache.rocketmq.broker.filtersrv.FilterServerManager;
import org.apache.rocketmq.broker.latency.BrokerFastFailure;
import org.apache.rocketmq.broker.latency.BrokerFixedThreadPoolExecutor;
@@ -96,6 +98,7 @@ public class BrokerController {
private final MessageStoreConfig messageStoreConfig;
private final ConsumerOffsetManager consumerOffsetManager;
private final ConsumerManager consumerManager;
+ private final ConsumerFilterManager consumerFilterManager;
private final ProducerManager producerManager;
private final ClientHousekeepingService clientHousekeepingService;
private final PullMessageProcessor pullMessageProcessor;
@@ -149,6 +152,7 @@ public class BrokerController {
this.messageArrivingListener = new NotifyMessageArrivingListener(this.pullRequestHoldService);
this.consumerIdsChangeListener = new DefaultConsumerIdsChangeListener(this);
this.consumerManager = new ConsumerManager(this.consumerIdsChangeListener);
+ this.consumerFilterManager = new ConsumerFilterManager(this);
this.producerManager = new ProducerManager();
this.clientHousekeepingService = new ClientHousekeepingService(this);
this.broker2Client = new Broker2Client(this);
@@ -192,6 +196,7 @@ public class BrokerController {
result = result && this.consumerOffsetManager.load();
result = result && this.subscriptionGroupManager.load();
+ result = result && this.consumerFilterManager.load();
if (result) {
try {
@@ -202,6 +207,7 @@ public class BrokerController {
//load plugin
MessageStorePluginContext context = new MessageStorePluginContext(messageStoreConfig, brokerStatsManager, messageArrivingListener, brokerConfig);
this.messageStore = MessageStoreFactory.build(context, this.messageStore);
+ this.messageStore.getDispatcherList().addFirst(new CommitLogDispatcherCalcBitMap(this.brokerConfig, this.consumerFilterManager));
} catch (IOException e) {
result = false;
e.printStackTrace();
@@ -278,6 +284,17 @@ public class BrokerController {
@Override
public void run() {
try {
+ BrokerController.this.consumerFilterManager.persist();
+ } catch (Throwable e) {
+ log.error("schedule persist consumer filter error.", e);
+ }
+ }
+ }, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS);
+
+ this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ try {
BrokerController.this.protectBroker();
} catch (Exception e) {
log.error("protectBroker error.", e);
@@ -400,9 +417,11 @@ public class BrokerController {
ClientManageProcessor clientProcessor = new ClientManageProcessor(this);
this.remotingServer.registerProcessor(RequestCode.HEART_BEAT, clientProcessor, this.clientManageExecutor);
this.remotingServer.registerProcessor(RequestCode.UNREGISTER_CLIENT, clientProcessor, this.clientManageExecutor);
+ this.remotingServer.registerProcessor(RequestCode.CHECK_CLIENT_CONFIG, clientProcessor, this.clientManageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.HEART_BEAT, clientProcessor, this.clientManageExecutor);
this.fastRemotingServer.registerProcessor(RequestCode.UNREGISTER_CLIENT, clientProcessor, this.clientManageExecutor);
+ this.remotingServer.registerProcessor(RequestCode.CHECK_CLIENT_CONFIG, clientProcessor, this.clientManageExecutor);
/**
* ConsumerManageProcessor
@@ -504,6 +523,10 @@ public class BrokerController {
return consumerManager;
}
+ public ConsumerFilterManager getConsumerFilterManager() {
+ return consumerFilterManager;
+ }
+
public ConsumerOffsetManager getConsumerOffsetManager() {
return consumerOffsetManager;
}
@@ -590,6 +613,10 @@ public class BrokerController {
if (this.brokerFastFailure != null) {
this.brokerFastFailure.shutdown();
}
+
+ if (this.consumerFilterManager != null) {
+ this.consumerFilterManager.persist();
+ }
}
private void unregisterBrokerAll() {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/BrokerPathConfigHelper.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerPathConfigHelper.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerPathConfigHelper.java
index 24876df..0a323ee 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerPathConfigHelper.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerPathConfigHelper.java
@@ -44,4 +44,7 @@ public class BrokerPathConfigHelper {
return rootDir + File.separator + "config" + File.separator + "subscriptionGroup.json";
}
+ public static String getConsumerFilterPath(final String rootDir) {
+ return rootDir + File.separator + "config" + File.separator + "consumerFilter.json";
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java
new file mode 100644
index 0000000..717fb70
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerGroupEvent.java
@@ -0,0 +1,33 @@
+/*
+ * 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.broker.client;
+
+public enum ConsumerGroupEvent {
+
+ /**
+ * Some consumers in the group are changed.
+ */
+ CHANGE,
+ /**
+ * The group of consumer is unregistered.
+ */
+ UNREGISTER,
+ /**
+ * The group of consumer is registered.
+ */
+ REGISTER
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerIdsChangeListener.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerIdsChangeListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerIdsChangeListener.java
index 07d28dc..831e293 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerIdsChangeListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerIdsChangeListener.java
@@ -16,9 +16,7 @@
*/
package org.apache.rocketmq.broker.client;
-import io.netty.channel.Channel;
-import java.util.List;
-
public interface ConsumerIdsChangeListener {
- void consumerIdsChanged(final String group, final List<Channel> channels);
+
+ void handle(ConsumerGroupEvent event, String group, Object... args);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
index a2d88d5..a5ddec8 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/ConsumerManager.java
@@ -85,10 +85,11 @@ public class ConsumerManager {
if (remove != null) {
log.info("unregister consumer ok, no any connection, and remove consumer group, {}",
next.getKey());
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, next.getKey());
}
}
- this.consumerIdsChangeListener.consumerIdsChanged(next.getKey(), info.getAllChannel());
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, next.getKey(), info.getAllChannel());
}
}
}
@@ -111,10 +112,12 @@ public class ConsumerManager {
if (r1 || r2) {
if (isNotifyConsumerIdsChangedEnable) {
- this.consumerIdsChangeListener.consumerIdsChanged(group, consumerGroupInfo.getAllChannel());
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel());
}
}
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.REGISTER, group, subList);
+
return r1 || r2;
}
@@ -126,10 +129,12 @@ public class ConsumerManager {
ConsumerGroupInfo remove = this.consumerTable.remove(group);
if (remove != null) {
log.info("unregister consumer ok, no any connection, and remove consumer group, {}", group);
+
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.UNREGISTER, group);
}
}
if (isNotifyConsumerIdsChangedEnable) {
- this.consumerIdsChangeListener.consumerIdsChanged(group, consumerGroupInfo.getAllChannel());
+ this.consumerIdsChangeListener.handle(ConsumerGroupEvent.CHANGE, group, consumerGroupInfo.getAllChannel());
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
index a1b2d8a..d716a33 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/client/DefaultConsumerIdsChangeListener.java
@@ -17,8 +17,12 @@
package org.apache.rocketmq.broker.client;
import io.netty.channel.Channel;
+
+import java.util.Collection;
import java.util.List;
+
import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListener {
private final BrokerController brokerController;
@@ -28,11 +32,34 @@ public class DefaultConsumerIdsChangeListener implements ConsumerIdsChangeListen
}
@Override
- public void consumerIdsChanged(String group, List<Channel> channels) {
- if (channels != null && brokerController.getBrokerConfig().isNotifyConsumerIdsChangedEnable()) {
- for (Channel chl : channels) {
- this.brokerController.getBroker2Client().notifyConsumerIdsChanged(chl, group);
- }
+ public void handle(ConsumerGroupEvent event, String group, Object... args) {
+ if (event == null) {
+ return;
+ }
+ switch (event) {
+ case CHANGE:
+ if (args == null || args.length < 1) {
+ return;
+ }
+ List<Channel> channels = (List<Channel>) args[0];
+ if (channels != null && brokerController.getBrokerConfig().isNotifyConsumerIdsChangedEnable()) {
+ for (Channel chl : channels) {
+ this.brokerController.getBroker2Client().notifyConsumerIdsChanged(chl, group);
+ }
+ }
+ break;
+ case UNREGISTER:
+ this.brokerController.getConsumerFilterManager().unRegister(group);
+ break;
+ case REGISTER:
+ if (args == null || args.length < 1) {
+ return;
+ }
+ Collection<SubscriptionData> subscriptionDataList = (Collection<SubscriptionData>) args[0];
+ this.brokerController.getConsumerFilterManager().register(group, subscriptionDataList);
+ break;
+ default:
+ throw new RuntimeException("Unknown event " + event);
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMap.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMap.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMap.java
new file mode 100644
index 0000000..85415d6
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/CommitLogDispatcherCalcBitMap.java
@@ -0,0 +1,110 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.filter.util.BitsArray;
+import org.apache.rocketmq.store.CommitLogDispatcher;
+import org.apache.rocketmq.store.DispatchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Calculate bit map of filter.
+ */
+public class CommitLogDispatcherCalcBitMap implements CommitLogDispatcher {
+
+ private static final Logger log = LoggerFactory.getLogger(LoggerName.FILTER_LOGGER_NAME);
+
+ protected final BrokerConfig brokerConfig;
+ protected final ConsumerFilterManager consumerFilterManager;
+
+ public CommitLogDispatcherCalcBitMap(BrokerConfig brokerConfig, ConsumerFilterManager consumerFilterManager) {
+ this.brokerConfig = brokerConfig;
+ this.consumerFilterManager = consumerFilterManager;
+ }
+
+ @Override
+ public void dispatch(DispatchRequest request) {
+ if (!this.brokerConfig.isEnableCalcFilterBitMap()) {
+ return;
+ }
+
+ try {
+
+ Collection<ConsumerFilterData> filterDatas = consumerFilterManager.get(request.getTopic());
+
+ if (filterDatas == null || filterDatas.isEmpty()) {
+ return;
+ }
+
+ Iterator<ConsumerFilterData> iterator = filterDatas.iterator();
+ BitsArray filterBitMap = BitsArray.create(
+ this.consumerFilterManager.getBloomFilter().getM()
+ );
+
+ long startTime = System.currentTimeMillis();
+ while (iterator.hasNext()) {
+ ConsumerFilterData filterData = iterator.next();
+
+ if (filterData.getCompiledExpression() == null) {
+ log.error("[BUG] Consumer in filter manager has no compiled expression! {}", filterData);
+ continue;
+ }
+
+ if (filterData.getBloomFilterData() == null) {
+ log.error("[BUG] Consumer in filter manager has no bloom data! {}", filterData);
+ continue;
+ }
+
+ Object ret = null;
+ try {
+ MessageEvaluationContext context = new MessageEvaluationContext(request.getPropertiesMap());
+
+ ret = filterData.getCompiledExpression().evaluate(context);
+ } catch (Throwable e) {
+ log.error("Calc filter bit map error!commitLogOffset={}, consumer={}, {}", request.getCommitLogOffset(), filterData, e);
+ }
+
+ log.debug("Result of Calc bit map:ret={}, data={}, props={}, offset={}", ret, filterData, request.getPropertiesMap(), request.getCommitLogOffset());
+
+ // eval true
+ if (ret != null && ret instanceof Boolean && (Boolean) ret) {
+ consumerFilterManager.getBloomFilter().hashTo(
+ filterData.getBloomFilterData(),
+ filterBitMap
+ );
+ }
+ }
+
+ request.setBitMap(filterBitMap.bytes());
+
+ long eclipseTime = System.currentTimeMillis() - startTime;
+ // 1ms
+ if (eclipseTime >= 1) {
+ log.warn("Spend {} ms to calc bit map, consumerNum={}, topic={}", eclipseTime, filterDatas.size(), request.getTopic());
+ }
+ } catch (Throwable e) {
+ log.error("Calc bit map error! topic={}, offset={}, queueId={}, {}", request.getTopic(), request.getCommitLogOffset(), request.getQueueId(), e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterData.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterData.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterData.java
new file mode 100644
index 0000000..4db02e2
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterData.java
@@ -0,0 +1,151 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.util.BloomFilterData;
+
+import java.util.Collections;
+
+/**
+ * Filter data of consumer.
+ */
+public class ConsumerFilterData {
+
+ private String consumerGroup;
+ private String topic;
+ private String expression;
+ private String expressionType;
+ private transient Expression compiledExpression;
+ private long bornTime;
+ private long deadTime = 0;
+ private BloomFilterData bloomFilterData;
+ private long clientVersion;
+
+ public boolean isDead() {
+ return this.deadTime >= this.bornTime;
+ }
+
+ public long howLongAfterDeath() {
+ if (isDead()) {
+ return System.currentTimeMillis() - getDeadTime();
+ }
+ return -1;
+ }
+
+ /**
+ * Check this filter data has been used to calculate bit map when msg was stored in server.
+ *
+ * @param msgStoreTime
+ * @return
+ */
+ public boolean isMsgInLive(long msgStoreTime) {
+ return msgStoreTime > getBornTime();
+ }
+
+ public String getConsumerGroup() {
+ return consumerGroup;
+ }
+
+ public void setConsumerGroup(final String consumerGroup) {
+ this.consumerGroup = consumerGroup;
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(final String topic) {
+ this.topic = topic;
+ }
+
+ public String getExpression() {
+ return expression;
+ }
+
+ public void setExpression(final String expression) {
+ this.expression = expression;
+ }
+
+ public String getExpressionType() {
+ return expressionType;
+ }
+
+ public void setExpressionType(final String expressionType) {
+ this.expressionType = expressionType;
+ }
+
+ public Expression getCompiledExpression() {
+ return compiledExpression;
+ }
+
+ public void setCompiledExpression(final Expression compiledExpression) {
+ this.compiledExpression = compiledExpression;
+ }
+
+ public long getBornTime() {
+ return bornTime;
+ }
+
+ public void setBornTime(final long bornTime) {
+ this.bornTime = bornTime;
+ }
+
+ public long getDeadTime() {
+ return deadTime;
+ }
+
+ public void setDeadTime(final long deadTime) {
+ this.deadTime = deadTime;
+ }
+
+ public BloomFilterData getBloomFilterData() {
+ return bloomFilterData;
+ }
+
+ public void setBloomFilterData(final BloomFilterData bloomFilterData) {
+ this.bloomFilterData = bloomFilterData;
+ }
+
+ public long getClientVersion() {
+ return clientVersion;
+ }
+
+ public void setClientVersion(long clientVersion) {
+ this.clientVersion = clientVersion;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return EqualsBuilder.reflectionEquals(this, o, Collections.<String>emptyList());
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this, Collections.<String>emptyList());
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
new file mode 100644
index 0000000..7f790af
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ConsumerFilterManager.java
@@ -0,0 +1,471 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.broker.BrokerPathConfigHelper;
+import org.apache.rocketmq.common.ConfigManager;
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.filter.FilterFactory;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.filter.util.BloomFilter;
+import org.apache.rocketmq.filter.util.BloomFilterData;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Consumer filter data manager.Just manage the consumers use expression filter.
+ */
+public class ConsumerFilterManager extends ConfigManager {
+
+ private static final Logger log = LoggerFactory.getLogger(LoggerName.FILTER_LOGGER_NAME);
+
+ private static final long MS_24_HOUR = 24 * 3600 * 1000;
+
+ private ConcurrentHashMap<String/*Topic*/, FilterDataMapByTopic>
+ filterDataByTopic = new ConcurrentHashMap<String/*consumer group*/, FilterDataMapByTopic>(256);
+
+ private transient BrokerController brokerController;
+ private transient BloomFilter bloomFilter;
+
+ public ConsumerFilterManager() {
+ // just for test
+ this.bloomFilter = BloomFilter.createByFn(20, 64);
+ }
+
+ public ConsumerFilterManager(BrokerController brokerController) {
+ this.brokerController = brokerController;
+ this.bloomFilter = BloomFilter.createByFn(
+ brokerController.getBrokerConfig().getMaxErrorRateOfBloomFilter(),
+ brokerController.getBrokerConfig().getExpectConsumerNumUseFilter()
+ );
+ // then set bit map length of store config.
+ brokerController.getMessageStoreConfig().setBitMapLengthConsumeQueueExt(
+ this.bloomFilter.getM()
+ );
+ }
+
+ /**
+ * Build consumer filter data.Be care, bloom filter data is not included.
+ *
+ * @param topic
+ * @param consumerGroup
+ * @param expression
+ * @param type
+ * @param clientVersion
+ * @return maybe null
+ */
+ public static ConsumerFilterData build(final String topic, final String consumerGroup,
+ final String expression, final String type,
+ final long clientVersion) {
+ if (ExpressionType.isTagType(type)) {
+ return null;
+ }
+
+ ConsumerFilterData consumerFilterData = new ConsumerFilterData();
+ consumerFilterData.setTopic(topic);
+ consumerFilterData.setConsumerGroup(consumerGroup);
+ consumerFilterData.setBornTime(System.currentTimeMillis());
+ consumerFilterData.setDeadTime(0);
+ consumerFilterData.setExpression(expression);
+ consumerFilterData.setExpressionType(type);
+ consumerFilterData.setClientVersion(clientVersion);
+ try {
+ consumerFilterData.setCompiledExpression(
+ FilterFactory.INSTANCE.get(type).compile(expression)
+ );
+ } catch (Throwable e) {
+ log.error("parse error: expr={}, topic={}, group={}, error={}", expression, topic, consumerGroup, e.getMessage());
+ return null;
+ }
+
+ return consumerFilterData;
+ }
+
+ public void register(final String consumerGroup, final Collection<SubscriptionData> subList) {
+ for (SubscriptionData subscriptionData : subList) {
+ register(
+ subscriptionData.getTopic(),
+ consumerGroup,
+ subscriptionData.getSubString(),
+ subscriptionData.getExpressionType(),
+ subscriptionData.getSubVersion()
+ );
+ }
+
+ // make illegal topic dead.
+ Collection<ConsumerFilterData> groupFilterData = getByGroup(consumerGroup);
+
+ Iterator<ConsumerFilterData> iterator = groupFilterData.iterator();
+ while (iterator.hasNext()) {
+ ConsumerFilterData filterData = iterator.next();
+
+ boolean exist = false;
+ for (SubscriptionData subscriptionData : subList) {
+ if (subscriptionData.getTopic().equals(filterData.getTopic())) {
+ exist = true;
+ break;
+ }
+ }
+
+ if (!exist && !filterData.isDead()) {
+ filterData.setDeadTime(System.currentTimeMillis());
+ log.info("Consumer filter changed: {}, make illegal topic dead:{}", consumerGroup, filterData);
+ }
+ }
+ }
+
+ public boolean register(final String topic, final String consumerGroup, final String expression,
+ final String type, final long clientVersion) {
+ if (ExpressionType.isTagType(type)) {
+ return false;
+ }
+
+ if (expression == null || expression.length() == 0) {
+ return false;
+ }
+
+ FilterDataMapByTopic filterDataMapByTopic = this.filterDataByTopic.get(topic);
+
+ if (filterDataMapByTopic == null) {
+ FilterDataMapByTopic temp = new FilterDataMapByTopic(topic);
+ FilterDataMapByTopic prev = this.filterDataByTopic.putIfAbsent(topic, temp);
+ filterDataMapByTopic = prev != null ? prev : temp;
+ }
+
+ BloomFilterData bloomFilterData = bloomFilter.generate(consumerGroup + "#" + topic);
+
+ return filterDataMapByTopic.register(consumerGroup, expression, type, bloomFilterData, clientVersion);
+ }
+
+ public void unRegister(final String consumerGroup) {
+ for (String topic : filterDataByTopic.keySet()) {
+ this.filterDataByTopic.get(topic).unRegister(consumerGroup);
+ }
+ }
+
+ public ConsumerFilterData get(final String topic, final String consumerGroup) {
+ if (!this.filterDataByTopic.containsKey(topic)) {
+ return null;
+ }
+ if (this.filterDataByTopic.get(topic).getGroupFilterData().isEmpty()) {
+ return null;
+ }
+
+ return this.filterDataByTopic.get(topic).getGroupFilterData().get(consumerGroup);
+ }
+
+ public Collection<ConsumerFilterData> getByGroup(final String consumerGroup) {
+ Collection<ConsumerFilterData> ret = new HashSet<ConsumerFilterData>();
+
+ Iterator<FilterDataMapByTopic> topicIterator = this.filterDataByTopic.values().iterator();
+ while (topicIterator.hasNext()) {
+ FilterDataMapByTopic filterDataMapByTopic = topicIterator.next();
+
+ Iterator<ConsumerFilterData> filterDataIterator = filterDataMapByTopic.getGroupFilterData().values().iterator();
+
+ while (filterDataIterator.hasNext()) {
+ ConsumerFilterData filterData = filterDataIterator.next();
+
+ if (filterData.getConsumerGroup().equals(consumerGroup)) {
+ ret.add(filterData);
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public final Collection<ConsumerFilterData> get(final String topic) {
+ if (!this.filterDataByTopic.containsKey(topic)) {
+ return null;
+ }
+ if (this.filterDataByTopic.get(topic).getGroupFilterData().isEmpty()) {
+ return null;
+ }
+
+ return this.filterDataByTopic.get(topic).getGroupFilterData().values();
+ }
+
+ public BloomFilter getBloomFilter() {
+ return bloomFilter;
+ }
+
+ @Override
+ public String encode() {
+ return encode(false);
+ }
+
+ @Override
+ public String configFilePath() {
+ if (this.brokerController != null) {
+ return BrokerPathConfigHelper.getConsumerFilterPath(
+ this.brokerController.getMessageStoreConfig().getStorePathRootDir()
+ );
+ }
+ return BrokerPathConfigHelper.getConsumerFilterPath("./unit_test");
+ }
+
+ @Override
+ public void decode(final String jsonString) {
+ ConsumerFilterManager load = RemotingSerializable.fromJson(jsonString, ConsumerFilterManager.class);
+ if (load != null && load.filterDataByTopic != null) {
+ boolean bloomChanged = false;
+ for (String topic : load.filterDataByTopic.keySet()) {
+ FilterDataMapByTopic dataMapByTopic = load.filterDataByTopic.get(topic);
+ if (dataMapByTopic == null) {
+ continue;
+ }
+
+ for (String group : dataMapByTopic.getGroupFilterData().keySet()) {
+
+ ConsumerFilterData filterData = dataMapByTopic.getGroupFilterData().get(group);
+
+ if (filterData == null) {
+ continue;
+ }
+
+ try {
+ filterData.setCompiledExpression(
+ FilterFactory.INSTANCE.get(filterData.getExpressionType()).compile(filterData.getExpression())
+ );
+ } catch (Exception e) {
+ log.error("load filter data error, " + filterData, e);
+ }
+
+ // check whether bloom filter is changed
+ // if changed, ignore the bit map calculated before.
+ if (!this.bloomFilter.isValid(filterData.getBloomFilterData())) {
+ bloomChanged = true;
+ log.info("Bloom filter is changed!So ignore all filter data persisted! {}, {}", this.bloomFilter, filterData.getBloomFilterData());
+ break;
+ }
+
+ log.info("load exist consumer filter data: {}", filterData);
+
+ if (filterData.getDeadTime() == 0) {
+ // we think all consumers are dead when load
+ long deadTime = System.currentTimeMillis() - 30 * 1000;
+ filterData.setDeadTime(
+ deadTime <= filterData.getBornTime() ? filterData.getBornTime() : deadTime
+ );
+ }
+ }
+ }
+
+ if (!bloomChanged) {
+ this.filterDataByTopic = load.filterDataByTopic;
+ }
+ }
+ }
+
+ @Override
+ public String encode(final boolean prettyFormat) {
+ // clean
+ {
+ clean();
+ }
+ return RemotingSerializable.toJson(this, prettyFormat);
+ }
+
+ public void clean() {
+ Iterator<Map.Entry<String, FilterDataMapByTopic>> topicIterator = this.filterDataByTopic.entrySet().iterator();
+ while (topicIterator.hasNext()) {
+ Map.Entry<String, FilterDataMapByTopic> filterDataMapByTopic = topicIterator.next();
+
+ Iterator<Map.Entry<String, ConsumerFilterData>> filterDataIterator
+ = filterDataMapByTopic.getValue().getGroupFilterData().entrySet().iterator();
+
+ while (filterDataIterator.hasNext()) {
+ Map.Entry<String, ConsumerFilterData> filterDataByGroup = filterDataIterator.next();
+
+ ConsumerFilterData filterData = filterDataByGroup.getValue();
+ if (filterData.howLongAfterDeath() >= (this.brokerController == null ? MS_24_HOUR : this.brokerController.getBrokerConfig().getFilterDataCleanTimeSpan())) {
+ log.info("Remove filter consumer {}, died too long!", filterDataByGroup.getValue());
+ filterDataIterator.remove();
+ }
+ }
+
+ if (filterDataMapByTopic.getValue().getGroupFilterData().isEmpty()) {
+ log.info("Topic has no consumer, remove it! {}", filterDataMapByTopic.getKey());
+ topicIterator.remove();
+ }
+ }
+ }
+
+ public ConcurrentHashMap<String, FilterDataMapByTopic> getFilterDataByTopic() {
+ return filterDataByTopic;
+ }
+
+ public void setFilterDataByTopic(final ConcurrentHashMap<String, FilterDataMapByTopic> filterDataByTopic) {
+ this.filterDataByTopic = filterDataByTopic;
+ }
+
+ public static class FilterDataMapByTopic {
+
+ private ConcurrentHashMap<String/*consumer group*/, ConsumerFilterData>
+ groupFilterData = new ConcurrentHashMap<String, ConsumerFilterData>();
+
+ private String topic;
+
+ public FilterDataMapByTopic() {
+ }
+
+ public FilterDataMapByTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public void unRegister(String consumerGroup) {
+ if (!this.groupFilterData.containsKey(consumerGroup)) {
+ return;
+ }
+
+ ConsumerFilterData data = this.groupFilterData.get(consumerGroup);
+
+ if (data == null || data.isDead()) {
+ return;
+ }
+
+ long now = System.currentTimeMillis();
+
+ log.info("Unregister consumer filter: {}, deadTime: {}", data, now);
+
+ data.setDeadTime(now);
+ }
+
+ public boolean register(String consumerGroup, String expression, String type, BloomFilterData bloomFilterData, long clientVersion) {
+ ConsumerFilterData old = this.groupFilterData.get(consumerGroup);
+
+ if (old == null) {
+ ConsumerFilterData consumerFilterData = build(topic, consumerGroup, expression, type, clientVersion);
+ if (consumerFilterData == null) {
+ return false;
+ }
+ consumerFilterData.setBloomFilterData(bloomFilterData);
+
+ old = this.groupFilterData.putIfAbsent(consumerGroup, consumerFilterData);
+ if (old == null) {
+ log.info("New consumer filter registered: {}", consumerFilterData);
+ return true;
+ } else {
+ if (clientVersion <= old.getClientVersion()) {
+ if (!type.equals(old.getExpressionType()) || !expression.equals(old.getExpression())) {
+ log.warn("Ignore consumer({} : {}) filter(concurrent), because of version {} <= {}, but maybe info changed!old={}:{}, ignored={}:{}",
+ consumerGroup, topic,
+ clientVersion, old.getClientVersion(),
+ old.getExpressionType(), old.getExpression(),
+ type, expression);
+ }
+ if (clientVersion == old.getClientVersion() && old.isDead()) {
+ reAlive(old);
+ return true;
+ }
+
+ return false;
+ } else {
+ this.groupFilterData.put(consumerGroup, consumerFilterData);
+ log.info("New consumer filter registered(concurrent): {}, old: {}", consumerFilterData, old);
+ return true;
+ }
+ }
+ } else {
+ if (clientVersion <= old.getClientVersion()) {
+ if (!type.equals(old.getExpressionType()) || !expression.equals(old.getExpression())) {
+ log.info("Ignore consumer({}:{}) filter, because of version {} <= {}, but maybe info changed!old={}:{}, ignored={}:{}",
+ consumerGroup, topic,
+ clientVersion, old.getClientVersion(),
+ old.getExpressionType(), old.getExpression(),
+ type, expression);
+ }
+ if (clientVersion == old.getClientVersion() && old.isDead()) {
+ reAlive(old);
+ return true;
+ }
+
+ return false;
+ }
+
+ boolean change = !old.getExpression().equals(expression) || !old.getExpressionType().equals(type);
+ if (old.getBloomFilterData() == null && bloomFilterData != null) {
+ change = true;
+ }
+ if (old.getBloomFilterData() != null && !old.getBloomFilterData().equals(bloomFilterData)) {
+ change = true;
+ }
+
+ // if subscribe data is changed, or consumer is died too long.
+ if (change) {
+ ConsumerFilterData consumerFilterData = build(topic, consumerGroup, expression, type, clientVersion);
+ if (consumerFilterData == null) {
+ // new expression compile error, remove old, let client report error.
+ this.groupFilterData.remove(consumerGroup);
+ return false;
+ }
+ consumerFilterData.setBloomFilterData(bloomFilterData);
+
+ this.groupFilterData.put(consumerGroup, consumerFilterData);
+
+ log.info("Consumer filter info change, old: {}, new: {}, change: {}",
+ old, consumerFilterData, change);
+
+ return true;
+ } else {
+ old.setClientVersion(clientVersion);
+ if (old.isDead()) {
+ reAlive(old);
+ }
+ return true;
+ }
+ }
+ }
+
+ protected void reAlive(ConsumerFilterData filterData) {
+ long oldDeadTime = filterData.getDeadTime();
+ filterData.setDeadTime(0);
+ log.info("Re alive consumer filter: {}, oldDeadTime: {}", filterData, oldDeadTime);
+ }
+
+ public final ConsumerFilterData get(String consumerGroup) {
+ return this.groupFilterData.get(consumerGroup);
+ }
+
+ public final ConcurrentHashMap<String, ConsumerFilterData> getGroupFilterData() {
+ return this.groupFilterData;
+ }
+
+ public void setGroupFilterData(final ConcurrentHashMap<String, ConsumerFilterData> groupFilterData) {
+ this.groupFilterData = groupFilterData;
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(final String topic) {
+ this.topic = topic;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionForRetryMessageFilter.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionForRetryMessageFilter.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionForRetryMessageFilter.java
new file mode 100644
index 0000000..9518178
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionForRetryMessageFilter.java
@@ -0,0 +1,97 @@
+/*
+ * 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.broker.filter;
+
+
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.common.message.MessageConst;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+/**
+ * Support filter to retry topic.
+ * <br>It will decode properties first in order to get real topic.
+ */
+public class ExpressionForRetryMessageFilter extends ExpressionMessageFilter {
+ public ExpressionForRetryMessageFilter(SubscriptionData subscriptionData, ConsumerFilterData consumerFilterData, ConsumerFilterManager consumerFilterManager) {
+ super(subscriptionData, consumerFilterData, consumerFilterManager);
+ }
+
+ @Override
+ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map<String, String> properties) {
+ if (subscriptionData == null) {
+ return true;
+ }
+
+ if (subscriptionData.isClassFilterMode()) {
+ return true;
+ }
+
+ boolean isRetryTopic = subscriptionData.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX);
+
+ if (!isRetryTopic && ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ return true;
+ }
+
+ ConsumerFilterData realFilterData = this.consumerFilterData;
+ Map<String, String> tempProperties = properties;
+ boolean decoded = false;
+ if (isRetryTopic) {
+ // retry topic, use original filter data.
+ // poor performance to support retry filter.
+ if (tempProperties == null && msgBuffer != null) {
+ decoded = true;
+ tempProperties = MessageDecoder.decodeProperties(msgBuffer);
+ }
+ String realTopic = tempProperties.get(MessageConst.PROPERTY_RETRY_TOPIC);
+ String group = subscriptionData.getTopic().substring(MixAll.RETRY_GROUP_TOPIC_PREFIX.length());
+ realFilterData = this.consumerFilterManager.get(realTopic, group);
+ }
+
+ // no expression
+ if (realFilterData == null || realFilterData.getExpression() == null
+ || realFilterData.getCompiledExpression() == null) {
+ return true;
+ }
+
+ if (!decoded && tempProperties == null && msgBuffer != null) {
+ tempProperties = MessageDecoder.decodeProperties(msgBuffer);
+ }
+
+ Object ret = null;
+ try {
+ MessageEvaluationContext context = new MessageEvaluationContext(tempProperties);
+
+ ret = realFilterData.getCompiledExpression().evaluate(context);
+ } catch (Throwable e) {
+ log.error("Message Filter error, " + realFilterData + ", " + tempProperties, e);
+ }
+
+ log.debug("Pull eval result: {}, {}, {}", ret, realFilterData, tempProperties);
+
+ if (ret == null || !(ret instanceof Boolean)) {
+ return false;
+ }
+
+ return (Boolean) ret;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionMessageFilter.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionMessageFilter.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionMessageFilter.java
new file mode 100644
index 0000000..893df0d
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/ExpressionMessageFilter.java
@@ -0,0 +1,162 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.common.constant.LoggerName;
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.common.message.MessageDecoder;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.filter.util.BitsArray;
+import org.apache.rocketmq.filter.util.BloomFilter;
+import org.apache.rocketmq.store.ConsumeQueueExt;
+import org.apache.rocketmq.store.MessageFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+public class ExpressionMessageFilter implements MessageFilter {
+
+ protected static final Logger log = LoggerFactory.getLogger(LoggerName.FILTER_LOGGER_NAME);
+
+ protected final SubscriptionData subscriptionData;
+ protected final ConsumerFilterData consumerFilterData;
+ protected final ConsumerFilterManager consumerFilterManager;
+ protected final boolean bloomDataValid;
+
+ public ExpressionMessageFilter(SubscriptionData subscriptionData, ConsumerFilterData consumerFilterData,
+ ConsumerFilterManager consumerFilterManager) {
+ this.subscriptionData = subscriptionData;
+ this.consumerFilterData = consumerFilterData;
+ this.consumerFilterManager = consumerFilterManager;
+ if (consumerFilterData == null) {
+ bloomDataValid = false;
+ return;
+ }
+ BloomFilter bloomFilter = this.consumerFilterManager.getBloomFilter();
+ if (bloomFilter != null && bloomFilter.isValid(consumerFilterData.getBloomFilterData())) {
+ bloomDataValid = true;
+ } else {
+ bloomDataValid = false;
+ }
+ }
+
+ @Override
+ public boolean isMatchedByConsumeQueue(Long tagsCode, ConsumeQueueExt.CqExtUnit cqExtUnit) {
+ if (null == subscriptionData) {
+ return true;
+ }
+
+ if (subscriptionData.isClassFilterMode()) {
+ return true;
+ }
+
+ // by tags code.
+ if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+
+ if (tagsCode == null || tagsCode < 0L) {
+ return true;
+ }
+
+ if (subscriptionData.getSubString().equals(SubscriptionData.SUB_ALL)) {
+ return true;
+ }
+
+ return subscriptionData.getCodeSet().contains(tagsCode.intValue());
+ } else {
+ // no expression or no bloom
+ if (consumerFilterData == null || consumerFilterData.getExpression() == null
+ || consumerFilterData.getCompiledExpression() == null || consumerFilterData.getBloomFilterData() == null) {
+ return true;
+ }
+
+ // message is before consumer
+ if (cqExtUnit == null || !consumerFilterData.isMsgInLive(cqExtUnit.getMsgStoreTime())) {
+ log.debug("Pull matched because not in live: {}, {}", consumerFilterData, cqExtUnit);
+ return true;
+ }
+
+ byte[] filterBitMap = cqExtUnit.getFilterBitMap();
+ BloomFilter bloomFilter = this.consumerFilterManager.getBloomFilter();
+ if (filterBitMap == null || !this.bloomDataValid
+ || filterBitMap.length * Byte.SIZE != consumerFilterData.getBloomFilterData().getBitNum()) {
+ return true;
+ }
+
+ BitsArray bitsArray = null;
+ try {
+ bitsArray = BitsArray.create(filterBitMap);
+ boolean ret = bloomFilter.isHit(consumerFilterData.getBloomFilterData(), bitsArray);
+ log.debug("Pull {} by bit map:{}, {}, {}", ret, consumerFilterData, bitsArray, cqExtUnit);
+ return ret;
+ } catch (Throwable e) {
+ log.error("bloom filter error, sub=" + subscriptionData
+ + ", filter=" + consumerFilterData + ", bitMap=" + bitsArray, e);
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean isMatchedByCommitLog(ByteBuffer msgBuffer, Map<String, String> properties) {
+ if (subscriptionData == null) {
+ return true;
+ }
+
+ if (subscriptionData.isClassFilterMode()) {
+ return true;
+ }
+
+ if (ExpressionType.isTagType(subscriptionData.getExpressionType())) {
+ return true;
+ }
+
+ ConsumerFilterData realFilterData = this.consumerFilterData;
+ Map<String, String> tempProperties = properties;
+
+ // no expression
+ if (realFilterData == null || realFilterData.getExpression() == null
+ || realFilterData.getCompiledExpression() == null) {
+ return true;
+ }
+
+ if (tempProperties == null && msgBuffer != null) {
+ tempProperties = MessageDecoder.decodeProperties(msgBuffer);
+ }
+
+ Object ret = null;
+ try {
+ MessageEvaluationContext context = new MessageEvaluationContext(tempProperties);
+
+ ret = realFilterData.getCompiledExpression().evaluate(context);
+ } catch (Throwable e) {
+ log.error("Message Filter error, " + realFilterData + ", " + tempProperties, e);
+ }
+
+ log.debug("Pull eval result: {}, {}, {}", ret, realFilterData, tempProperties);
+
+ if (ret == null || !(ret instanceof Boolean)) {
+ return false;
+ }
+
+ return (Boolean) ret;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/filter/MessageEvaluationContext.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/filter/MessageEvaluationContext.java b/broker/src/main/java/org/apache/rocketmq/broker/filter/MessageEvaluationContext.java
new file mode 100644
index 0000000..879d179
--- /dev/null
+++ b/broker/src/main/java/org/apache/rocketmq/broker/filter/MessageEvaluationContext.java
@@ -0,0 +1,58 @@
+/*
+ * 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.broker.filter;
+
+import org.apache.rocketmq.filter.expression.EvaluationContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Evaluation context from message.
+ */
+public class MessageEvaluationContext implements EvaluationContext {
+
+ private Map<String, String> properties;
+
+ public MessageEvaluationContext(Map<String, String> properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public Object get(final String name) {
+ if (this.properties == null) {
+ return null;
+ }
+ return this.properties.get(name);
+ }
+
+ @Override
+ public Map<String, Object> keyValues() {
+ if (properties == null) {
+ return null;
+ }
+
+ Map<String, Object> copy = new HashMap<String, Object>(properties.size(), 1);
+
+ for (String key : properties.keySet()) {
+ copy.put(key, properties.get(key));
+ }
+
+ return copy;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/NotifyMessageArrivingListener.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/NotifyMessageArrivingListener.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/NotifyMessageArrivingListener.java
index 2dec9f7..fd38c4f 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/NotifyMessageArrivingListener.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/NotifyMessageArrivingListener.java
@@ -19,6 +19,8 @@ package org.apache.rocketmq.broker.longpolling;
import org.apache.rocketmq.store.MessageArrivingListener;
+import java.util.Map;
+
public class NotifyMessageArrivingListener implements MessageArrivingListener {
private final PullRequestHoldService pullRequestHoldService;
@@ -27,7 +29,9 @@ public class NotifyMessageArrivingListener implements MessageArrivingListener {
}
@Override
- public void arriving(String topic, int queueId, long logicOffset, long tagsCode) {
- this.pullRequestHoldService.notifyMessageArriving(topic, queueId, logicOffset, tagsCode);
+ public void arriving(String topic, int queueId, long logicOffset, long tagsCode,
+ long msgStoreTime, byte[] filterBitMap, Map<String, String> properties) {
+ this.pullRequestHoldService.notifyMessageArriving(topic, queueId, logicOffset, tagsCode,
+ msgStoreTime, filterBitMap, properties);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
index b66344f..045ab9b 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequest.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.broker.longpolling;
import io.netty.channel.Channel;
import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.store.MessageFilter;
public class PullRequest {
private final RemotingCommand requestCommand;
@@ -27,15 +28,18 @@ public class PullRequest {
private final long suspendTimestamp;
private final long pullFromThisOffset;
private final SubscriptionData subscriptionData;
+ private final MessageFilter messageFilter;
public PullRequest(RemotingCommand requestCommand, Channel clientChannel, long timeoutMillis, long suspendTimestamp,
- long pullFromThisOffset, SubscriptionData subscriptionData) {
+ long pullFromThisOffset, SubscriptionData subscriptionData,
+ MessageFilter messageFilter) {
this.requestCommand = requestCommand;
this.clientChannel = clientChannel;
this.timeoutMillis = timeoutMillis;
this.suspendTimestamp = suspendTimestamp;
this.pullFromThisOffset = pullFromThisOffset;
this.subscriptionData = subscriptionData;
+ this.messageFilter = messageFilter;
}
public RemotingCommand getRequestCommand() {
@@ -61,4 +65,8 @@ public class PullRequest {
public SubscriptionData getSubscriptionData() {
return subscriptionData;
}
+
+ public MessageFilter getMessageFilter() {
+ return messageFilter;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
index fdba50d..1a53db1 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/longpolling/PullRequestHoldService.java
@@ -18,13 +18,13 @@ package org.apache.rocketmq.broker.longpolling;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.common.ServiceThread;
import org.apache.rocketmq.common.SystemClock;
import org.apache.rocketmq.common.constant.LoggerName;
-import org.apache.rocketmq.store.DefaultMessageFilter;
-import org.apache.rocketmq.store.MessageFilter;
+import org.apache.rocketmq.store.ConsumeQueueExt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,7 +33,6 @@ public class PullRequestHoldService extends ServiceThread {
private static final String TOPIC_QUEUEID_SEPARATOR = "@";
private final BrokerController brokerController;
private final SystemClock systemClock = new SystemClock();
- private final MessageFilter messageFilter = new DefaultMessageFilter();
private ConcurrentHashMap<String/* topic@queueId */, ManyPullRequest> pullRequestTable =
new ConcurrentHashMap<String, ManyPullRequest>(1024);
@@ -110,10 +109,11 @@ public class PullRequestHoldService extends ServiceThread {
}
public void notifyMessageArriving(final String topic, final int queueId, final long maxOffset) {
- notifyMessageArriving(topic, queueId, maxOffset, null);
+ notifyMessageArriving(topic, queueId, maxOffset, null, 0, null, null);
}
- public void notifyMessageArriving(final String topic, final int queueId, final long maxOffset, final Long tagsCode) {
+ public void notifyMessageArriving(final String topic, final int queueId, final long maxOffset, final Long tagsCode,
+ long msgStoreTime, byte[] filterBitMap, Map<String, String> properties) {
String key = this.buildKey(topic, queueId);
ManyPullRequest mpr = this.pullRequestTable.get(key);
if (mpr != null) {
@@ -128,7 +128,14 @@ public class PullRequestHoldService extends ServiceThread {
}
if (newestOffset > request.getPullFromThisOffset()) {
- if (this.messageFilter.isMessageMatched(request.getSubscriptionData(), tagsCode)) {
+ boolean match = request.getMessageFilter().isMatchedByConsumeQueue(tagsCode,
+ new ConsumeQueueExt.CqExtUnit(tagsCode, msgStoreTime, filterBitMap));
+ // match by bit map, need eval again when properties is not null.
+ if (match && properties != null) {
+ match = request.getMessageFilter().isMatchedByCommitLog(null, properties);
+ }
+
+ if (match) {
try {
this.brokerController.getPullMessageProcessor().executeRequestWhenWakeup(request.getClientChannel(),
request.getRequestCommand());
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
index 039c942..6c2a987 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/out/BrokerOuterAPI.java
@@ -50,7 +50,7 @@ import org.slf4j.LoggerFactory;
public class BrokerOuterAPI {
private static final Logger log = LoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
private final RemotingClient remotingClient;
- private final TopAddressing topAddressing = new TopAddressing(MixAll.WS_ADDR);
+ private final TopAddressing topAddressing = new TopAddressing(MixAll.getWSAddr());
private String nameSrvAddr = null;
public BrokerOuterAPI(final NettyClientConfig nettyClientConfig) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java b/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
index 00257fd..8ded973 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/plugin/AbstractPluginMessageStore.java
@@ -18,11 +18,14 @@
package org.apache.rocketmq.broker.plugin;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.Set;
import org.apache.rocketmq.common.message.MessageExt;
-import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.store.CommitLogDispatcher;
+import org.apache.rocketmq.store.ConsumeQueue;
import org.apache.rocketmq.store.GetMessageResult;
import org.apache.rocketmq.store.MessageExtBrokerInner;
+import org.apache.rocketmq.store.MessageFilter;
import org.apache.rocketmq.store.MessageStore;
import org.apache.rocketmq.store.PutMessageResult;
import org.apache.rocketmq.store.QueryMessageResult;
@@ -84,8 +87,8 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
@Override
public GetMessageResult getMessage(String group, String topic, int queueId, long offset,
- int maxMsgNums, SubscriptionData subscriptionData) {
- return next.getMessage(group, topic, queueId, offset, maxMsgNums, subscriptionData);
+ int maxMsgNums, final MessageFilter messageFilter) {
+ return next.getMessage(group, topic, queueId, offset, maxMsgNums, messageFilter);
}
@Override
@@ -234,4 +237,13 @@ public abstract class AbstractPluginMessageStore implements MessageStore {
next.setConfirmOffset(phyOffset);
}
+ @Override
+ public LinkedList<CommitLogDispatcher> getDispatcherList() {
+ return next.getDispatcherList();
+ }
+
+ @Override
+ public ConsumeQueue getConsumeQueue(String topic, int queueId) {
+ return next.getConsumeQueue(topic, queueId);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
----------------------------------------------------------------------
diff --git a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
index e35316d..daea53c 100644
--- a/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
+++ b/broker/src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.broker.processor;
+import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import java.io.UnsupportedEncodingException;
@@ -32,6 +33,8 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.rocketmq.broker.BrokerController;
import org.apache.rocketmq.broker.client.ClientChannelInfo;
import org.apache.rocketmq.broker.client.ConsumerGroupInfo;
+import org.apache.rocketmq.broker.filter.ConsumerFilterData;
+import org.apache.rocketmq.broker.filter.ExpressionMessageFilter;
import org.apache.rocketmq.common.MQVersion;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.common.TopicConfig;
@@ -49,6 +52,7 @@ import org.apache.rocketmq.common.protocol.ResponseCode;
import org.apache.rocketmq.common.protocol.body.BrokerStatsData;
import org.apache.rocketmq.common.protocol.body.BrokerStatsItem;
import org.apache.rocketmq.common.protocol.body.Connection;
+import org.apache.rocketmq.common.protocol.body.ConsumeQueueData;
import org.apache.rocketmq.common.protocol.body.ConsumeStatsList;
import org.apache.rocketmq.common.protocol.body.ConsumerConnection;
import org.apache.rocketmq.common.protocol.body.GroupList;
@@ -56,6 +60,7 @@ import org.apache.rocketmq.common.protocol.body.KVTable;
import org.apache.rocketmq.common.protocol.body.LockBatchRequestBody;
import org.apache.rocketmq.common.protocol.body.LockBatchResponseBody;
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
+import org.apache.rocketmq.common.protocol.body.QueryConsumeQueueResponseBody;
import org.apache.rocketmq.common.protocol.body.QueryConsumeTimeSpanBody;
import org.apache.rocketmq.common.protocol.body.QueryCorrectionOffsetBody;
import org.apache.rocketmq.common.protocol.body.QueueTimeSpan;
@@ -81,6 +86,7 @@ import org.apache.rocketmq.common.protocol.header.GetMinOffsetRequestHeader;
import org.apache.rocketmq.common.protocol.header.GetMinOffsetResponseHeader;
import org.apache.rocketmq.common.protocol.header.GetProducerConnectionListRequestHeader;
import org.apache.rocketmq.common.protocol.header.GetTopicStatsInfoRequestHeader;
+import org.apache.rocketmq.common.protocol.header.QueryConsumeQueueRequestHeader;
import org.apache.rocketmq.common.protocol.header.QueryConsumeTimeSpanRequestHeader;
import org.apache.rocketmq.common.protocol.header.QueryCorrectionOffsetHeader;
import org.apache.rocketmq.common.protocol.header.QueryTopicConsumeByWhoRequestHeader;
@@ -94,6 +100,7 @@ import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.common.stats.StatsItem;
import org.apache.rocketmq.common.stats.StatsSnapshot;
import org.apache.rocketmq.common.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.filter.util.BitsArray;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingCommandException;
import org.apache.rocketmq.remoting.exception.RemotingTimeoutException;
@@ -101,7 +108,10 @@ import org.apache.rocketmq.remoting.netty.NettyRequestProcessor;
import org.apache.rocketmq.remoting.protocol.LanguageCode;
import org.apache.rocketmq.remoting.protocol.RemotingCommand;
import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+import org.apache.rocketmq.store.ConsumeQueue;
+import org.apache.rocketmq.store.ConsumeQueueExt;
import org.apache.rocketmq.store.DefaultMessageStore;
+import org.apache.rocketmq.store.MessageFilter;
import org.apache.rocketmq.store.SelectMappedBufferResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -187,6 +197,8 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
return ViewBrokerStatsData(ctx, request);
case RequestCode.GET_BROKER_CONSUME_STATS:
return fetchAllConsumeStatsInBroker(ctx, request);
+ case RequestCode.QUERY_CONSUME_QUEUE:
+ return queryConsumeQueue(ctx, request);
default:
break;
}
@@ -1244,4 +1256,83 @@ public class AdminBrokerProcessor implements NettyRequestProcessor {
}
}
+ private RemotingCommand queryConsumeQueue(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {
+ QueryConsumeQueueRequestHeader requestHeader =
+ (QueryConsumeQueueRequestHeader) request.decodeCommandCustomHeader(QueryConsumeQueueRequestHeader.class);
+
+ RemotingCommand response = RemotingCommand.createResponseCommand(null);
+
+ ConsumeQueue consumeQueue = this.brokerController.getMessageStore().getConsumeQueue(requestHeader.getTopic(),
+ requestHeader.getQueueId());
+ if (consumeQueue == null) {
+ response.setCode(ResponseCode.SYSTEM_ERROR);
+ response.setRemark(String.format("%d@%s is not exist!", requestHeader.getQueueId(), requestHeader.getTopic()));
+ return response;
+ }
+
+ QueryConsumeQueueResponseBody body = new QueryConsumeQueueResponseBody();
+ response.setCode(ResponseCode.SUCCESS);
+ response.setBody(body.encode());
+
+ body.setMaxQueueIndex(consumeQueue.getMaxOffsetInQueue());
+ body.setMinQueueIndex(consumeQueue.getMinOffsetInQueue());
+
+ MessageFilter messageFilter = null;
+ if (requestHeader.getConsumerGroup() != null) {
+ SubscriptionData subscriptionData = this.brokerController.getConsumerManager().findSubscriptionData(
+ requestHeader.getConsumerGroup(), requestHeader.getTopic()
+ );
+ body.setSubscriptionData(subscriptionData);
+ if (subscriptionData == null) {
+ body.setFilterData(String.format("%s@%s is not online!", requestHeader.getConsumerGroup(), requestHeader.getTopic()));
+ } else {
+ ConsumerFilterData filterData = this.brokerController.getConsumerFilterManager()
+ .get(requestHeader.getTopic(), requestHeader.getConsumerGroup());
+ body.setFilterData(JSON.toJSONString(filterData, true));
+
+ messageFilter = new ExpressionMessageFilter(subscriptionData, filterData,
+ this.brokerController.getConsumerFilterManager());
+ }
+ }
+
+ SelectMappedBufferResult result = consumeQueue.getIndexBuffer(requestHeader.getIndex());
+ if (result == null) {
+ response.setRemark(String.format("Index %d of %d@%s is not exist!", requestHeader.getIndex(), requestHeader.getQueueId(), requestHeader.getTopic()));
+ return response;
+ }
+ try {
+ List<ConsumeQueueData> queues = new ArrayList<>();
+ for (int i = 0; i < result.getSize() && i < requestHeader.getCount() * ConsumeQueue.CQ_STORE_UNIT_SIZE; i += ConsumeQueue.CQ_STORE_UNIT_SIZE) {
+ ConsumeQueueData one = new ConsumeQueueData();
+ one.setPhysicOffset(result.getByteBuffer().getLong());
+ one.setPhysicSize(result.getByteBuffer().getInt());
+ one.setTagsCode(result.getByteBuffer().getLong());
+
+ if (!consumeQueue.isExtAddr(one.getTagsCode())) {
+ queues.add(one);
+ continue;
+ }
+
+ ConsumeQueueExt.CqExtUnit cqExtUnit = consumeQueue.getExt(one.getTagsCode());
+ if (cqExtUnit != null) {
+ one.setExtendDataJson(JSON.toJSONString(cqExtUnit));
+ if (cqExtUnit.getFilterBitMap() != null) {
+ one.setBitMap(BitsArray.create(cqExtUnit.getFilterBitMap()).toString());
+ }
+ if (messageFilter != null) {
+ one.setEval(messageFilter.isMatchedByConsumeQueue(cqExtUnit.getTagsCode(), cqExtUnit));
+ }
+ } else {
+ one.setMsg("Cq extend not exist!addr: " + one.getTagsCode());
+ }
+
+ queues.add(one);
+ }
+ body.setQueueData(queues);
+ } finally {
+ result.release();
+ }
+
+ return response;
+ }
}
[28/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-189]
Misleading tip on consumeTimestamp and wrong consumeTimestamp exception
message closes apache/incubator-rocketmq#97
Posted by do...@apache.org.
[ROCKETMQ-189] Misleading tip on consumeTimestamp and wrong consumeTimestamp exception message closes apache/incubator-rocketmq#97
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/99ce40a7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/99ce40a7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/99ce40a7
Branch: refs/heads/release-4.1.0-incubating
Commit: 99ce40a72382dd5b7ecb5eb5717b8daf84a90682
Parents: 8280388
Author: lindzh <li...@163.com>
Authored: Fri May 26 15:28:28 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri May 26 15:28:28 2017 +0800
----------------------------------------------------------------------
.../client/impl/consumer/DefaultMQPushConsumerImpl.java | 8 ++++----
.../rocketmq/client/impl/consumer/RebalancePushImpl.java | 2 +-
common/src/main/java/org/apache/rocketmq/common/UtilAll.java | 2 +-
.../org/apache/rocketmq/example/simple/PushConsumer.java | 2 ++
4 files changed, 8 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/99ce40a7/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
index 2cafe29..8767964 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultMQPushConsumerImpl.java
@@ -655,12 +655,12 @@ public class DefaultMQPushConsumerImpl implements MQConsumerInner {
null);
}
- Date dt = UtilAll.parseDate(this.defaultMQPushConsumer.getConsumeTimestamp(), UtilAll.YYYY_MMDD_HHMMSS);
+ Date dt = UtilAll.parseDate(this.defaultMQPushConsumer.getConsumeTimestamp(), UtilAll.YYYYMMDDHHMMSS);
if (null == dt) {
throw new MQClientException(
- "consumeTimestamp is invalid, YYYY_MMDD_HHMMSS"
- + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL),
- null);
+ "consumeTimestamp is invalid, the valid format is yyyyMMddHHmmss,but received "
+ + this.defaultMQPushConsumer.getConsumeTimestamp()
+ + " " + FAQUrl.suggestTodo(FAQUrl.CLIENT_PARAMETER_CHECK_URL), null);
}
// allocateMessageQueueStrategy
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/99ce40a7/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
index 509c9a4..112bcee 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
@@ -171,7 +171,7 @@ public class RebalancePushImpl extends RebalanceImpl {
} else {
try {
long timestamp = UtilAll.parseDate(this.defaultMQPushConsumerImpl.getDefaultMQPushConsumer().getConsumeTimestamp(),
- UtilAll.YYYY_MMDD_HHMMSS).getTime();
+ UtilAll.YYYYMMDDHHMMSS).getTime();
result = this.mQClientFactory.getMQAdminImpl().searchOffset(mq, timestamp);
} catch (MQClientException e) {
result = -1;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/99ce40a7/common/src/main/java/org/apache/rocketmq/common/UtilAll.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/UtilAll.java b/common/src/main/java/org/apache/rocketmq/common/UtilAll.java
index 016da0b..e9d926f 100644
--- a/common/src/main/java/org/apache/rocketmq/common/UtilAll.java
+++ b/common/src/main/java/org/apache/rocketmq/common/UtilAll.java
@@ -41,7 +41,7 @@ import org.apache.rocketmq.remoting.common.RemotingHelper;
public class UtilAll {
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd#HH:mm:ss:SSS";
- public static final String YYYY_MMDD_HHMMSS = "yyyyMMddHHmmss";
+ public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
public static int getPid() {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/99ce40a7/example/src/main/java/org/apache/rocketmq/example/simple/PushConsumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/simple/PushConsumer.java b/example/src/main/java/org/apache/rocketmq/example/simple/PushConsumer.java
index d03c2c5..c8252d0 100644
--- a/example/src/main/java/org/apache/rocketmq/example/simple/PushConsumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/simple/PushConsumer.java
@@ -31,6 +31,8 @@ public class PushConsumer {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_JODIE_1");
consumer.subscribe("Jodie_topic_1023", "*");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+ //wrong time format 2017_0422_221800
+ consumer.setConsumeTimestamp("20170422221800");
consumer.registerMessageListener(new MessageListenerConcurrently() {
/**
[34/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-200]-Cluster
name is always missing when fetch ClusterInfo from name server closes
apache/incubator-rocketmq#105
Posted by do...@apache.org.
[ROCKETMQ-200]-Cluster name is always missing when fetch ClusterInfo from name server closes apache/incubator-rocketmq#105
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/c7961407
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/c7961407
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/c7961407
Branch: refs/heads/release-4.1.0-incubating
Commit: c79614071b1941940f934c066bde5711062bdc7e
Parents: 8c8610f
Author: Jaskey <li...@gmail.com>
Authored: Sat May 27 11:24:02 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 11:24:02 2017 +0800
----------------------------------------------------------------------
.../rocketmq/common/protocol/route/BrokerData.java | 14 +++++++++++---
.../rocketmq/namesrv/routeinfo/RouteInfoManager.java | 10 ++--------
2 files changed, 13 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c7961407/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java
index 612e5b4..9d868ae 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/route/BrokerData.java
@@ -15,9 +15,7 @@
* limitations under the License.
*/
-/**
- * $Id: BrokerData.java 1835 2013-05-16 02:00:50Z vintagewang@apache.org $
- */
+
package org.apache.rocketmq.common.protocol.route;
import java.util.HashMap;
@@ -29,6 +27,16 @@ public class BrokerData implements Comparable<BrokerData> {
private String brokerName;
private HashMap<Long/* brokerId */, String/* broker address */> brokerAddrs;
+ public BrokerData() {
+
+ }
+
+ public BrokerData(String cluster, String brokerName, HashMap<Long, String> brokerAddrs) {
+ this.cluster = cluster;
+ this.brokerName = brokerName;
+ this.brokerAddrs = brokerAddrs;
+ }
+
public String selectBrokerAddr() {
String value = this.brokerAddrs.get(MixAll.MASTER_ID);
if (null == value) {
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/c7961407/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
----------------------------------------------------------------------
diff --git a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
index 16b7847..5a953a9 100644
--- a/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
+++ b/namesrv/src/main/java/org/apache/rocketmq/namesrv/routeinfo/RouteInfoManager.java
@@ -125,11 +125,7 @@ public class RouteInfoManager {
BrokerData brokerData = this.brokerAddrTable.get(brokerName);
if (null == brokerData) {
registerFirst = true;
- brokerData = new BrokerData();
- brokerData.setBrokerName(brokerName);
- HashMap<Long, String> brokerAddrs = new HashMap<Long, String>();
- brokerData.setBrokerAddrs(brokerAddrs);
-
+ brokerData = new BrokerData(clusterName, brokerName, new HashMap<Long, String>());
this.brokerAddrTable.put(brokerName, brokerData);
}
String oldAddr = brokerData.getBrokerAddrs().put(brokerId, brokerAddr);
@@ -381,9 +377,7 @@ public class RouteInfoManager {
for (String brokerName : brokerNameSet) {
BrokerData brokerData = this.brokerAddrTable.get(brokerName);
if (null != brokerData) {
- BrokerData brokerDataClone = new BrokerData();
- brokerDataClone.setBrokerName(brokerData.getBrokerName());
- brokerDataClone.setBrokerAddrs((HashMap<Long, String>) brokerData
+ BrokerData brokerDataClone = new BrokerData(brokerData.getCluster(), brokerData.getBrokerName(), (HashMap<Long, String>) brokerData
.getBrokerAddrs().clone());
brokerDataList.add(brokerDataClone);
foundBrokerData = true;
[29/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-194] log
appender support closes apache/incubator-rocketmq#101
Posted by do...@apache.org.
[ROCKETMQ-194] log appender support closes apache/incubator-rocketmq#101
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/37fbb7be
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/37fbb7be
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/37fbb7be
Branch: refs/heads/release-4.1.0-incubating
Commit: 37fbb7be8ae2a932f14006a2c08e3247143f75ea
Parents: 99ce40a
Author: lindzh <li...@163.com>
Authored: Fri May 26 16:12:16 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri May 26 16:12:16 2017 +0800
----------------------------------------------------------------------
logappender/pom.xml | 86 +++++++
.../logappender/common/ProducerInstance.java | 93 ++++++++
.../log4j/RocketmqLog4jAppender.java | 194 +++++++++++++++
.../log4j2/RocketmqLog4j2Appender.java | 233 +++++++++++++++++++
.../logback/RocketmqLogbackAppender.java | 183 +++++++++++++++
.../rocketmq/logappender/AbstractTestCase.java | 154 ++++++++++++
.../logappender/Log4jPropertiesTest.java | 32 +++
.../apache/rocketmq/logappender/Log4jTest.java | 43 ++++
.../rocketmq/logappender/Log4jXmlTest.java | 32 +++
.../rocketmq/logappender/LogbackTest.java | 54 +++++
.../apache/rocketmq/logappender/log4j2Test.java | 44 ++++
.../src/test/resources/log4j-example.properties | 38 +++
.../src/test/resources/log4j-example.xml | 62 +++++
.../src/test/resources/log4j2-example.xml | 41 ++++
.../src/test/resources/logback-example.xml | 89 +++++++
pom.xml | 11 +
style/rmq_checkstyle.xml | 6 +
17 files changed, 1395 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/pom.xml
----------------------------------------------------------------------
diff --git a/logappender/pom.xml b/logappender/pom.xml
new file mode 100644
index 0000000..5974c75
--- /dev/null
+++ b/logappender/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.apache.rocketmq</groupId>
+ <artifactId>rocketmq-all</artifactId>
+ <version>4.1.0-incubating-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>rocketmq-logappender</artifactId>
+ <packaging>jar</packaging>
+ <name>rocketmq-logappender ${project.version}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-core</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-client</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-namesrv</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-broker</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ </dependencies>
+
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/main/java/org/apache/rocketmq/logappender/common/ProducerInstance.java
----------------------------------------------------------------------
diff --git a/logappender/src/main/java/org/apache/rocketmq/logappender/common/ProducerInstance.java b/logappender/src/main/java/org/apache/rocketmq/logappender/common/ProducerInstance.java
new file mode 100644
index 0000000..669e30c
--- /dev/null
+++ b/logappender/src/main/java/org/apache/rocketmq/logappender/common/ProducerInstance.java
@@ -0,0 +1,93 @@
+/*
+ * 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.logappender.common;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.MQProducer;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Common Producer component
+ */
+public class ProducerInstance {
+
+ public static final String APPENDER_TYPE = "APPENDER_TYPE";
+
+ public static final String LOG4J_APPENDER = "LOG4J_APPENDER";
+
+ public static final String LOG4J2_APPENDER = "LOG4J2_APPENDER";
+
+ public static final String LOGBACK_APPENDER = "LOGBACK_APPENDER";
+
+ public static final String DEFAULT_GROUP = "rocketmq_appender";
+
+ private static ConcurrentHashMap<String, MQProducer> producerMap = new ConcurrentHashMap<String, MQProducer>();
+
+ private static String genKey(String nameServerAddress, String group) {
+ return nameServerAddress + "_" + group;
+ }
+
+
+ public static MQProducer getInstance(String nameServerAddress, String group) throws MQClientException {
+ if (group == null) {
+ group = DEFAULT_GROUP;
+ }
+
+ String genKey = genKey(nameServerAddress, group);
+ MQProducer p = producerMap.get(genKey);
+ if (p != null) {
+ return p;
+ }
+
+ DefaultMQProducer defaultMQProducer = new DefaultMQProducer(group);
+ defaultMQProducer.setNamesrvAddr(nameServerAddress);
+ MQProducer beforeProducer = null;
+ //cas put producer
+ beforeProducer = producerMap.putIfAbsent(genKey, defaultMQProducer);
+ if (beforeProducer != null) {
+ return beforeProducer;
+ }
+ defaultMQProducer.start();
+ return defaultMQProducer;
+ }
+
+
+ public static void removeAndClose(String nameServerAddress, String group) {
+ if (group == null) {
+ group = DEFAULT_GROUP;
+ }
+ String genKey = genKey(nameServerAddress, group);
+ MQProducer producer = producerMap.remove(genKey);
+
+ if (producer != null) {
+ producer.shutdown();
+ }
+ }
+
+ public static void closeAll() {
+ Set<Map.Entry<String, MQProducer>> entries = producerMap.entrySet();
+ for (Map.Entry<String, MQProducer> entry : entries) {
+ producerMap.remove(entry.getKey());
+ entry.getValue().shutdown();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/main/java/org/apache/rocketmq/logappender/log4j/RocketmqLog4jAppender.java
----------------------------------------------------------------------
diff --git a/logappender/src/main/java/org/apache/rocketmq/logappender/log4j/RocketmqLog4jAppender.java b/logappender/src/main/java/org/apache/rocketmq/logappender/log4j/RocketmqLog4jAppender.java
new file mode 100644
index 0000000..b2983b6
--- /dev/null
+++ b/logappender/src/main/java/org/apache/rocketmq/logappender/log4j/RocketmqLog4jAppender.java
@@ -0,0 +1,194 @@
+/*
+ * 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.logappender.log4j;
+
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.logappender.common.ProducerInstance;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.ErrorCode;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.rocketmq.client.producer.MQProducer;
+
+/**
+ * Log4j Appender Component
+ */
+public class RocketmqLog4jAppender extends AppenderSkeleton {
+
+ /**
+ * Appended message tag define
+ */
+ private String tag;
+
+ /**
+ * Whitch topic to send log messages
+ */
+ private String topic;
+
+ private boolean locationInfo;
+
+ /**
+ * Log producer send instance
+ */
+ private MQProducer producer;
+
+ /**
+ * RocketMQ nameserver address
+ */
+ private String nameServerAddress;
+
+ /**
+ * Log producer group
+ */
+ private String producerGroup;
+
+ public RocketmqLog4jAppender() {
+ }
+
+
+ public void activateOptions() {
+ LogLog.debug("Getting initial context.");
+ if (!checkEntryConditions()) {
+ return;
+ }
+ try {
+ producer = ProducerInstance.getInstance(nameServerAddress, producerGroup);
+ } catch (Exception e) {
+ LogLog.error("activateOptions nameserver:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+ }
+
+
+ /**
+ * Info,error,warn,callback method implementation
+ *
+ * @param event
+ */
+ public void append(LoggingEvent event) {
+ if (null == producer) {
+ return;
+ }
+ if (locationInfo) {
+ event.getLocationInformation();
+ }
+ byte[] data = this.layout.format(event).getBytes();
+ try {
+ Message msg = new Message(topic, tag, data);
+ msg.getProperties().put(ProducerInstance.APPENDER_TYPE, ProducerInstance.LOG4J_APPENDER);
+
+ //Send message and do not wait for the ack from the message broker.
+ producer.sendOneway(msg);
+ } catch (Exception e) {
+ String msg = new String(data);
+ errorHandler.error("Could not send message in RocketmqLog4jAppender [" + name + "].Message is :" + msg, e,
+ ErrorCode.GENERIC_FAILURE);
+ }
+ }
+
+ protected boolean checkEntryConditions() {
+ String fail = null;
+
+ if (this.topic == null) {
+ fail = "No topic";
+ } else if (this.tag == null) {
+ fail = "No tag";
+ }
+
+ if (fail != null) {
+ errorHandler.error(fail + " for RocketmqLog4jAppender named [" + name + "].");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * When system exit,this method will be called to close resources
+ */
+ public synchronized void close() {
+ // The synchronized modifier avoids concurrent append and close operations
+
+ if (this.closed)
+ return;
+
+ LogLog.debug("Closing RocketmqLog4jAppender [" + name + "].");
+ this.closed = true;
+
+ try {
+ ProducerInstance.removeAndClose(this.nameServerAddress, this.producerGroup);
+ } catch (Exception e) {
+ LogLog.error("Closing RocketmqLog4jAppender [" + name + "] nameServerAddress:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+ // Help garbage collection
+ producer = null;
+ }
+
+ public boolean requiresLayout() {
+ return true;
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ /**
+ * Returns value of the <b>LocationInfo</b> property which
+ * determines whether location (stack) info is sent to the remote
+ * subscriber.
+ */
+ public boolean isLocationInfo() {
+ return locationInfo;
+ }
+
+ /**
+ * If true, the information sent to the remote subscriber will
+ * include caller's location information. By default no location
+ * information is sent to the subscriber.
+ */
+ public void setLocationInfo(boolean locationInfo) {
+ this.locationInfo = locationInfo;
+ }
+
+ /**
+ * Returns the message producer,Only valid after
+ * activateOptions() method has been invoked.
+ */
+ protected MQProducer getProducer() {
+ return producer;
+ }
+
+ public void setNameServerAddress(String nameServerAddress) {
+ this.nameServerAddress = nameServerAddress;
+ }
+
+ public void setProducerGroup(String producerGroup) {
+ this.producerGroup = producerGroup;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/main/java/org/apache/rocketmq/logappender/log4j2/RocketmqLog4j2Appender.java
----------------------------------------------------------------------
diff --git a/logappender/src/main/java/org/apache/rocketmq/logappender/log4j2/RocketmqLog4j2Appender.java b/logappender/src/main/java/org/apache/rocketmq/logappender/log4j2/RocketmqLog4j2Appender.java
new file mode 100644
index 0000000..fb8341f
--- /dev/null
+++ b/logappender/src/main/java/org/apache/rocketmq/logappender/log4j2/RocketmqLog4j2Appender.java
@@ -0,0 +1,233 @@
+/*
+ * 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.logappender.log4j2;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.ErrorHandler;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.logappender.common.ProducerInstance;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
+import org.apache.logging.log4j.core.layout.SerializedLayout;
+import org.apache.rocketmq.client.producer.MQProducer;
+
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Log4j2 Appender Component
+ */
+@Plugin(name = "RocketMQ",
+ category = Node.CATEGORY,
+ elementType = Appender.ELEMENT_TYPE,
+ printObject = true)
+public class RocketmqLog4j2Appender extends AbstractAppender {
+
+ /**
+ * RocketMQ nameserver address
+ */
+ private String nameServerAddress;
+
+ /**
+ * Log producer group
+ */
+ private String producerGroup;
+
+ /**
+ * Log producer send instance
+ */
+ private MQProducer producer;
+
+ /**
+ * Appended message tag define
+ */
+ private String tag;
+
+ /**
+ * Whitch topic to send log messages
+ */
+ private String topic;
+
+
+ protected RocketmqLog4j2Appender(String name, Filter filter, Layout<? extends Serializable> layout,
+ boolean ignoreExceptions, String nameServerAddress, String producerGroup,
+ String topic, String tag) {
+ super(name, filter, layout, ignoreExceptions);
+ this.producer = producer;
+ this.topic = topic;
+ this.tag = tag;
+ this.nameServerAddress = nameServerAddress;
+ this.producerGroup = producerGroup;
+ try {
+ this.producer = ProducerInstance.getInstance(this.nameServerAddress, this.producerGroup);
+ } catch (Exception e) {
+ ErrorHandler handler = this.getHandler();
+ if (handler != null) {
+ handler.error("Starting RocketmqLog4j2Appender [" + this.getName()
+ + "] nameServerAddress:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Info,error,warn,callback method implementation
+ *
+ * @param event
+ */
+ public void append(LogEvent event) {
+ if (null == producer) {
+ return;
+ }
+ byte[] data = this.getLayout().toByteArray(event);
+ try {
+ Message msg = new Message(topic, tag, data);
+ msg.getProperties().put(ProducerInstance.APPENDER_TYPE, ProducerInstance.LOG4J2_APPENDER);
+
+ //Send message and do not wait for the ack from the message broker.
+ producer.sendOneway(msg);
+ } catch (Exception e) {
+ ErrorHandler handler = this.getHandler();
+ if (handler != null) {
+ String msg = new String(data);
+ handler.error("Could not send message in RocketmqLog4j2Appender [" + this.getName() + "].Message is : " + msg, e);
+ }
+
+ }
+ }
+
+ /**
+ * When system exit,this method will be called to close resources
+ *
+ * @param timeout
+ * @param timeUnit
+ * @return
+ */
+ public boolean stop(long timeout, TimeUnit timeUnit) {
+ this.setStopping();
+ try {
+ ProducerInstance.removeAndClose(this.nameServerAddress, this.producerGroup);
+ } catch (Exception e) {
+ ErrorHandler handler = this.getHandler();
+ if (handler != null) {
+ handler.error("Closeing RocketmqLog4j2Appender [" + this.getName()
+ + "] nameServerAddress:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+ }
+
+ boolean stopped = super.stop(timeout, timeUnit, false);
+ this.setStopped();
+ return stopped;
+ }
+
+ /**
+ * Log4j2 builder creator
+ */
+ @PluginBuilderFactory
+ public static RocketmqLog4j2Appender.Builder newBuilder() {
+ return new RocketmqLog4j2Appender.Builder();
+ }
+
+ /**
+ * Log4j2 xml builder define
+ */
+ public static class Builder implements org.apache.logging.log4j.core.util.Builder<RocketmqLog4j2Appender> {
+
+ @PluginBuilderAttribute
+ @Required(message = "A name for the RocketmqLog4j2Appender must be specified")
+ private String name;
+
+ @PluginElement("Layout")
+ private Layout<? extends Serializable> layout;
+
+ @PluginElement("Filter")
+ private Filter filter;
+
+ @PluginBuilderAttribute
+ private boolean ignoreExceptions;
+
+ @PluginBuilderAttribute
+ private String tag;
+
+ @PluginBuilderAttribute
+ private String nameServerAddress;
+
+ @PluginBuilderAttribute
+ private String producerGroup;
+
+ @PluginBuilderAttribute
+ @Required(message = "A topic name must be specified")
+ private String topic;
+
+ private Builder() {
+ this.layout = SerializedLayout.createLayout();
+ this.ignoreExceptions = true;
+ }
+
+ public RocketmqLog4j2Appender.Builder setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setLayout(Layout<? extends Serializable> layout) {
+ this.layout = layout;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setFilter(Filter filter) {
+ this.filter = filter;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setIgnoreExceptions(boolean ignoreExceptions) {
+ this.ignoreExceptions = ignoreExceptions;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setTag(final String tag) {
+ this.tag = tag;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setTopic(final String topic) {
+ this.topic = topic;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setNameServerAddress(String nameServerAddress) {
+ this.nameServerAddress = nameServerAddress;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender.Builder setProducerGroup(String producerGroup) {
+ this.producerGroup = producerGroup;
+ return this;
+ }
+
+ public RocketmqLog4j2Appender build() {
+ return new RocketmqLog4j2Appender(name, filter, layout, ignoreExceptions,
+ nameServerAddress, producerGroup, topic, tag);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/main/java/org/apache/rocketmq/logappender/logback/RocketmqLogbackAppender.java
----------------------------------------------------------------------
diff --git a/logappender/src/main/java/org/apache/rocketmq/logappender/logback/RocketmqLogbackAppender.java b/logappender/src/main/java/org/apache/rocketmq/logappender/logback/RocketmqLogbackAppender.java
new file mode 100644
index 0000000..cb45522
--- /dev/null
+++ b/logappender/src/main/java/org/apache/rocketmq/logappender/logback/RocketmqLogbackAppender.java
@@ -0,0 +1,183 @@
+/*
+ * 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.logappender.logback;
+
+import ch.qos.logback.classic.net.LoggingEventPreSerializationTransformer;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.Layout;
+import ch.qos.logback.core.spi.PreSerializationTransformer;
+import ch.qos.logback.core.status.ErrorStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.logappender.common.ProducerInstance;
+import org.apache.rocketmq.client.producer.MQProducer;
+
+/**
+ * Logback Appender Component
+ */
+public class RocketmqLogbackAppender extends AppenderBase<ILoggingEvent> {
+
+ /**
+ * Message tag define
+ */
+ private String tag;
+
+ /**
+ * Whitch topic to send log messages
+ */
+ private String topic;
+
+ /**
+ * RocketMQ nameserver address
+ */
+ private String nameServerAddress;
+
+ /**
+ * Log producer group
+ */
+ private String producerGroup;
+
+ /**
+ * Log producer send instance
+ */
+ private MQProducer producer;
+
+ private Layout layout;
+
+ private PreSerializationTransformer<ILoggingEvent> pst = new LoggingEventPreSerializationTransformer();
+
+ /**
+ * Info,error,warn,callback method implementation
+ *
+ * @param event
+ */
+ @Override
+ protected void append(ILoggingEvent event) {
+ if (!isStarted()) {
+ return;
+ }
+ String logStr = this.layout.doLayout(event);
+ try {
+ Message msg = new Message(topic, tag, logStr.getBytes());
+ msg.getProperties().put(ProducerInstance.APPENDER_TYPE, ProducerInstance.LOGBACK_APPENDER);
+
+ //Send message and do not wait for the ack from the message broker.
+ producer.sendOneway(msg);
+ } catch (Exception e) {
+ addError("Could not send message in RocketmqLogbackAppender [" + name + "]. Message is : " + logStr, e);
+ }
+ }
+
+ /**
+ * Options are activated and become effective only after calling this method.
+ */
+ public void start() {
+ int errors = 0;
+
+ if (this.layout == null) {
+ addStatus(new ErrorStatus("No layout set for the RocketmqLogbackAppender named \"" + name + "\".", this));
+ errors++;
+ }
+
+ if (errors > 0 || !checkEntryConditions()) {
+ return;
+ }
+ try {
+ producer = ProducerInstance.getInstance(nameServerAddress, producerGroup);
+ } catch (Exception e) {
+ addError("Starting RocketmqLogbackAppender [" + this.getName()
+ + "] nameServerAddress:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+ if (producer != null) {
+ super.start();
+ }
+ }
+
+ /**
+ * When system exit,this method will be called to close resources
+ */
+ public synchronized void stop() {
+ // The synchronized modifier avoids concurrent append and close operations
+ if (!this.started) {
+ return;
+ }
+
+ this.started = false;
+
+ try {
+ ProducerInstance.removeAndClose(this.nameServerAddress, this.producerGroup);
+ } catch (Exception e) {
+ addError("Closeing RocketmqLogbackAppender [" + this.getName()
+ + "] nameServerAddress:" + nameServerAddress + " group:" + producerGroup + " " + e.getMessage());
+ }
+
+ // Help garbage collection
+ producer = null;
+ }
+
+ protected boolean checkEntryConditions() {
+ String fail = null;
+
+ if (this.topic == null) {
+ fail = "No topic";
+ }
+
+ if (fail != null) {
+ addError(fail + " for RocketmqLogbackAppender named [" + name + "].");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+ public Layout getLayout() {
+ return this.layout;
+ }
+
+ /**
+ * Set the pattern layout to format the log.
+ */
+ public void setLayout(Layout layout) {
+ this.layout = layout;
+ }
+
+ public String getTag() {
+ return tag;
+ }
+
+
+ public void setTag(String tag) {
+ this.tag = tag;
+ }
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public void setNameServerAddress(String nameServerAddress) {
+ this.nameServerAddress = nameServerAddress;
+ }
+
+ public void setProducerGroup(String producerGroup) {
+ this.producerGroup = producerGroup;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/AbstractTestCase.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/AbstractTestCase.java b/logappender/src/test/java/org/apache/rocketmq/logappender/AbstractTestCase.java
new file mode 100644
index 0000000..d3e2f8a
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/AbstractTestCase.java
@@ -0,0 +1,154 @@
+/*
+ * 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.logappender;
+
+import org.apache.rocketmq.broker.BrokerController;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.BrokerConfig;
+import org.apache.rocketmq.common.MQVersion;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.namesrv.NamesrvConfig;
+import org.apache.rocketmq.logappender.common.ProducerInstance;
+import org.apache.rocketmq.namesrv.NamesrvController;
+import org.apache.rocketmq.remoting.netty.NettyClientConfig;
+import org.apache.rocketmq.remoting.netty.NettyServerConfig;
+import org.apache.rocketmq.remoting.protocol.RemotingCommand;
+import org.apache.rocketmq.store.config.MessageStoreConfig;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Basic test rocketmq broker and name server init
+ */
+public class AbstractTestCase {
+
+ private static String nameServer = "localhost:9876";
+
+ private static NamesrvController namesrvController;
+
+ private static BrokerController brokerController;
+
+ private static String topic = "TopicTest";
+
+ @BeforeClass
+ public static void startRocketmqService() throws Exception {
+
+ startNamesrv();
+
+ startBroker();
+ }
+
+ /**
+ * Start rocketmq name server
+ * @throws Exception
+ */
+ private static void startNamesrv() throws Exception {
+
+ NamesrvConfig namesrvConfig = new NamesrvConfig();
+ NettyServerConfig nettyServerConfig = new NettyServerConfig();
+ nettyServerConfig.setListenPort(9876);
+
+ namesrvController = new NamesrvController(namesrvConfig, nettyServerConfig);
+ boolean initResult = namesrvController.initialize();
+ if (!initResult) {
+ namesrvController.shutdown();
+ throw new Exception();
+ }
+ namesrvController.start();
+ }
+
+ /**
+ * Start rocketmq broker service
+ * @throws Exception
+ */
+ private static void startBroker() throws Exception {
+
+ System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
+
+ BrokerConfig brokerConfig = new BrokerConfig();
+ brokerConfig.setNamesrvAddr(nameServer);
+ brokerConfig.setBrokerId(MixAll.MASTER_ID);
+ NettyServerConfig nettyServerConfig = new NettyServerConfig();
+ nettyServerConfig.setListenPort(10911);
+ NettyClientConfig nettyClientConfig = new NettyClientConfig();
+ MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
+
+ brokerController = new BrokerController(brokerConfig, nettyServerConfig, nettyClientConfig, messageStoreConfig);
+ boolean initResult = brokerController.initialize();
+ if (!initResult) {
+ brokerController.shutdown();
+ throw new Exception();
+ }
+ brokerController.start();
+ }
+
+ @AfterClass
+ public static void stop() {
+ ProducerInstance.closeAll();
+ if (brokerController != null) {
+ brokerController.shutdown();
+ }
+
+ if (namesrvController != null) {
+ namesrvController.shutdown();
+ }
+ }
+
+ protected int consumeMessages(int count,final String key,int timeout) throws MQClientException, InterruptedException {
+
+ final AtomicInteger cc = new AtomicInteger(0);
+ final CountDownLatch countDownLatch = new CountDownLatch(count);
+
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("hello");
+ consumer.setNamesrvAddr(nameServer);
+ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
+ consumer.subscribe(topic, "*");
+
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+ ConsumeConcurrentlyContext context) {
+ for (MessageExt msg : msgs) {
+ String body = new String(msg.getBody());
+ if(key==null||body.contains(key)){
+ countDownLatch.countDown();
+ cc.incrementAndGet();
+ continue;
+ }
+ }
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+ consumer.start();
+ countDownLatch.await(timeout, TimeUnit.SECONDS);
+ consumer.shutdown();
+ return cc.get();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jPropertiesTest.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jPropertiesTest.java b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jPropertiesTest.java
new file mode 100644
index 0000000..8675230
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jPropertiesTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.logappender;
+
+import org.apache.log4j.PropertyConfigurator;
+
+public class Log4jPropertiesTest extends Log4jTest {
+
+ @Override
+ public void init() {
+ PropertyConfigurator.configure("src/test/resources/log4j-example.properties");
+ }
+
+ @Override
+ public String getType() {
+ return "properties";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jTest.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jTest.java b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jTest.java
new file mode 100644
index 0000000..75f9bf2
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.logappender;
+
+import org.apache.log4j.Logger;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public abstract class Log4jTest extends AbstractTestCase{
+
+ @Before
+ public abstract void init();
+
+ public abstract String getType();
+
+ @Test
+ public void testLog4j() throws InterruptedException, MQClientException {
+ Logger logger = Logger.getLogger("testLogger");
+ for (int i = 0; i < 50; i++) {
+ logger.info("log4j " + this.getType() + " simple test message " + i);
+ }
+ int received = consumeMessages(30, "log4j",30);
+ Assert.assertTrue(received>20);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jXmlTest.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jXmlTest.java b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jXmlTest.java
new file mode 100644
index 0000000..6743f7c
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/Log4jXmlTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.logappender;
+
+import org.apache.log4j.xml.DOMConfigurator;
+
+public class Log4jXmlTest extends Log4jTest {
+
+ @Override
+ public void init() {
+ DOMConfigurator.configure("src/test/resources/log4j-example.xml");
+ }
+
+ @Override
+ public String getType() {
+ return "xml";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/LogbackTest.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/LogbackTest.java b/logappender/src/test/java/org/apache/rocketmq/logappender/LogbackTest.java
new file mode 100644
index 0000000..15a21a3
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/LogbackTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.logappender;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.joran.JoranConfigurator;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.util.StatusPrinter;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+public class LogbackTest extends AbstractTestCase{
+
+ @Before
+ public void init() throws JoranException {
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+ JoranConfigurator configurator = new JoranConfigurator();
+ configurator.setContext(lc);
+ lc.reset();
+ configurator.doConfigure(new File("src/test/resources/logback-example.xml"));
+ StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
+ }
+
+
+ @Test
+ public void testLogback() throws InterruptedException, MQClientException {
+ Logger logger = LoggerFactory.getLogger("testLogger");
+ for (int i = 0; i < 50; i++) {
+ logger.info("logback test message " + i);
+ }
+ int received = consumeMessages(30, "logback",30);
+ Assert.assertTrue(received>20);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/java/org/apache/rocketmq/logappender/log4j2Test.java
----------------------------------------------------------------------
diff --git a/logappender/src/test/java/org/apache/rocketmq/logappender/log4j2Test.java b/logappender/src/test/java/org/apache/rocketmq/logappender/log4j2Test.java
new file mode 100644
index 0000000..75ba523
--- /dev/null
+++ b/logappender/src/test/java/org/apache/rocketmq/logappender/log4j2Test.java
@@ -0,0 +1,44 @@
+/*
+ * 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.logappender;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class log4j2Test extends AbstractTestCase{
+
+ @Before
+ public void init() {
+ Configurator.initialize("log4j2", "src/test/resources/log4j2-example.xml");
+ }
+
+
+ @Test
+ public void testLog4j2() throws InterruptedException, MQClientException {
+ Logger logger = LogManager.getLogger("test");
+ for (int i = 0; i < 50; i++) {
+ logger.info("log4j2 log message " + i);
+ }
+ int received = consumeMessages(30, "log4j2",30);
+ Assert.assertTrue(received>20);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/resources/log4j-example.properties
----------------------------------------------------------------------
diff --git a/logappender/src/test/resources/log4j-example.properties b/logappender/src/test/resources/log4j-example.properties
new file mode 100644
index 0000000..b4e8114
--- /dev/null
+++ b/logappender/src/test/resources/log4j-example.properties
@@ -0,0 +1,38 @@
+# 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.
+
+log4j.rootLogger=INFO,stdout
+
+log4j.logger.testLogger=INFO,mq
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %-4r [%t] (%F:%L) %-5p - %m%n
+
+log4j.appender.store=org.apache.log4j.DailyRollingFileAppender
+log4j.appender.store.File=${user.home}/logs/rocketmqlogs/appender.log
+log4j.appender.store.Append=true
+log4j.appender.store.DatePattern ='_'yyyy-MM-dd'.log'
+log4j.appender.store.layout=org.apache.log4j.PatternLayout
+log4j.appender.store.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-4r [%t] (%F:%L) %-5p - %m%n
+
+log4j.appender.mq=org.apache.rocketmq.logappender.log4j.RocketmqLog4jAppender
+log4j.appender.mq.Tag=log
+log4j.appender.mq.Topic=TopicTest
+log4j.appender.mq.ProducerGroup=log4jp
+log4j.appender.mq.NameServerAddress=127.0.0.1:9876
+log4j.appender.mq.layout=org.apache.log4j.PatternLayout
+log4j.appender.mq.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-4r [%t] (%F:%L) %-5p - %m%n
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/resources/log4j-example.xml
----------------------------------------------------------------------
diff --git a/logappender/src/test/resources/log4j-example.xml b/logappender/src/test/resources/log4j-example.xml
new file mode 100644
index 0000000..e58bcb0
--- /dev/null
+++ b/logappender/src/test/resources/log4j-example.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+ <appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
+ <param name="Encoding" value="UTF-8" />
+ <param name="Target" value="System.out" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss},%d %-4r [%t] (%F:%L) %-5p - %m%n" />
+ </layout>
+ </appender>
+
+ <appender name="mqAppender1" class="org.apache.rocketmq.logappender.log4j.RocketmqLog4jAppender">
+ <param name="Tag" value="log1" />
+ <param name="Topic" value="TopicTest" />
+ <param name="ProducerGroup" value="log4jxml" />
+ <param name="NameServerAddress" value="127.0.0.1:9876"/>
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}-%p %t %c - %m%n" />
+ </layout>
+ </appender>
+
+ <appender name="mqAsyncAppender1" class="org.apache.log4j.AsyncAppender">
+ <param name="BufferSize" value="1024" />
+ <param name="Blocking" value="false" />
+ <appender-ref ref="mqAppender1"/>
+ </appender>
+
+ <logger name="testLogger" additivity="false">
+ <level value="INFO" />
+ <appender-ref ref="mqAsyncAppender1" />
+ <appender-ref ref="consoleAppender" />
+ </logger>
+
+ <logger name="consoleLogger" additivity="false">
+ <level value="INFO" />
+ <appender-ref ref="consoleAppender" />
+ </logger>
+
+
+ <root>
+ <level value="INFO" />
+ <appender-ref ref="consoleAppender"/>
+ </root>
+
+</log4j:configuration>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/resources/log4j2-example.xml
----------------------------------------------------------------------
diff --git a/logappender/src/test/resources/log4j2-example.xml b/logappender/src/test/resources/log4j2-example.xml
new file mode 100644
index 0000000..358d40e
--- /dev/null
+++ b/logappender/src/test/resources/log4j2-example.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<Configuration status="warn" name="Rocketmq">
+<Appenders>
+ <RocketMQ name="rocketmqAppender" producerGroup="log4j2" nameServerAddress="127.0.0.1:9876"
+ topic="TopicTest" tag="log">
+ <PatternLayout pattern="%d [%p] hahahah %c %m%n"/>
+ </RocketMQ>
+
+ <Console name="Console" target="SYSTEM_OUT">
+ <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
+ </Console>
+</Appenders>
+<Loggers>
+
+ <Logger name="rocketmqLogger" level="info">
+ <AppenderRef ref="rocketmqAppender"/>
+ </Logger>
+
+ <Root level="debug">
+ <AppenderRef ref="Console"/>
+ <AppenderRef ref="rocketmqAppender"/>
+ </Root>
+</Loggers>
+</Configuration>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/logappender/src/test/resources/logback-example.xml
----------------------------------------------------------------------
diff --git a/logappender/src/test/resources/logback-example.xml b/logappender/src/test/resources/logback-example.xml
new file mode 100644
index 0000000..21b5434
--- /dev/null
+++ b/logappender/src/test/resources/logback-example.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+ -->
+
+<configuration>
+
+ <appender name="system" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${user.home}/logs/simple/system.log</file>
+ <append>true</append>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${user.home}/logs/simple/system.%i.log
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>30</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>100MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>%date %p %t - %m%n</pattern>
+ <charset class="java.nio.charset.Charset">UTF-8</charset>
+ </encoder>
+ </appender>
+
+ <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender">
+ <target>System.out</target>
+ <encoder>
+ <pattern>%date %p %t - %m%n</pattern>
+ <charset class="java.nio.charset.Charset">UTF-8</charset>
+ </encoder>
+ </appender>
+
+ <appender name="dailyAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${user.home}/logs/simple/daily.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+ <fileNamePattern>${user.home}/logs/simple/daily.log.%d{yyyy-MM-dd_HH}</fileNamePattern>
+ <maxHistory>30</maxHistory>
+ </rollingPolicy>
+ <encoder>
+ <pattern>%date %p %t - %m%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="mqAppender1" class="org.apache.rocketmq.logappender.logback.RocketmqLogbackAppender">
+ <tag>log1</tag>
+ <topic>TopicTest</topic>
+ <producerGroup>logback</producerGroup>
+ <nameServerAddress>127.0.0.1:9876</nameServerAddress>
+ <layout>
+ <pattern>%date %p %t - %m%n</pattern>
+ </layout>
+ </appender>
+
+ <appender name="mqAsyncAppender1" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>1024</queueSize>
+ <discardingThreshold>80</discardingThreshold>
+ <maxFlushTime>2000</maxFlushTime>
+ <neverBlock>true</neverBlock>
+ <appender-ref ref="mqAppender1"/>
+ </appender>
+
+ <root>
+ <level value="debug"/>
+ <appender-ref ref="consoleAppender"/>
+ </root>
+
+ <logger name="systemLogger" level="debug" additivity="false">
+ <appender-ref ref="system"/>
+ </logger>
+
+ <logger name="testLogger" level="debug" additivity="false">
+ <appender-ref ref="mqAsyncAppender1"/>
+ <appender-ref ref="consoleAppender"/>
+ </logger>
+</configuration>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 25e4c84..c60c93c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -175,6 +175,7 @@
<module>store</module>
<module>namesrv</module>
<module>remoting</module>
+ <module>logappender</module>
<module>example</module>
<module>filtersrv</module>
<module>srvutil</module>
@@ -623,6 +624,16 @@
<artifactId>openmessaging-api</artifactId>
<version>0.1.0-alpha</version>
</dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.17</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>2.7</version>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/37fbb7be/style/rmq_checkstyle.xml
----------------------------------------------------------------------
diff --git a/style/rmq_checkstyle.xml b/style/rmq_checkstyle.xml
index 2872eb7..6ec2ad0 100644
--- a/style/rmq_checkstyle.xml
+++ b/style/rmq_checkstyle.xml
@@ -30,6 +30,12 @@
<!-- header -->
<module name="RegexpHeader">
<property name="header" value="/\*\nLicensed to the Apache Software Foundation*"/>
+ <property name="fileExtensions" value="java"/>
+ </module>
+
+ <module name="RegexpHeader">
+ <property name="header" value="#[\s]*Licensed to the Apache Software Foundation*"/>
+ <property name="fileExtensions" value="properties"/>
</module>
<module name="RegexpSingleline">
[09/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-121]Support
message filtering based on SQL92 closes apache/incubator-rocketmq#82
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/message/Message.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/message/Message.java b/common/src/main/java/org/apache/rocketmq/common/message/Message.java
index f3bff83..2c81f5c 100644
--- a/common/src/main/java/org/apache/rocketmq/common/message/Message.java
+++ b/common/src/main/java/org/apache/rocketmq/common/message/Message.java
@@ -81,6 +81,12 @@ public class Message implements Serializable {
throw new RuntimeException(String.format(
"The Property<%s> is used by system, input another please", name));
}
+ if (value == null || value == "" || value.trim() == ""
+ || name == null || name == "" || name.trim() == "") {
+ throw new IllegalArgumentException(
+ "The name or value of property can not be null or blank string!"
+ );
+ }
this.putProperty(name, value);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java b/common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java
index 90b837a..e41ec9d 100644
--- a/common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java
+++ b/common/src/main/java/org/apache/rocketmq/common/message/MessageDecoder.java
@@ -41,6 +41,20 @@ public class MessageDecoder {
public final static int MESSAGE_MAGIC_CODE = 0xAABBCCDD ^ 1880681586 + 8;
public static final char NAME_VALUE_SEPARATOR = 1;
public static final char PROPERTY_SEPARATOR = 2;
+ public static final int BODY_SIZE_POSITION = 4 // 1 TOTALSIZE
+ + 4 // 2 MAGICCODE
+ + 4 // 3 BODYCRC
+ + 4 // 4 QUEUEID
+ + 4 // 5 FLAG
+ + 8 // 6 QUEUEOFFSET
+ + 8 // 7 PHYSICALOFFSET
+ + 4 // 8 SYSFLAG
+ + 8 // 9 BORNTIMESTAMP
+ + 8 // 10 BORNHOST
+ + 8 // 11 STORETIMESTAMP
+ + 8 // 12 STOREHOSTADDRESS
+ + 4 // 13 RECONSUMETIMES
+ + 8; // 14 Prepared Transaction Offset
public static String createMessageId(final ByteBuffer input, final ByteBuffer addr, final long offset) {
input.flip();
@@ -80,6 +94,31 @@ public class MessageDecoder {
return new MessageId(address, offset);
}
+ /**
+ * Just decode properties from msg buffer.
+ *
+ * @param byteBuffer msg commit log buffer.
+ * @return
+ */
+ public static Map<String, String> decodeProperties(java.nio.ByteBuffer byteBuffer) {
+ int topicLengthPosition = BODY_SIZE_POSITION + 4 + byteBuffer.getInt(BODY_SIZE_POSITION);
+
+ byte topicLength = byteBuffer.get(topicLengthPosition);
+
+ short propertiesLength = byteBuffer.getShort(topicLengthPosition + 1 + topicLength);
+
+ byteBuffer.position(topicLengthPosition + 1 + topicLength + 2);
+
+ if (propertiesLength > 0) {
+ byte[] properties = new byte[propertiesLength];
+ byteBuffer.get(properties);
+ String propertiesString = new String(properties, CHARSET_UTF8);
+ Map<String, String> map = string2messageProperties(propertiesString);
+ return map;
+ }
+ return null;
+ }
+
public static MessageExt decode(java.nio.ByteBuffer byteBuffer) {
return decode(byteBuffer, true, true, false);
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/namesrv/TopAddressing.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/namesrv/TopAddressing.java b/common/src/main/java/org/apache/rocketmq/common/namesrv/TopAddressing.java
index 74fd965..990e748 100644
--- a/common/src/main/java/org/apache/rocketmq/common/namesrv/TopAddressing.java
+++ b/common/src/main/java/org/apache/rocketmq/common/namesrv/TopAddressing.java
@@ -88,7 +88,7 @@ public class TopAddressing {
if (verbose) {
String errorMsg =
- "connect to " + url + " failed, maybe the domain name " + MixAll.WS_DOMAIN_NAME + " not bind in /etc/hosts";
+ "connect to " + url + " failed, maybe the domain name " + MixAll.getWSAddr() + " not bind in /etc/hosts";
errorMsg += FAQUrl.suggestTodo(FAQUrl.NAME_SERVER_ADDR_NOT_EXIST_URL);
log.warn(errorMsg);
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java b/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
index c6b0925..6f132f7 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/RequestCode.java
@@ -68,6 +68,8 @@ public class RequestCode {
public static final int GET_ALL_DELAY_OFFSET = 45;
+ public static final int CHECK_CLIENT_CONFIG = 46;
+
public static final int PUT_KV_CONFIG = 100;
public static final int GET_KV_CONFIG = 101;
@@ -162,4 +164,6 @@ public class RequestCode {
public static final int SEND_BATCH_MESSAGE = 320;
+
+ public static final int QUERY_CONSUME_QUEUE = 321;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java b/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
index 90b182b..f62c4ea 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/ResponseCode.java
@@ -53,6 +53,10 @@ public class ResponseCode extends RemotingSysResponseCode {
public static final int SUBSCRIPTION_GROUP_NOT_EXIST = 26;
+ public static final int FILTER_DATA_NOT_EXIST = 27;
+
+ public static final int FILTER_DATA_NOT_LATEST = 28;
+
public static final int TRANSACTION_SHOULD_COMMIT = 200;
public static final int TRANSACTION_SHOULD_ROLLBACK = 201;
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
new file mode 100644
index 0000000..a78ce55
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/CheckClientRequestBody.java
@@ -0,0 +1,52 @@
+/*
+ * 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.common.protocol.body;
+
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
+public class CheckClientRequestBody extends RemotingSerializable {
+
+ private String clientId;
+ private String group;
+ private SubscriptionData subscriptionData;
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public void setGroup(String group) {
+ this.group = group;
+ }
+
+ public SubscriptionData getSubscriptionData() {
+ return subscriptionData;
+ }
+
+ public void setSubscriptionData(SubscriptionData subscriptionData) {
+ this.subscriptionData = subscriptionData;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeQueueData.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeQueueData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeQueueData.java
new file mode 100644
index 0000000..7268dcd
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/ConsumeQueueData.java
@@ -0,0 +1,98 @@
+/*
+ * 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.common.protocol.body;
+
+public class ConsumeQueueData {
+
+ private long physicOffset;
+ private int physicSize;
+ private long tagsCode;
+ private String extendDataJson;
+ private String bitMap;
+ private boolean eval;
+ private String msg;
+
+ public long getPhysicOffset() {
+ return physicOffset;
+ }
+
+ public void setPhysicOffset(long physicOffset) {
+ this.physicOffset = physicOffset;
+ }
+
+ public int getPhysicSize() {
+ return physicSize;
+ }
+
+ public void setPhysicSize(int physicSize) {
+ this.physicSize = physicSize;
+ }
+
+ public long getTagsCode() {
+ return tagsCode;
+ }
+
+ public void setTagsCode(long tagsCode) {
+ this.tagsCode = tagsCode;
+ }
+
+ public String getExtendDataJson() {
+ return extendDataJson;
+ }
+
+ public void setExtendDataJson(String extendDataJson) {
+ this.extendDataJson = extendDataJson;
+ }
+
+ public String getBitMap() {
+ return bitMap;
+ }
+
+ public void setBitMap(String bitMap) {
+ this.bitMap = bitMap;
+ }
+
+ public boolean isEval() {
+ return eval;
+ }
+
+ public void setEval(boolean eval) {
+ this.eval = eval;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ @Override
+ public String toString() {
+ return "ConsumeQueueData{" +
+ "physicOffset=" + physicOffset +
+ ", physicSize=" + physicSize +
+ ", tagsCode=" + tagsCode +
+ ", extendDataJson='" + extendDataJson + '\'' +
+ ", bitMap='" + bitMap + '\'' +
+ ", eval=" + eval +
+ ", msg='" + msg + '\'' +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
new file mode 100644
index 0000000..be93da9
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/body/QueryConsumeQueueResponseBody.java
@@ -0,0 +1,72 @@
+/*
+ * 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.common.protocol.body;
+
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
+import org.apache.rocketmq.remoting.protocol.RemotingSerializable;
+
+import java.util.List;
+
+public class QueryConsumeQueueResponseBody extends RemotingSerializable {
+
+ private SubscriptionData subscriptionData;
+ private String filterData;
+ private List<ConsumeQueueData> queueData;
+ private long maxQueueIndex;
+ private long minQueueIndex;
+
+ public SubscriptionData getSubscriptionData() {
+ return subscriptionData;
+ }
+
+ public void setSubscriptionData(SubscriptionData subscriptionData) {
+ this.subscriptionData = subscriptionData;
+ }
+
+ public String getFilterData() {
+ return filterData;
+ }
+
+ public void setFilterData(String filterData) {
+ this.filterData = filterData;
+ }
+
+ public List<ConsumeQueueData> getQueueData() {
+ return queueData;
+ }
+
+ public void setQueueData(List<ConsumeQueueData> queueData) {
+ this.queueData = queueData;
+ }
+
+ public long getMaxQueueIndex() {
+ return maxQueueIndex;
+ }
+
+ public void setMaxQueueIndex(long maxQueueIndex) {
+ this.maxQueueIndex = maxQueueIndex;
+ }
+
+ public long getMinQueueIndex() {
+ return minQueueIndex;
+ }
+
+ public void setMinQueueIndex(long minQueueIndex) {
+ this.minQueueIndex = minQueueIndex;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
index 8a59213..106e89e 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/PullMessageRequestHeader.java
@@ -46,6 +46,7 @@ public class PullMessageRequestHeader implements CommandCustomHeader {
private String subscription;
@CFNotNull
private Long subVersion;
+ private String expressionType;
@Override
public void checkFields() throws RemotingCommandException {
@@ -130,4 +131,12 @@ public class PullMessageRequestHeader implements CommandCustomHeader {
public void setSubVersion(Long subVersion) {
this.subVersion = subVersion;
}
+
+ public String getExpressionType() {
+ return expressionType;
+ }
+
+ public void setExpressionType(String expressionType) {
+ this.expressionType = expressionType;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumeQueueRequestHeader.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumeQueueRequestHeader.java b/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumeQueueRequestHeader.java
new file mode 100644
index 0000000..642fe17
--- /dev/null
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/header/QueryConsumeQueueRequestHeader.java
@@ -0,0 +1,75 @@
+/*
+ * 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.common.protocol.header;
+
+import org.apache.rocketmq.remoting.CommandCustomHeader;
+import org.apache.rocketmq.remoting.exception.RemotingCommandException;
+
+public class QueryConsumeQueueRequestHeader implements CommandCustomHeader {
+
+ private String topic;
+ private int queueId;
+ private long index;
+ private int count;
+ private String consumerGroup;
+
+ public String getTopic() {
+ return topic;
+ }
+
+ public void setTopic(String topic) {
+ this.topic = topic;
+ }
+
+ public int getQueueId() {
+ return queueId;
+ }
+
+ public void setQueueId(int queueId) {
+ this.queueId = queueId;
+ }
+
+ public long getIndex() {
+ return index;
+ }
+
+ public void setIndex(long index) {
+ this.index = index;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public String getConsumerGroup() {
+ return consumerGroup;
+ }
+
+ public void setConsumerGroup(String consumerGroup) {
+ this.consumerGroup = consumerGroup;
+ }
+
+ @Override
+ public void checkFields() throws RemotingCommandException {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java
index 81f5954..e456b7e 100644
--- a/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java
+++ b/common/src/main/java/org/apache/rocketmq/common/protocol/heartbeat/SubscriptionData.java
@@ -32,6 +32,7 @@ public class SubscriptionData implements Comparable<SubscriptionData> {
private Set<String> tagsSet = new HashSet<String>();
private Set<Integer> codeSet = new HashSet<Integer>();
private long subVersion = System.currentTimeMillis();
+ private String expressionType;
@JSONField(serialize = false)
private String filterClassSource;
@@ -102,6 +103,14 @@ public class SubscriptionData implements Comparable<SubscriptionData> {
this.classFilterMode = classFilterMode;
}
+ public String getExpressionType() {
+ return expressionType;
+ }
+
+ public void setExpressionType(String expressionType) {
+ this.expressionType = expressionType;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -111,6 +120,7 @@ public class SubscriptionData implements Comparable<SubscriptionData> {
result = prime * result + ((subString == null) ? 0 : subString.hashCode());
result = prime * result + ((tagsSet == null) ? 0 : tagsSet.hashCode());
result = prime * result + ((topic == null) ? 0 : topic.hashCode());
+ result = prime * result + ((expressionType == null) ? 0 : expressionType.hashCode());
return result;
}
@@ -147,6 +157,11 @@ public class SubscriptionData implements Comparable<SubscriptionData> {
return false;
} else if (!topic.equals(other.topic))
return false;
+ if (expressionType == null) {
+ if (other.expressionType != null)
+ return false;
+ } else if (!expressionType.equals(other.expressionType))
+ return false;
return true;
}
@@ -154,7 +169,7 @@ public class SubscriptionData implements Comparable<SubscriptionData> {
public String toString() {
return "SubscriptionData [classFilterMode=" + classFilterMode + ", topic=" + topic + ", subString="
+ subString + ", tagsSet=" + tagsSet + ", codeSet=" + codeSet + ", subVersion=" + subVersion
- + "]";
+ + ", expressionType=" + expressionType + "]";
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/test/java/org/apache/rocketmq/common/filter/FilterAPITest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/rocketmq/common/filter/FilterAPITest.java b/common/src/test/java/org/apache/rocketmq/common/filter/FilterAPITest.java
index 5137f32..c5f8460 100644
--- a/common/src/test/java/org/apache/rocketmq/common/filter/FilterAPITest.java
+++ b/common/src/test/java/org/apache/rocketmq/common/filter/FilterAPITest.java
@@ -42,4 +42,53 @@ public class FilterAPITest {
}
assertThat(subscriptionData.getTagsSet()).isEqualTo(tagSet);
}
+
+ @Test
+ public void testBuildTagSome() {
+ try {
+ SubscriptionData subscriptionData = FilterAPI.build(
+ "TOPIC", "A || B", ExpressionType.TAG
+ );
+
+ assertThat(subscriptionData).isNotNull();
+ assertThat(subscriptionData.getTopic()).isEqualTo("TOPIC");
+ assertThat(subscriptionData.getSubString()).isEqualTo("A || B");
+ assertThat(ExpressionType.isTagType(subscriptionData.getExpressionType())).isTrue();
+
+ assertThat(subscriptionData.getTagsSet()).isNotNull();
+ assertThat(subscriptionData.getTagsSet()).containsExactly("A", "B");
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+ }
+
+ @Test
+ public void testBuildSQL() {
+ try {
+ SubscriptionData subscriptionData = FilterAPI.build(
+ "TOPIC", "a is not null", ExpressionType.SQL92
+ );
+
+ assertThat(subscriptionData).isNotNull();
+ assertThat(subscriptionData.getTopic()).isEqualTo("TOPIC");
+ assertThat(subscriptionData.getExpressionType()).isEqualTo(ExpressionType.SQL92);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+ }
+
+ @Test
+ public void testBuildSQLWithNullSubString() {
+ try {
+ FilterAPI.build(
+ "TOPIC", null, ExpressionType.SQL92
+ );
+
+ assertThat(Boolean.FALSE).isTrue();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/common/src/test/java/org/apache/rocketmq/common/message/MessageDecoderTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/rocketmq/common/message/MessageDecoderTest.java b/common/src/test/java/org/apache/rocketmq/common/message/MessageDecoderTest.java
new file mode 100644
index 0000000..d14d6b0
--- /dev/null
+++ b/common/src/test/java/org/apache/rocketmq/common/message/MessageDecoderTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.common.message;
+
+import org.junit.Test;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MessageDecoderTest {
+
+ @Test
+ public void testDecodeProperties() {
+ MessageExt messageExt = new MessageExt();
+
+ messageExt.setMsgId("645100FA00002A9F000000489A3AA09E");
+ messageExt.setTopic("abc");
+ messageExt.setBody("hello!q!".getBytes());
+ try {
+ messageExt.setBornHost(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0));
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+ messageExt.setBornTimestamp(System.currentTimeMillis());
+ messageExt.setCommitLogOffset(123456);
+ messageExt.setPreparedTransactionOffset(0);
+ messageExt.setQueueId(0);
+ messageExt.setQueueOffset(123);
+ messageExt.setReconsumeTimes(0);
+ try {
+ messageExt.setStoreHost(new InetSocketAddress(InetAddress.getLocalHost(), 0));
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ messageExt.putUserProperty("a", "123");
+ messageExt.putUserProperty("b", "hello");
+ messageExt.putUserProperty("c", "3.14");
+
+ byte[] msgBytes = new byte[0];
+ try {
+ msgBytes = MessageDecoder.encode(messageExt, false);
+ } catch (Exception e) {
+ e.printStackTrace();
+ assertThat(Boolean.FALSE).isTrue();
+ }
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(msgBytes.length);
+ byteBuffer.put(msgBytes);
+
+ Map<String, String> properties = MessageDecoder.decodeProperties(byteBuffer);
+
+ assertThat(properties).isNotNull();
+ assertThat("123").isEqualTo(properties.get("a"));
+ assertThat("hello").isEqualTo(properties.get("b"));
+ assertThat("3.14").isEqualTo(properties.get("c"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/distribution/conf/logback_broker.xml
----------------------------------------------------------------------
diff --git a/distribution/conf/logback_broker.xml b/distribution/conf/logback_broker.xml
index 05c0ee4..dd5c63f 100644
--- a/distribution/conf/logback_broker.xml
+++ b/distribution/conf/logback_broker.xml
@@ -222,6 +222,29 @@
<appender-ref ref="RocketmqRebalanceLockAppender_inner"/>
</appender>
+ <appender name="RocketmqFilterAppender_inner"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${user.home}/logs/rocketmqlogs/filter.log</file>
+ <append>true</append>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${user.home}/logs/rocketmqlogs/otherdays/filter.%i.log
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>10</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>100MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>%d{yyy-MM-dd HH:mm:ss,GMT+8} %p %t - %m%n</pattern>
+ <charset class="java.nio.charset.Charset">UTF-8</charset>
+ </encoder>
+ </appender>
+ <appender name="RocketmqFilterAppender" class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="RocketmqFilterAppender_inner"/>
+ </appender>
+
<appender name="RocketmqStatsAppender"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${user.home}/logs/rocketmqlogs/stats.log</file>
@@ -321,6 +344,11 @@
<appender-ref ref="RocketmqCommercialAppender"/>
</logger>
+ <logger name="RocketmqFilter" additivity="false">
+ <level value="INFO"/>
+ <appender-ref ref="RocketmqFilterAppender"/>
+ </logger>
+
<root>
<level value="INFO"/>
<appender-ref ref="DefaultAppender"/>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/distribution/release.xml
----------------------------------------------------------------------
diff --git a/distribution/release.xml b/distribution/release.xml
index 2d3ec1e..9e4ef2a 100644
--- a/distribution/release.xml
+++ b/distribution/release.xml
@@ -67,6 +67,7 @@
<include>org.apache.rocketmq:rocketmq-namesrv</include>
<include>org.apache.rocketmq:rocketmq-filtersrv</include>
<include>org.apache.rocketmq:rocketmq-example</include>
+ <include>org.apache.rocketmq:rocketmq-filter</include>
</includes>
<binaries>
<outputDirectory>lib/</outputDirectory>
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java b/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
index 473e4c7..3e1b79b 100644
--- a/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/benchmark/Consumer.java
@@ -27,10 +27,13 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.MessageSelector;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.MixAll;
+import org.apache.rocketmq.common.filter.ExpressionType;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.srvutil.ServerUtil;
@@ -46,12 +49,14 @@ public class Consumer {
final String topic = commandLine.hasOption('t') ? commandLine.getOptionValue('t').trim() : "BenchmarkTest";
final String groupPrefix = commandLine.hasOption('g') ? commandLine.getOptionValue('g').trim() : "benchmark_consumer";
final String isPrefixEnable = commandLine.hasOption('p') ? commandLine.getOptionValue('p').trim() : "true";
+ final String filterType = commandLine.hasOption('f') ? commandLine.getOptionValue('f').trim() : null;
+ final String expression = commandLine.hasOption('e') ? commandLine.getOptionValue('e').trim() : null;
String group = groupPrefix;
if (Boolean.parseBoolean(isPrefixEnable)) {
group = groupPrefix + "_" + Long.toString(System.currentTimeMillis() % 100);
}
- System.out.printf("topic %s group %s prefix %s%n", topic, group, isPrefixEnable);
+ System.out.printf("topic: %s, group: %s, prefix: %s, filterType: %s, expression: %s%n", topic, group, isPrefixEnable, filterType, expression);
final StatsBenchmarkConsumer statsBenchmarkConsumer = new StatsBenchmarkConsumer();
@@ -99,7 +104,21 @@ public class Consumer {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(group);
consumer.setInstanceName(Long.toString(System.currentTimeMillis()));
- consumer.subscribe(topic, "*");
+ if (filterType == null || expression == null) {
+ consumer.subscribe(topic, "*");
+ } else {
+ if (ExpressionType.TAG.equals(filterType)) {
+ String expr = MixAll.file2String(expression);
+ System.out.printf("Expression: %s%n", expr);
+ consumer.subscribe(topic, MessageSelector.byTag(expr));
+ } else if (ExpressionType.SQL92.equals(filterType)) {
+ String expr = MixAll.file2String(expression);
+ System.out.printf("Expression: %s%n", expr);
+ consumer.subscribe(topic, MessageSelector.bySql(expr));
+ } else {
+ throw new IllegalArgumentException("Not support filter type! " + filterType);
+ }
+ }
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
@@ -142,6 +161,14 @@ public class Consumer {
opt.setRequired(false);
options.addOption(opt);
+ opt = new Option("f", "filterType", true, "TAG, SQL92");
+ opt.setRequired(false);
+ options.addOption(opt);
+
+ opt = new Option("e", "expression", true, "filter expression content file path.ie: ./test/expr");
+ opt.setRequired(false);
+ options.addOption(opt);
+
return options;
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/example/src/main/java/org/apache/rocketmq/example/benchmark/Producer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/benchmark/Producer.java b/example/src/main/java/org/apache/rocketmq/example/benchmark/Producer.java
index 50d750d..2d8d0f6 100644
--- a/example/src/main/java/org/apache/rocketmq/example/benchmark/Producer.java
+++ b/example/src/main/java/org/apache/rocketmq/example/benchmark/Producer.java
@@ -18,11 +18,13 @@ package org.apache.rocketmq.example.benchmark;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
+import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
+
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -50,13 +52,12 @@ public class Producer {
final int threadCount = commandLine.hasOption('w') ? Integer.parseInt(commandLine.getOptionValue('w')) : 64;
final int messageSize = commandLine.hasOption('s') ? Integer.parseInt(commandLine.getOptionValue('s')) : 128;
final boolean keyEnable = commandLine.hasOption('k') && Boolean.parseBoolean(commandLine.getOptionValue('k'));
+ final int propertySize = commandLine.hasOption('p') ? Integer.parseInt(commandLine.getOptionValue('p')) : 0;
System.out.printf("topic %s threadCount %d messageSize %d keyEnable %s%n", topic, threadCount, messageSize, keyEnable);
final Logger log = ClientLogger.getLog();
- final Message msg = buildMessage(messageSize, topic);
-
final ExecutorService sendThreadPool = Executors.newFixedThreadPool(threadCount);
final StatsBenchmarkProducer statsBenchmark = new StatsBenchmarkProducer();
@@ -117,10 +118,37 @@ public class Producer {
public void run() {
while (true) {
try {
+ final Message msg;
+ try {
+ msg = buildMessage(messageSize, topic);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return;
+ }
final long beginTimestamp = System.currentTimeMillis();
if (keyEnable) {
msg.setKeys(String.valueOf(beginTimestamp / 1000));
}
+ if (propertySize > 0) {
+ if (msg.getProperties() != null) {
+ msg.getProperties().clear();
+ }
+ int i = 0;
+ int startValue = (new Random(System.currentTimeMillis())).nextInt(100);
+ int size = 0;
+ while (true) {
+ String prop1 = "prop" + i, prop1V = "hello" + startValue;
+ String prop2 = "prop" + (i + 1), prop2V = String.valueOf(startValue);
+ msg.putUserProperty(prop1, prop1V);
+ msg.putUserProperty(prop2, prop2V);
+ size += prop1.length() + prop2.length() + prop1V.length() + prop2V.length();
+ if (size > propertySize) {
+ break;
+ }
+ i += 2;
+ startValue += 2;
+ }
+ }
producer.send(msg);
statsBenchmark.getSendRequestSuccessCount().incrementAndGet();
statsBenchmark.getReceiveResponseSuccessCount().incrementAndGet();
@@ -214,7 +242,7 @@ class StatsBenchmarkProducer {
private final AtomicLong sendMessageMaxRT = new AtomicLong(0L);
public Long[] createSnapshot() {
- Long[] snap = new Long[] {
+ Long[] snap = new Long[]{
System.currentTimeMillis(),
this.sendRequestSuccessCount.get(),
this.sendRequestFailedCount.get(),
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
new file mode 100644
index 0000000..9a3b813
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/filter/SqlConsumer.java
@@ -0,0 +1,62 @@
+/*
+ * 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.example.filter;
+
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.MessageSelector;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
+import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.common.message.MessageExt;
+
+import java.util.List;
+
+public class SqlConsumer {
+
+ public static void main(String[] args) {
+ DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4");
+
+ try {
+ consumer.subscribe("TopicTest",
+ MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))" +
+ "and (a is not null and a between 0 3)"));
+ } catch (MQClientException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ consumer.registerMessageListener(new MessageListenerConcurrently() {
+
+ @Override
+ public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
+ ConsumeConcurrentlyContext context) {
+ System.out.printf(Thread.currentThread().getName() + " Receive New Messages: " + msgs + "%n");
+ return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
+ }
+ });
+
+ try {
+ consumer.start();
+ } catch (MQClientException e) {
+ e.printStackTrace();
+ return;
+ }
+ System.out.printf("Consumer Started.%n");
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/example/src/main/java/org/apache/rocketmq/example/filter/SqlProducer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/filter/SqlProducer.java b/example/src/main/java/org/apache/rocketmq/example/filter/SqlProducer.java
new file mode 100644
index 0000000..3f3a0e6
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/filter/SqlProducer.java
@@ -0,0 +1,67 @@
+/*
+ * 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.example.filter;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.common.RemotingHelper;
+
+public class SqlProducer {
+
+ public static void main(String[] args) {
+ DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name");
+ try {
+ producer.start();
+ } catch (MQClientException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ for (int i = 0; i < 10; i++) {
+ try {
+ String tag;
+ int div = i % 3;
+ if (div == 0) {
+ tag = "TagA";
+ } else if (div == 1) {
+ tag = "TagB";
+ } else {
+ tag = "TagC";
+ }
+ Message msg = new Message("TopicTest",
+ tag,
+ ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)
+ );
+ msg.putUserProperty("a", String.valueOf(i));
+
+ SendResult sendResult = producer.send(msg);
+ System.out.printf("%s%n", sendResult);
+ } catch (Exception e) {
+ e.printStackTrace();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ }
+ }
+ producer.shutdown();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/pom.xml
----------------------------------------------------------------------
diff --git a/filter/pom.xml b/filter/pom.xml
new file mode 100644
index 0000000..7978f05
--- /dev/null
+++ b/filter/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>rocketmq-all</artifactId>
+ <groupId>org.apache.rocketmq</groupId>
+ <version>4.1.0-incubating-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>jar</packaging>
+ <artifactId>rocketmq-filter</artifactId>
+ <name>rocketmq-filter ${project.version}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>rocketmq-srvutil</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/FilterFactory.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/FilterFactory.java b/filter/src/main/java/org/apache/rocketmq/filter/FilterFactory.java
new file mode 100644
index 0000000..a318548
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/FilterFactory.java
@@ -0,0 +1,72 @@
+/*
+ * 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.filter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Filter factory: support other filter to register.
+ */
+public class FilterFactory {
+
+ public static final FilterFactory INSTANCE = new FilterFactory();
+
+ protected static final Map<String, FilterSpi> FILTER_SPI_HOLDER = new HashMap<String, FilterSpi>(4);
+
+ static {
+ FilterFactory.INSTANCE.register(new SqlFilter());
+ }
+
+ /**
+ * Register a filter.
+ * <br>
+ * Note:
+ * <li>1. Filter registered will be used in broker server, so take care of it's reliability and performance.</li>
+ *
+ * @param filterSpi
+ */
+ public void register(FilterSpi filterSpi) {
+ if (FILTER_SPI_HOLDER.containsKey(filterSpi.ofType())) {
+ throw new IllegalArgumentException(String.format("Filter spi type(%s) already exist!", filterSpi.ofType()));
+ }
+
+ FILTER_SPI_HOLDER.put(filterSpi.ofType(), filterSpi);
+ }
+
+ /**
+ * Un register a filter.
+ *
+ * @param type
+ * @return
+ */
+ public FilterSpi unRegister(String type) {
+ return FILTER_SPI_HOLDER.remove(type);
+ }
+
+ /**
+ * Get a filter registered, null if none exist.
+ *
+ * @param type
+ * @return
+ */
+ public FilterSpi get(String type) {
+ return FILTER_SPI_HOLDER.get(type);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/FilterSpi.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/FilterSpi.java b/filter/src/main/java/org/apache/rocketmq/filter/FilterSpi.java
new file mode 100644
index 0000000..fcc39fa
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/FilterSpi.java
@@ -0,0 +1,43 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+
+/**
+ * Filter spi interface.
+ */
+public interface FilterSpi {
+
+ /**
+ * Compile.
+ *
+ * @param expr
+ * @return
+ * @throws org.apache.rocketmq.filter.expression.MQFilterException
+ */
+ Expression compile(final String expr) throws MQFilterException;
+
+ /**
+ * Which type.
+ *
+ * @return
+ */
+ String ofType();
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/SqlFilter.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/SqlFilter.java b/filter/src/main/java/org/apache/rocketmq/filter/SqlFilter.java
new file mode 100644
index 0000000..0c1ffb8
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/SqlFilter.java
@@ -0,0 +1,43 @@
+/*
+ * 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.filter;
+
+import org.apache.rocketmq.common.filter.ExpressionType;
+import org.apache.rocketmq.filter.expression.Expression;
+import org.apache.rocketmq.filter.expression.MQFilterException;
+import org.apache.rocketmq.filter.parser.SelectorParser;
+
+/**
+ * SQL92 Filter, just a wrapper of {@link org.apache.rocketmq.filter.parser.SelectorParser}.
+ * <p/>
+ * <p>
+ * Do not use this filter directly.Use {@link FilterFactory#get} to select a filter.
+ * </p>
+ */
+public class SqlFilter implements FilterSpi {
+
+ @Override
+ public Expression compile(final String expr) throws MQFilterException {
+ return SelectorParser.parse(expr);
+ }
+
+ @Override
+ public String ofType() {
+ return ExpressionType.SQL92;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/constant/UnaryType.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/constant/UnaryType.java b/filter/src/main/java/org/apache/rocketmq/filter/constant/UnaryType.java
new file mode 100644
index 0000000..d2d04cd
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/constant/UnaryType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.filter.constant;
+
+public enum UnaryType {
+ NEGATE,
+ IN,
+ NOT,
+ BOOLEANCAST,
+ LIKE
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/BinaryExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/BinaryExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/BinaryExpression.java
new file mode 100644
index 0000000..0f172e3
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/BinaryExpression.java
@@ -0,0 +1,91 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * An expression which performs an operation on two expression values.
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.BinaryExpression,
+ * </p>
+ */
+public abstract class BinaryExpression implements Expression {
+ protected Expression left;
+ protected Expression right;
+
+ public BinaryExpression(Expression left, Expression right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ public Expression getLeft() {
+ return left;
+ }
+
+ public Expression getRight() {
+ return right;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")";
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ /**
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object o) {
+
+ if (o == null || !this.getClass().equals(o.getClass())) {
+ return false;
+ }
+ return toString().equals(o.toString());
+
+ }
+
+ /**
+ * Returns the symbol that represents this binary expression. For example, addition is
+ * represented by "+"
+ *
+ * @return
+ */
+ public abstract String getExpressionSymbol();
+
+ /**
+ * @param expression
+ */
+ public void setRight(Expression expression) {
+ right = expression;
+ }
+
+ /**
+ * @param expression
+ */
+ public void setLeft(Expression expression) {
+ left = expression;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/BooleanExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/BooleanExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/BooleanExpression.java
new file mode 100644
index 0000000..bb54632
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/BooleanExpression.java
@@ -0,0 +1,39 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * A BooleanExpression is an expression that always
+ * produces a Boolean result.
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.BooleanExpression,
+ * but the parameter is changed to an interface.
+ * </p>
+ *
+ * @see org.apache.rocketmq.filter.expression.EvaluationContext
+ */
+public interface BooleanExpression extends Expression {
+
+ /**
+ * @param context
+ * @return true if the expression evaluates to Boolean.TRUE.
+ * @throws Exception
+ */
+ boolean matches(EvaluationContext context) throws Exception;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/ComparisonExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/ComparisonExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/ComparisonExpression.java
new file mode 100644
index 0000000..8b82e57
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/ComparisonExpression.java
@@ -0,0 +1,413 @@
+/*
+ * 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.filter.expression;
+
+import java.util.List;
+
+/**
+ * A filter performing a comparison of two objects
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.ComparisonExpression,
+ * but:
+ * 1. Remove LIKE expression, and related methods;
+ * 2. Extract a new method __compare which has int return value;
+ * 3. When create between expression, check whether left value is less or equal than right value;
+ * 4. For string type value(can not convert to number), only equal or unequal comparison are supported.
+ * </p>
+ */
+public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression {
+
+ public static final ThreadLocal<Boolean> CONVERT_STRING_EXPRESSIONS = new ThreadLocal<Boolean>();
+
+ boolean convertStringExpressions = false;
+
+ /**
+ * @param left
+ * @param right
+ */
+ public ComparisonExpression(Expression left, Expression right) {
+ super(left, right);
+ convertStringExpressions = CONVERT_STRING_EXPRESSIONS.get() != null;
+ }
+
+ public static BooleanExpression createBetween(Expression value, Expression left, Expression right) {
+ // check
+ if (left instanceof ConstantExpression && right instanceof ConstantExpression) {
+ Object lv = ((ConstantExpression) left).getValue();
+ Object rv = ((ConstantExpression) right).getValue();
+ if (lv == null || rv == null) {
+ throw new RuntimeException("Illegal values of between, values can not be null!");
+ }
+ if (lv instanceof Comparable && rv instanceof Comparable) {
+ int ret = __compare((Comparable) rv, (Comparable) lv, true);
+ if (ret < 0)
+ throw new RuntimeException(
+ String.format("Illegal values of between, left value(%s) must less than or equal to right value(%s)", lv, rv)
+ );
+ }
+ }
+
+ return LogicExpression.createAND(createGreaterThanEqual(value, left), createLessThanEqual(value, right));
+ }
+
+ public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right) {
+ return LogicExpression.createOR(createLessThan(value, left), createGreaterThan(value, right));
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static BooleanExpression createInFilter(Expression left, List elements) {
+
+ if (!(left instanceof PropertyExpression)) {
+ throw new RuntimeException("Expected a property for In expression, got: " + left);
+ }
+ return UnaryExpression.createInExpression((PropertyExpression) left, elements, false);
+
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public static BooleanExpression createNotInFilter(Expression left, List elements) {
+
+ if (!(left instanceof PropertyExpression)) {
+ throw new RuntimeException("Expected a property for In expression, got: " + left);
+ }
+ return UnaryExpression.createInExpression((PropertyExpression) left, elements, true);
+
+ }
+
+ public static BooleanExpression createIsNull(Expression left) {
+ return doCreateEqual(left, ConstantExpression.NULL);
+ }
+
+ public static BooleanExpression createIsNotNull(Expression left) {
+ return UnaryExpression.createNOT(doCreateEqual(left, ConstantExpression.NULL));
+ }
+
+ public static BooleanExpression createNotEqual(Expression left, Expression right) {
+ return UnaryExpression.createNOT(createEqual(left, right));
+ }
+
+ public static BooleanExpression createEqual(Expression left, Expression right) {
+ checkEqualOperand(left);
+ checkEqualOperand(right);
+ checkEqualOperandCompatability(left, right);
+ return doCreateEqual(left, right);
+ }
+
+ @SuppressWarnings({"rawtypes"})
+ private static BooleanExpression doCreateEqual(Expression left, Expression right) {
+ return new ComparisonExpression(left, right) {
+
+ public Object evaluate(EvaluationContext context) throws Exception {
+ Object lv = left.evaluate(context);
+ Object rv = right.evaluate(context);
+
+ // If one of the values is null
+ if (lv == null ^ rv == null) {
+ if (lv == null) {
+ return null;
+ }
+ return Boolean.FALSE;
+ }
+ if (lv == rv || lv.equals(rv)) {
+ return Boolean.TRUE;
+ }
+ if (lv instanceof Comparable && rv instanceof Comparable) {
+ return compare((Comparable) lv, (Comparable) rv);
+ }
+ return Boolean.FALSE;
+ }
+
+ protected boolean asBoolean(int answer) {
+ return answer == 0;
+ }
+
+ public String getExpressionSymbol() {
+ return "==";
+ }
+ };
+ }
+
+ public static BooleanExpression createGreaterThan(final Expression left, final Expression right) {
+ checkLessThanOperand(left);
+ checkLessThanOperand(right);
+ return new ComparisonExpression(left, right) {
+ protected boolean asBoolean(int answer) {
+ return answer > 0;
+ }
+
+ public String getExpressionSymbol() {
+ return ">";
+ }
+ };
+ }
+
+ public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right) {
+ checkLessThanOperand(left);
+ checkLessThanOperand(right);
+ return new ComparisonExpression(left, right) {
+ protected boolean asBoolean(int answer) {
+ return answer >= 0;
+ }
+
+ public String getExpressionSymbol() {
+ return ">=";
+ }
+ };
+ }
+
+ public static BooleanExpression createLessThan(final Expression left, final Expression right) {
+ checkLessThanOperand(left);
+ checkLessThanOperand(right);
+ return new ComparisonExpression(left, right) {
+
+ protected boolean asBoolean(int answer) {
+ return answer < 0;
+ }
+
+ public String getExpressionSymbol() {
+ return "<";
+ }
+
+ };
+ }
+
+ public static BooleanExpression createLessThanEqual(final Expression left, final Expression right) {
+ checkLessThanOperand(left);
+ checkLessThanOperand(right);
+ return new ComparisonExpression(left, right) {
+
+ protected boolean asBoolean(int answer) {
+ return answer <= 0;
+ }
+
+ public String getExpressionSymbol() {
+ return "<=";
+ }
+ };
+ }
+
+ /**
+ * Only Numeric expressions can be used in >, >=, < or <= expressions.s
+ *
+ * @param expr
+ */
+ public static void checkLessThanOperand(Expression expr) {
+ if (expr instanceof ConstantExpression) {
+ Object value = ((ConstantExpression) expr).getValue();
+ if (value instanceof Number) {
+ return;
+ }
+
+ // Else it's boolean or a String..
+ throw new RuntimeException("Value '" + expr + "' cannot be compared.");
+ }
+ if (expr instanceof BooleanExpression) {
+ throw new RuntimeException("Value '" + expr + "' cannot be compared.");
+ }
+ }
+
+ /**
+ * Validates that the expression can be used in == or <> expression. Cannot
+ * not be NULL TRUE or FALSE litterals.
+ *
+ * @param expr
+ */
+ public static void checkEqualOperand(Expression expr) {
+ if (expr instanceof ConstantExpression) {
+ Object value = ((ConstantExpression) expr).getValue();
+ if (value == null) {
+ throw new RuntimeException("'" + expr + "' cannot be compared.");
+ }
+ }
+ }
+
+ /**
+ * @param left
+ * @param right
+ */
+ private static void checkEqualOperandCompatability(Expression left, Expression right) {
+ if (left instanceof ConstantExpression && right instanceof ConstantExpression) {
+ if (left instanceof BooleanExpression && !(right instanceof BooleanExpression)) {
+ throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'");
+ }
+ }
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public Object evaluate(EvaluationContext context) throws Exception {
+ Comparable<Comparable> lv = (Comparable) left.evaluate(context);
+ if (lv == null) {
+ return null;
+ }
+ Comparable rv = (Comparable) right.evaluate(context);
+ if (rv == null) {
+ return null;
+ }
+ if (getExpressionSymbol().equals(">=") || getExpressionSymbol().equals(">")
+ || getExpressionSymbol().equals("<") || getExpressionSymbol().equals("<=")) {
+ Class<? extends Comparable> lc = lv.getClass();
+ Class<? extends Comparable> rc = rv.getClass();
+ if (lc == rc && lc == String.class) {
+ // Compare String is illegal
+ // first try to convert to double
+ try {
+ Comparable lvC = Double.valueOf((String) (Comparable) lv);
+ Comparable rvC = Double.valueOf((String) rv);
+
+ return compare(lvC, rvC);
+ } catch (Exception e) {
+ throw new RuntimeException("It's illegal to compare string by '>=', '>', '<', '<='. lv=" + lv + ", rv=" + rv, e);
+ }
+ }
+ }
+ return compare(lv, rv);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected static int __compare(Comparable lv, Comparable rv, boolean convertStringExpressions) {
+ Class<? extends Comparable> lc = lv.getClass();
+ Class<? extends Comparable> rc = rv.getClass();
+ // If the the objects are not of the same type,
+ // try to convert up to allow the comparison.
+ if (lc != rc) {
+ try {
+ if (lc == Boolean.class) {
+ if (convertStringExpressions && rc == String.class) {
+ lv = Boolean.valueOf((String) lv).booleanValue();
+ } else {
+ return -1;
+ }
+ } else if (lc == Byte.class) {
+ if (rc == Short.class) {
+ lv = Short.valueOf(((Number) lv).shortValue());
+ } else if (rc == Integer.class) {
+ lv = Integer.valueOf(((Number) lv).intValue());
+ } else if (rc == Long.class) {
+ lv = Long.valueOf(((Number) lv).longValue());
+ } else if (rc == Float.class) {
+ lv = new Float(((Number) lv).floatValue());
+ } else if (rc == Double.class) {
+ lv = new Double(((Number) lv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Byte.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (lc == Short.class) {
+ if (rc == Integer.class) {
+ lv = Integer.valueOf(((Number) lv).intValue());
+ } else if (rc == Long.class) {
+ lv = Long.valueOf(((Number) lv).longValue());
+ } else if (rc == Float.class) {
+ lv = new Float(((Number) lv).floatValue());
+ } else if (rc == Double.class) {
+ lv = new Double(((Number) lv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Short.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (lc == Integer.class) {
+ if (rc == Long.class) {
+ lv = Long.valueOf(((Number) lv).longValue());
+ } else if (rc == Float.class) {
+ lv = new Float(((Number) lv).floatValue());
+ } else if (rc == Double.class) {
+ lv = new Double(((Number) lv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Integer.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (lc == Long.class) {
+ if (rc == Integer.class) {
+ rv = Long.valueOf(((Number) rv).longValue());
+ } else if (rc == Float.class) {
+ lv = new Float(((Number) lv).floatValue());
+ } else if (rc == Double.class) {
+ lv = new Double(((Number) lv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Long.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (lc == Float.class) {
+ if (rc == Integer.class) {
+ rv = new Float(((Number) rv).floatValue());
+ } else if (rc == Long.class) {
+ rv = new Float(((Number) rv).floatValue());
+ } else if (rc == Double.class) {
+ lv = new Double(((Number) lv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Float.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (lc == Double.class) {
+ if (rc == Integer.class) {
+ rv = new Double(((Number) rv).doubleValue());
+ } else if (rc == Long.class) {
+ rv = new Double(((Number) rv).doubleValue());
+ } else if (rc == Float.class) {
+ rv = new Float(((Number) rv).doubleValue());
+ } else if (convertStringExpressions && rc == String.class) {
+ rv = Double.valueOf((String) rv);
+ } else {
+ return -1;
+ }
+ } else if (convertStringExpressions && lc == String.class) {
+ if (rc == Boolean.class) {
+ lv = Boolean.valueOf((String) lv);
+ } else if (rc == Byte.class) {
+ lv = Byte.valueOf((String) lv);
+ } else if (rc == Short.class) {
+ lv = Short.valueOf((String) lv);
+ } else if (rc == Integer.class) {
+ lv = Integer.valueOf((String) lv);
+ } else if (rc == Long.class) {
+ lv = Long.valueOf((String) lv);
+ } else if (rc == Float.class) {
+ lv = Float.valueOf((String) lv);
+ } else if (rc == Double.class) {
+ lv = Double.valueOf((String) lv);
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } catch (NumberFormatException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return lv.compareTo(rv);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ protected Boolean compare(Comparable lv, Comparable rv) {
+ return asBoolean(__compare(lv, rv, convertStringExpressions)) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ protected abstract boolean asBoolean(int answer);
+
+ public boolean matches(EvaluationContext context) throws Exception {
+ Object object = evaluate(context);
+ return object != null && object == Boolean.TRUE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/ConstantExpression.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/ConstantExpression.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/ConstantExpression.java
new file mode 100644
index 0000000..ca70f51
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/ConstantExpression.java
@@ -0,0 +1,156 @@
+/*
+ * 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.filter.expression;
+
+/**
+ * Represents a constant expression
+ * <p>
+ * This class was taken from ActiveMQ org.apache.activemq.filter.ConstantExpression,
+ * but:
+ * 1. For long type constant, the range bound by java Long type;
+ * 2. For float type constant, the range bound by java Double type;
+ * 3. Remove Hex and Octal expression;
+ * 4. Add now expression to support to get current time.
+ * </p>
+ */
+public class ConstantExpression implements Expression {
+
+ static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression {
+ public BooleanConstantExpression(Object value) {
+ super(value);
+ }
+
+ public boolean matches(EvaluationContext context) throws Exception {
+ Object object = evaluate(context);
+ return object != null && object == Boolean.TRUE;
+ }
+ }
+
+ public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null);
+ public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE);
+ public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE);
+
+ private Object value;
+
+ public ConstantExpression(Object value) {
+ this.value = value;
+ }
+
+ public static ConstantExpression createFromDecimal(String text) {
+
+ // Strip off the 'l' or 'L' if needed.
+ if (text.endsWith("l") || text.endsWith("L")) {
+ text = text.substring(0, text.length() - 1);
+ }
+
+ // only support Long.MIN_VALUE ~ Long.MAX_VALUE
+ Number value = new Long(text);
+// try {
+// value = new Long(text);
+// } catch (NumberFormatException e) {
+// // The number may be too big to fit in a long.
+// value = new BigDecimal(text);
+// }
+
+ long l = value.longValue();
+ if (Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE) {
+ value = Integer.valueOf(value.intValue());
+ }
+ return new ConstantExpression(value);
+ }
+
+ public static ConstantExpression createFloat(String text) {
+ Double value = new Double(text);
+ if (value > Double.MAX_VALUE) {
+ throw new RuntimeException(text + " is greater than " + Double.MAX_VALUE);
+ }
+ if (value < Double.MIN_VALUE) {
+ throw new RuntimeException(text + " is less than " + Double.MIN_VALUE);
+ }
+ return new ConstantExpression(value);
+ }
+
+ public static ConstantExpression createNow() {
+ return new NowExpression();
+ }
+
+ public Object evaluate(EvaluationContext context) throws Exception {
+ return value;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * @see Object#toString()
+ */
+ public String toString() {
+ Object value = getValue();
+ if (value == null) {
+ return "NULL";
+ }
+ if (value instanceof Boolean) {
+ return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE";
+ }
+ if (value instanceof String) {
+ return encodeString((String) value);
+ }
+ return value.toString();
+ }
+
+ /**
+ * @see Object#hashCode()
+ */
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ /**
+ * @see Object#equals(Object)
+ */
+ public boolean equals(Object o) {
+
+ if (o == null || !this.getClass().equals(o.getClass())) {
+ return false;
+ }
+ return toString().equals(o.toString());
+
+ }
+
+ /**
+ * Encodes the value of string so that it looks like it would look like when
+ * it was provided in a selector.
+ *
+ * @return
+ */
+ public static String encodeString(String s) {
+ StringBuffer b = new StringBuffer();
+ b.append('\'');
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '\'') {
+ b.append(c);
+ }
+ b.append(c);
+ }
+ b.append('\'');
+ return b.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/EmptyEvaluationContext.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/EmptyEvaluationContext.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/EmptyEvaluationContext.java
new file mode 100644
index 0000000..52af2d0
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/EmptyEvaluationContext.java
@@ -0,0 +1,35 @@
+/*
+ * 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.filter.expression;
+
+import java.util.Map;
+
+/**
+ * Empty context.
+ */
+public class EmptyEvaluationContext implements EvaluationContext {
+ @Override
+ public Object get(String name) {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> keyValues() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/58f1574b/filter/src/main/java/org/apache/rocketmq/filter/expression/EvaluationContext.java
----------------------------------------------------------------------
diff --git a/filter/src/main/java/org/apache/rocketmq/filter/expression/EvaluationContext.java b/filter/src/main/java/org/apache/rocketmq/filter/expression/EvaluationContext.java
new file mode 100644
index 0000000..094ef53
--- /dev/null
+++ b/filter/src/main/java/org/apache/rocketmq/filter/expression/EvaluationContext.java
@@ -0,0 +1,43 @@
+/*
+ * 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.filter.expression;
+
+import java.util.Map;
+
+/**
+ * Context of evaluate expression.
+ *
+ * Compare to org.apache.activemq.filter.MessageEvaluationContext, this is just an interface.
+ */
+public interface EvaluationContext {
+
+ /**
+ * Get value by name from context
+ *
+ * @param name
+ * @return
+ */
+ Object get(String name);
+
+ /**
+ * Context variables.
+ *
+ * @return
+ */
+ Map<String, Object> keyValues();
+}
[48/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-219] Add
batch example, closes apache/incubator-rocketmq#112
Posted by do...@apache.org.
[ROCKETMQ-219] Add batch example, closes apache/incubator-rocketmq#112
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/f45a1bcd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/f45a1bcd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/f45a1bcd
Branch: refs/heads/release-4.1.0-incubating
Commit: f45a1bcd2b42423050e6bd28c5fb92f5c47e263e
Parents: 703ac00
Author: dongeforever <zh...@yeah.net>
Authored: Thu Jun 8 11:13:24 2017 +0800
Committer: yukon <yu...@apache.org>
Committed: Thu Jun 8 11:20:40 2017 +0800
----------------------------------------------------------------------
.../example/batch/SimpleBatchProducer.java | 42 +++++++++
.../example/batch/SplitBatchProducer.java | 97 ++++++++++++++++++++
2 files changed, 139 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f45a1bcd/example/src/main/java/org/apache/rocketmq/example/batch/SimpleBatchProducer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/batch/SimpleBatchProducer.java b/example/src/main/java/org/apache/rocketmq/example/batch/SimpleBatchProducer.java
new file mode 100644
index 0000000..a8609e7
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/batch/SimpleBatchProducer.java
@@ -0,0 +1,42 @@
+/*
+ * 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.example.batch;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.message.Message;
+
+public class SimpleBatchProducer {
+
+
+ public static void main(String[] args) throws Exception {
+ DefaultMQProducer producer = new DefaultMQProducer("BatchProducerGroupName");
+ producer.start();
+
+ //If you just send messages of no more than 1MiB at a time, it is easy to use batch
+ //Messages of the same batch should have: same topic, same waitStoreMsgOK and no schedule support
+ String topic = "BatchTest";
+ List<Message> messages = new ArrayList<>();
+ messages.add(new Message(topic, "Tag", "OrderID001", "Hello world 0".getBytes()));
+ messages.add(new Message(topic, "Tag", "OrderID002", "Hello world 1".getBytes()));
+ messages.add(new Message(topic, "Tag", "OrderID003", "Hello world 2".getBytes()));
+
+ producer.send(messages);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/f45a1bcd/example/src/main/java/org/apache/rocketmq/example/batch/SplitBatchProducer.java
----------------------------------------------------------------------
diff --git a/example/src/main/java/org/apache/rocketmq/example/batch/SplitBatchProducer.java b/example/src/main/java/org/apache/rocketmq/example/batch/SplitBatchProducer.java
new file mode 100644
index 0000000..8809a11
--- /dev/null
+++ b/example/src/main/java/org/apache/rocketmq/example/batch/SplitBatchProducer.java
@@ -0,0 +1,97 @@
+/*
+ * 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.example.batch;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.common.message.Message;
+
+public class SplitBatchProducer {
+
+ public static void main(String[] args) throws Exception {
+
+ DefaultMQProducer producer = new DefaultMQProducer("BatchProducerGroupName");
+ producer.start();
+
+ //large batch
+ String topic = "BatchTest";
+ List<Message> messages = new ArrayList<>(100 * 1000);
+ for (int i = 0; i < 100 * 1000; i++) {
+ messages.add(new Message(topic, "Tag", "OrderID" + i, ("Hello world " + i).getBytes()));
+ }
+
+ //split the large batch into small ones:
+ ListSplitter splitter = new ListSplitter(messages);
+ while (splitter.hasNext()) {
+ List<Message> listItem = splitter.next();
+ producer.send(listItem);
+ }
+ }
+
+}
+
+
+class ListSplitter implements Iterator<List<Message>> {
+ private int sizeLimit = 1000 * 1000;
+ private final List<Message> messages;
+ private int currIndex;
+ public ListSplitter(List<Message> messages) {
+ this.messages = messages;
+ }
+ @Override public boolean hasNext() {
+ return currIndex < messages.size();
+ }
+ @Override public List<Message> next() {
+ int nextIndex = currIndex;
+ int totalSize = 0;
+ for (; nextIndex < messages.size(); nextIndex++) {
+ Message message = messages.get(nextIndex);
+ int tmpSize = message.getTopic().length() + message.getBody().length;
+ Map<String, String> properties = message.getProperties();
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+ tmpSize += entry.getKey().length() + entry.getValue().length();
+ }
+ tmpSize = tmpSize + 20; //for log overhead
+ if (tmpSize > sizeLimit) {
+ //it is unexpected that single message exceeds the sizeLimit
+ //here just let it go, otherwise it will block the splitting process
+ if (nextIndex - currIndex == 0) {
+ //if the next sublist has no element, add this one and then break, otherwise just break
+ nextIndex++;
+ }
+ break;
+ }
+ if (tmpSize + totalSize > sizeLimit) {
+ break;
+ } else {
+ totalSize += tmpSize;
+ }
+
+ }
+ List<Message> subList = messages.subList(currIndex, nextIndex);
+ currIndex = nextIndex;
+ return subList;
+ }
+
+ @Override public void remove() {
+ throw new UnsupportedOperationException("Not allowed to remove");
+ }
+}
[13/50] [abbrv] incubator-rocketmq git commit: Add javadoc to
NettyRemotingAbstract class and several other trivial clean up.
Posted by do...@apache.org.
Add javadoc to NettyRemotingAbstract class and several other trivial clean up.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/6609c866
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/6609c866
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/6609c866
Branch: refs/heads/release-4.1.0-incubating
Commit: 6609c86650917ebfb5bd12a4bd8b1bcf9c477759
Parents: 6a9628b
Author: Zhanhui Li <li...@apache.org>
Authored: Tue Apr 25 22:58:14 2017 +0800
Committer: Zhanhui Li <li...@apache.org>
Committed: Tue Apr 25 22:58:14 2017 +0800
----------------------------------------------------------------------
.../remoting/netty/NettyRemotingAbstract.java | 93 ++++++++++++++++++--
.../remoting/netty/NettyRemotingClient.java | 19 ++--
.../remoting/netty/NettyRemotingServer.java | 22 ++---
3 files changed, 106 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6609c866/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
index 83eeb02..cddab3d 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java
@@ -48,32 +48,84 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class NettyRemotingAbstract {
+
+ /**
+ * Remoting logger instance.
+ */
private static final Logger PLOG = LoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
+ /**
+ * Semaphore to limit maximum number of on-going one-way requests, which protects system memory footprint.
+ */
protected final Semaphore semaphoreOneway;
+ /**
+ * Semaphore to limit maximum number of on-going asynchronous requests, which protects system memory footprint.
+ */
protected final Semaphore semaphoreAsync;
+ /**
+ * This map caches all on-going requests.
+ */
protected final ConcurrentHashMap<Integer /* opaque */, ResponseFuture> responseTable =
new ConcurrentHashMap<Integer, ResponseFuture>(256);
+ /**
+ * This container holds all processors per request code, aka, for each incoming request, we may look up the
+ * responding processor in this map to handle the request.
+ */
protected final HashMap<Integer/* request code */, Pair<NettyRequestProcessor, ExecutorService>> processorTable =
new HashMap<Integer, Pair<NettyRequestProcessor, ExecutorService>>(64);
- protected final NettyEventExecuter nettyEventExecuter = new NettyEventExecuter();
+ /**
+ * Executor to feed netty events to user defined {@link ChannelEventListener}.
+ */
+ protected final NettyEventExecutor nettyEventExecutor = new NettyEventExecutor();
+
+ /**
+ * The default request processor to use in case there is no exact match in {@link #processorTable} per request code.
+ */
protected Pair<NettyRequestProcessor, ExecutorService> defaultRequestProcessor;
+ /**
+ * Constructor, specifying capacity of one-way and asynchronous semaphores.
+ * @param permitsOneway Number of permits for one-way requests.
+ * @param permitsAsync Number of permits for asynchronous requests.
+ */
public NettyRemotingAbstract(final int permitsOneway, final int permitsAsync) {
this.semaphoreOneway = new Semaphore(permitsOneway, true);
this.semaphoreAsync = new Semaphore(permitsAsync, true);
}
+ /**
+ * Custom channel event listener.
+ * @return custom channel event listener if defined; null otherwise.
+ */
public abstract ChannelEventListener getChannelEventListener();
+ /**
+ * Put a netty event to the executor.
+ * @param event Netty event instance.
+ */
public void putNettyEvent(final NettyEvent event) {
- this.nettyEventExecuter.putNettyEvent(event);
+ this.nettyEventExecutor.putNettyEvent(event);
}
+ /**
+ * Entry of incoming command processing.
+ *
+ * <p>
+ * <strong>Note:</strong>
+ * The incoming remoting command may be
+ * <ul>
+ * <li>An inquiry request from a remote peer component;</li>
+ * <li>A response to a previous request issued by this very participant.</li>
+ * </ul>
+ * </p>
+ * @param ctx Channel handler context.
+ * @param msg incoming remoting command.
+ * @throws Exception if there were any error while processing the incoming command.
+ */
public void processMessageReceived(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
final RemotingCommand cmd = msg;
if (cmd != null) {
@@ -90,6 +142,11 @@ public abstract class NettyRemotingAbstract {
}
}
+ /**
+ * Process incoming request command issued by remote peer.
+ * @param ctx channel handler context.
+ * @param cmd request command.
+ */
public void processRequestCommand(final ChannelHandlerContext ctx, final RemotingCommand cmd) {
final Pair<NettyRequestProcessor, ExecutorService> matched = this.processorTable.get(cmd.getCode());
final Pair<NettyRequestProcessor, ExecutorService> pair = null == matched ? this.defaultRequestProcessor : matched;
@@ -175,6 +232,11 @@ public abstract class NettyRemotingAbstract {
}
}
+ /**
+ * Process response from remote peer to the previous issued requests.
+ * @param ctx channel handler context.
+ * @param cmd response command instance.
+ */
public void processResponseCommand(ChannelHandlerContext ctx, RemotingCommand cmd) {
final int opaque = cmd.getOpaque();
final ResponseFuture responseFuture = responseTable.get(opaque);
@@ -196,7 +258,10 @@ public abstract class NettyRemotingAbstract {
}
}
- //execute callback in callback executor. If callback executor is null, run directly in current thread
+ /**
+ * Execute callback in callback executor. If callback executor is null, run directly in current thread
+ * @param responseFuture
+ */
private void executeInvokeCallback(final ResponseFuture responseFuture) {
boolean runInThisThread = false;
ExecutorService executor = this.getCallbackExecutor();
@@ -229,10 +294,24 @@ public abstract class NettyRemotingAbstract {
}
}
+ /**
+ * Custom RPC hook.
+ * @return RPC hook if specified; null otherwise.
+ */
public abstract RPCHook getRPCHook();
- abstract public ExecutorService getCallbackExecutor();
-
+ /**
+ * This method specifies thread pool to use while invoking callback methods.
+ * @return Dedicated thread pool instance if specified; or null if the callback is supposed to be executed in the
+ * netty event-loop thread.
+ */
+ public abstract ExecutorService getCallbackExecutor();
+
+ /**
+ * <p>
+ * This method is periodically invoked to scan and expire deprecated request.
+ * </p>
+ */
public void scanResponseTable() {
final List<ResponseFuture> rfList = new LinkedList<ResponseFuture>();
Iterator<Entry<Integer, ResponseFuture>> it = this.responseTable.entrySet().iterator();
@@ -386,7 +465,7 @@ public abstract class NettyRemotingAbstract {
}
}
- class NettyEventExecuter extends ServiceThread {
+ class NettyEventExecutor extends ServiceThread {
private final LinkedBlockingQueue<NettyEvent> eventQueue = new LinkedBlockingQueue<NettyEvent>();
private final int maxSize = 10000;
@@ -436,7 +515,7 @@ public abstract class NettyRemotingAbstract {
@Override
public String getServiceName() {
- return NettyEventExecuter.class.getSimpleName();
+ return NettyEventExecutor.class.getSimpleName();
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6609c866/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
index 26088aa..52ca47e 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java
@@ -172,7 +172,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
}, 1000 * 3, 1000);
if (this.channelEventListener != null) {
- this.nettyEventExecuter.start();
+ this.nettyEventExecutor.start();
}
}
@@ -189,8 +189,8 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
this.eventLoopGroupWorker.shutdownGracefully();
- if (this.nettyEventExecuter != null) {
- this.nettyEventExecuter.shutdown();
+ if (this.nettyEventExecutor != null) {
+ this.nettyEventExecutor.shutdown();
}
if (this.defaultEventExecutorGroup != null) {
@@ -586,7 +586,6 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
@Override
protected void channelRead0(ChannelHandlerContext ctx, RemotingCommand msg) throws Exception {
processMessageReceived(ctx, msg);
-
}
}
@@ -594,8 +593,8 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
ChannelPromise promise) throws Exception {
- final String local = localAddress == null ? "UNKNOWN" : localAddress.toString();
- final String remote = remoteAddress == null ? "UNKNOWN" : remoteAddress.toString();
+ final String local = localAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(localAddress);
+ final String remote = remoteAddress == null ? "UNKNOWN" : RemotingHelper.parseSocketAddressAddr(remoteAddress);
log.info("NETTY CLIENT PIPELINE: CONNECT {} => {}", local, remote);
super.connect(ctx, remoteAddress, localAddress, promise);
@@ -613,7 +612,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
super.disconnect(ctx, promise);
if (NettyRemotingClient.this.channelEventListener != null) {
- NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
}
}
@@ -625,7 +624,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
super.close(ctx, promise);
if (NettyRemotingClient.this.channelEventListener != null) {
- NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
}
}
@@ -639,7 +638,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
closeChannel(ctx.channel());
if (NettyRemotingClient.this.channelEventListener != null) {
NettyRemotingClient.this
- .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress.toString(), ctx.channel()));
+ .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
}
}
}
@@ -654,7 +653,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti
log.warn("NETTY CLIENT PIPELINE: exceptionCaught exception.", cause);
closeChannel(ctx.channel());
if (NettyRemotingClient.this.channelEventListener != null) {
- NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingClient.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/6609c866/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
index 6a6df37..d8d9b65 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
@@ -160,7 +160,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
new NettyEncoder(),
new NettyDecoder(),
new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
- new NettyConnetManageHandler(),
+ new NettyConnectManageHandler(),
new NettyServerHandler());
}
});
@@ -178,7 +178,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
}
if (this.channelEventListener != null) {
- this.nettyEventExecuter.start();
+ this.nettyEventExecutor.start();
}
this.timer.scheduleAtFixedRate(new TimerTask() {
@@ -205,8 +205,8 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
this.eventLoopGroupSelector.shutdownGracefully();
- if (this.nettyEventExecuter != null) {
- this.nettyEventExecuter.shutdown();
+ if (this.nettyEventExecutor != null) {
+ this.nettyEventExecutor.shutdown();
}
if (this.defaultEventExecutorGroup != null) {
@@ -297,7 +297,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
}
}
- class NettyConnetManageHandler extends ChannelDuplexHandler {
+ class NettyConnectManageHandler extends ChannelDuplexHandler {
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
@@ -319,7 +319,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
super.channelActive(ctx);
if (NettyRemotingServer.this.channelEventListener != null) {
- NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CONNECT, remoteAddress, ctx.channel()));
}
}
@@ -330,21 +330,21 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
super.channelInactive(ctx);
if (NettyRemotingServer.this.channelEventListener != null) {
- NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.CLOSE, remoteAddress, ctx.channel()));
}
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
- IdleStateEvent evnet = (IdleStateEvent) evt;
- if (evnet.state().equals(IdleState.ALL_IDLE)) {
+ IdleStateEvent event = (IdleStateEvent) evt;
+ if (event.state().equals(IdleState.ALL_IDLE)) {
final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
log.warn("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddress);
RemotingUtil.closeChannel(ctx.channel());
if (NettyRemotingServer.this.channelEventListener != null) {
NettyRemotingServer.this
- .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress.toString(), ctx.channel()));
+ .putNettyEvent(new NettyEvent(NettyEventType.IDLE, remoteAddress, ctx.channel()));
}
}
}
@@ -359,7 +359,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
log.warn("NETTY SERVER PIPELINE: exceptionCaught exception.", cause);
if (NettyRemotingServer.this.channelEventListener != null) {
- NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress.toString(), ctx.channel()));
+ NettyRemotingServer.this.putNettyEvent(new NettyEvent(NettyEventType.EXCEPTION, remoteAddress, ctx.channel()));
}
RemotingUtil.closeChannel(ctx.channel());
[38/50] [abbrv] incubator-rocketmq git commit: Merge remote-tracking
branch 'wip/ROCKETMQ-206' into develop
Posted by do...@apache.org.
Merge remote-tracking branch 'wip/ROCKETMQ-206' into develop
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/e57f9ac4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/e57f9ac4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/e57f9ac4
Branch: refs/heads/release-4.1.0-incubating
Commit: e57f9ac433bdf4ec640089ccaf580954e93f50dc
Parents: 04c8925 aced0de
Author: dongeforever <zh...@yeah.net>
Authored: Sat May 27 12:39:25 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Sat May 27 12:39:25 2017 +0800
----------------------------------------------------------------------
.../client/consumer/store/LocalFileOffsetStore.java | 14 ++++++++++++--
.../apache/rocketmq/example/benchmark/Consumer.java | 3 ++-
.../org/apache/rocketmq/example/filter/Consumer.java | 3 ++-
.../rocketmq/namesrv/kvconfig/KVConfigManager.java | 7 ++++++-
4 files changed, 22 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
[27/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-175] Consumer may miss messages because of inconsistent sub… closes apache/incubator-rocketmq#92
Posted by do...@apache.org.
[ROCKETMQ-175] Consumer may miss messages because of inconsistent sub… closes apache/incubator-rocketmq#92
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/82803889
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/82803889
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/82803889
Branch: refs/heads/release-4.1.0-incubating
Commit: 8280388917c466d030ffb774a2474ca8e4144811
Parents: 42826c4
Author: vsair <li...@gmail.com>
Authored: Fri May 26 15:13:29 2017 +0800
Committer: dongeforever <zh...@yeah.net>
Committed: Fri May 26 15:13:29 2017 +0800
----------------------------------------------------------------------
.../rocketmq/client/impl/consumer/RebalancePushImpl.java | 11 +++++++++++
1 file changed, 11 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/82803889/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
index 1730c99..509c9a4 100644
--- a/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
+++ b/client/src/main/java/org/apache/rocketmq/client/impl/consumer/RebalancePushImpl.java
@@ -30,6 +30,7 @@ import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.protocol.heartbeat.ConsumeType;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
+import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
public class RebalancePushImpl extends RebalanceImpl {
private final static long UNLOCK_DELAY_TIME_MILLS = Long.parseLong(System.getProperty("rocketmq.client.unlockDelayTimeMills", "20000"));
@@ -47,6 +48,16 @@ public class RebalancePushImpl extends RebalanceImpl {
@Override
public void messageQueueChanged(String topic, Set<MessageQueue> mqAll, Set<MessageQueue> mqDivided) {
+ /**
+ * When rebalance result changed, should update subscription's version to notify broker.
+ * Fix: inconsistency subscription may lead to consumer miss messages.
+ */
+ SubscriptionData subscriptionData = this.subscriptionInner.get(topic);
+ long newVersion = System.currentTimeMillis();
+ log.info("{} Rebalance changed, also update version: {}, {}", topic, subscriptionData.getSubVersion(), newVersion);
+ subscriptionData.setSubVersion(newVersion);
+ // notify broker
+ this.getmQClientFactory().sendHeartbeatToAllBrokerWithLock();
}
@Override
[19/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-191] Fix
socket options
Posted by do...@apache.org.
[ROCKETMQ-191] Fix socket options
Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/80aac138
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/80aac138
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/80aac138
Branch: refs/heads/release-4.1.0-incubating
Commit: 80aac138d905561c7a63c8e15fdfe60e958a3032
Parents: f5a2ee0
Author: Li Zhanhui <li...@apache.org>
Authored: Wed May 10 10:44:34 2017 +0800
Committer: Li Zhanhui <li...@apache.org>
Committed: Wed May 10 10:44:34 2017 +0800
----------------------------------------------------------------------
.../remoting/netty/NettyRemotingServer.java | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/80aac138/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
----------------------------------------------------------------------
diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
index d8d9b65..a9a55ab 100644
--- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
+++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java
@@ -26,7 +26,9 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
@@ -105,8 +107,7 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
}
});
- if (RemotingUtil.isLinuxPlatform() //
- && nettyServerConfig.isUseEpollNativeSelector()) {
+ if (useEpoll()) {
this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
private int threadTotal = nettyServerConfig.getServerSelectorThreads();
@@ -129,6 +130,12 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
}
}
+ private boolean useEpoll() {
+ return RemotingUtil.isLinuxPlatform()
+ && nettyServerConfig.isUseEpollNativeSelector()
+ && Epoll.isAvailable();
+ }
+
@Override
public void start() {
this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(
@@ -144,13 +151,14 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti
});
ServerBootstrap childHandler =
- this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector).channel(NioServerSocketChannel.class)
+ this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
+ .channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.SO_KEEPALIVE, false)
.childOption(ChannelOption.TCP_NODELAY, true)
- .option(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
- .option(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())
+ .childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize())
+ .childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize())
.localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
[21/50] [abbrv] incubator-rocketmq git commit: [ROCKETMQ-186]
Implement the OpenMessaging specification 0.1.0-alpha version
Posted by do...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/FutureState.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/FutureState.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/FutureState.java
new file mode 100644
index 0000000..84b6c2d
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/promise/FutureState.java
@@ -0,0 +1,51 @@
+/*
+ * 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 io.openmessaging.rocketmq.promise;
+
+public enum FutureState {
+ /**
+ * the task is doing
+ **/
+ DOING(0),
+ /**
+ * the task is done
+ **/
+ DONE(1),
+ /**
+ * ths task is cancelled
+ **/
+ CANCELLED(2);
+
+ public final int value;
+
+ private FutureState(int value) {
+ this.value = value;
+ }
+
+ public boolean isCancelledState() {
+ return this == CANCELLED;
+ }
+
+ public boolean isDoneState() {
+ return this == DONE;
+ }
+
+ public boolean isDoingState() {
+ return this == DOING;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/BeanUtils.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/BeanUtils.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/BeanUtils.java
new file mode 100644
index 0000000..104d3d9
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/BeanUtils.java
@@ -0,0 +1,185 @@
+/*
+ * 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 io.openmessaging.rocketmq.utils;
+
+import io.openmessaging.KeyValue;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.rocketmq.client.log.ClientLogger;
+import org.slf4j.Logger;
+
+public final class BeanUtils {
+ final static Logger log = ClientLogger.getLog();
+
+ /**
+ * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
+ */
+ private static Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>();
+
+ static {
+ primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
+ primitiveWrapperMap.put(Byte.TYPE, Byte.class);
+ primitiveWrapperMap.put(Character.TYPE, Character.class);
+ primitiveWrapperMap.put(Short.TYPE, Short.class);
+ primitiveWrapperMap.put(Integer.TYPE, Integer.class);
+ primitiveWrapperMap.put(Long.TYPE, Long.class);
+ primitiveWrapperMap.put(Double.TYPE, Double.class);
+ primitiveWrapperMap.put(Float.TYPE, Float.class);
+ primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
+ }
+
+ private static Map<Class<?>, Class<?>> wrapperMap = new HashMap<Class<?>, Class<?>>();
+
+ static {
+ for (final Class<?> primitiveClass : primitiveWrapperMap.keySet()) {
+ final Class<?> wrapperClass = primitiveWrapperMap.get(primitiveClass);
+ if (!primitiveClass.equals(wrapperClass)) {
+ wrapperMap.put(wrapperClass, primitiveClass);
+ }
+ }
+ wrapperMap.put(String.class, String.class);
+ }
+
+ /**
+ * <p>Populate the JavaBeans properties of the specified bean, based on
+ * the specified name/value pairs. This method uses Java reflection APIs
+ * to identify corresponding "property setter" method names, and deals
+ * with setter arguments of type <Code>String</Code>, <Code>boolean</Code>,
+ * <Code>int</Code>, <Code>long</Code>, <Code>float</Code>, and
+ * <Code>double</Code>.</p>
+ *
+ * <p>The particular setter method to be called for each property is
+ * determined using the usual JavaBeans introspection mechanisms. Thus,
+ * you may identify custom setter methods using a BeanInfo class that is
+ * associated with the class of the bean itself. If no such BeanInfo
+ * class is available, the standard method name conversion ("set" plus
+ * the capitalized name of the property in question) is used.</p>
+ *
+ * <p><strong>NOTE</strong>: It is contrary to the JavaBeans Specification
+ * to have more than one setter method (with different argument
+ * signatures) for the same property.</p>
+ *
+ * @param clazz JavaBean class whose properties are being populated
+ * @param properties Map keyed by property name, with the corresponding (String or String[]) value(s) to be set
+ * @param <T> Class type
+ * @return Class instance
+ */
+ public static <T> T populate(final Properties properties, final Class<T> clazz) {
+ T obj = null;
+ try {
+ obj = clazz.newInstance();
+ return populate(properties, obj);
+ } catch (Throwable e) {
+ log.warn("Error occurs !", e);
+ }
+ return obj;
+ }
+
+ public static <T> T populate(final KeyValue properties, final Class<T> clazz) {
+ T obj = null;
+ try {
+ obj = clazz.newInstance();
+ return populate(properties, obj);
+ } catch (Throwable e) {
+ log.warn("Error occurs !", e);
+ }
+ return obj;
+ }
+
+ public static Class<?> getMethodClass(Class<?> clazz, String methodName) {
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ if (method.getName().equalsIgnoreCase(methodName)) {
+ return method.getParameterTypes()[0];
+ }
+ }
+ return null;
+ }
+
+ public static void setProperties(Class<?> clazz, Object obj, String methodName,
+ Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+ Class<?> parameterClass = getMethodClass(clazz, methodName);
+ Method setterMethod = clazz.getMethod(methodName, parameterClass);
+ if (parameterClass == Boolean.TYPE) {
+ setterMethod.invoke(obj, Boolean.valueOf(value.toString()));
+ } else if (parameterClass == Integer.TYPE) {
+ setterMethod.invoke(obj, Integer.valueOf(value.toString()));
+ } else if (parameterClass == Double.TYPE) {
+ setterMethod.invoke(obj, Double.valueOf(value.toString()));
+ } else if (parameterClass == Float.TYPE) {
+ setterMethod.invoke(obj, Float.valueOf(value.toString()));
+ } else if (parameterClass == Long.TYPE) {
+ setterMethod.invoke(obj, Long.valueOf(value.toString()));
+ } else
+ setterMethod.invoke(obj, value);
+ }
+
+ public static <T> T populate(final Properties properties, final T obj) {
+ Class<?> clazz = obj.getClass();
+ try {
+
+ Set<Map.Entry<Object, Object>> entries = properties.entrySet();
+ for (Map.Entry<Object, Object> entry : entries) {
+ String entryKey = entry.getKey().toString();
+ String[] keyGroup = entryKey.split("\\.");
+ for (int i = 0; i < keyGroup.length; i++) {
+ keyGroup[i] = keyGroup[i].toLowerCase();
+ keyGroup[i] = StringUtils.capitalize(keyGroup[i]);
+ }
+ String beanFieldNameWithCapitalization = StringUtils.join(keyGroup);
+ try {
+ setProperties(clazz, obj, "set" + beanFieldNameWithCapitalization, entry.getValue());
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
+ //ignored...
+ }
+ }
+ } catch (RuntimeException e) {
+ log.warn("Error occurs !", e);
+ }
+ return obj;
+ }
+
+ public static <T> T populate(final KeyValue properties, final T obj) {
+ Class<?> clazz = obj.getClass();
+ try {
+
+ final Set<String> keySet = properties.keySet();
+ for (String key : keySet) {
+ String[] keyGroup = key.split("\\.");
+ for (int i = 0; i < keyGroup.length; i++) {
+ keyGroup[i] = keyGroup[i].toLowerCase();
+ keyGroup[i] = StringUtils.capitalize(keyGroup[i]);
+ }
+ String beanFieldNameWithCapitalization = StringUtils.join(keyGroup);
+ try {
+ setProperties(clazz, obj, "set" + beanFieldNameWithCapitalization, properties.getString(key));
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ignored) {
+ //ignored...
+ }
+ }
+ } catch (RuntimeException e) {
+ log.warn("Error occurs !", e);
+ }
+ return obj;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/OMSUtil.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/OMSUtil.java b/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/OMSUtil.java
new file mode 100644
index 0000000..60c8408
--- /dev/null
+++ b/openmessaging/src/main/java/io/openmessaging/rocketmq/utils/OMSUtil.java
@@ -0,0 +1,182 @@
+/*
+ * 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 io.openmessaging.rocketmq.utils;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.KeyValue;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.OMS;
+import io.openmessaging.SendResult;
+import io.openmessaging.rocketmq.domain.BytesMessageImpl;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import io.openmessaging.rocketmq.domain.SendResultImpl;
+import java.lang.reflect.Field;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.UtilAll;
+import org.apache.rocketmq.common.message.MessageAccessor;
+
+public class OMSUtil {
+
+ /**
+ * Builds a OMS client instance name.
+ *
+ * @return a unique instance name
+ */
+ public static String buildInstanceName() {
+ return Integer.toString(UtilAll.getPid()) + "%OpenMessaging" + "%" + System.nanoTime();
+ }
+
+ public static org.apache.rocketmq.common.message.Message msgConvert(BytesMessage omsMessage) {
+ org.apache.rocketmq.common.message.Message rmqMessage = new org.apache.rocketmq.common.message.Message();
+ rmqMessage.setBody(omsMessage.getBody());
+
+ KeyValue headers = omsMessage.headers();
+ KeyValue properties = omsMessage.properties();
+
+ //All destinations in RocketMQ use Topic
+ if (headers.containsKey(MessageHeader.TOPIC)) {
+ rmqMessage.setTopic(headers.getString(MessageHeader.TOPIC));
+ rmqMessage.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC");
+ } else {
+ rmqMessage.setTopic(headers.getString(MessageHeader.QUEUE));
+ rmqMessage.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "QUEUE");
+ }
+
+ for (String key : properties.keySet()) {
+ MessageAccessor.putProperty(rmqMessage, key, properties.getString(key));
+ }
+
+ //Headers has a high priority
+ for (String key : headers.keySet()) {
+ MessageAccessor.putProperty(rmqMessage, key, headers.getString(key));
+ }
+
+ return rmqMessage;
+ }
+
+ public static BytesMessage msgConvert(org.apache.rocketmq.common.message.MessageExt rmqMsg) {
+ BytesMessage omsMsg = new BytesMessageImpl();
+ omsMsg.setBody(rmqMsg.getBody());
+
+ KeyValue headers = omsMsg.headers();
+ KeyValue properties = omsMsg.properties();
+
+ final Set<Map.Entry<String, String>> entries = rmqMsg.getProperties().entrySet();
+
+ for (final Map.Entry<String, String> entry : entries) {
+ if (isOMSHeader(entry.getKey())) {
+ headers.put(entry.getKey(), entry.getValue());
+ } else {
+ properties.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ omsMsg.putHeaders(MessageHeader.MESSAGE_ID, rmqMsg.getMsgId());
+ if (!rmqMsg.getProperties().containsKey(NonStandardKeys.MESSAGE_DESTINATION) ||
+ rmqMsg.getProperties().get(NonStandardKeys.MESSAGE_DESTINATION).equals("TOPIC")) {
+ omsMsg.putHeaders(MessageHeader.TOPIC, rmqMsg.getTopic());
+ } else {
+ omsMsg.putHeaders(MessageHeader.QUEUE, rmqMsg.getTopic());
+ }
+ omsMsg.putHeaders(MessageHeader.SEARCH_KEY, rmqMsg.getKeys());
+ omsMsg.putHeaders(MessageHeader.BORN_HOST, String.valueOf(rmqMsg.getBornHost()));
+ omsMsg.putHeaders(MessageHeader.BORN_TIMESTAMP, rmqMsg.getBornTimestamp());
+ omsMsg.putHeaders(MessageHeader.STORE_HOST, String.valueOf(rmqMsg.getStoreHost()));
+ omsMsg.putHeaders(MessageHeader.STORE_TIMESTAMP, rmqMsg.getStoreTimestamp());
+ return omsMsg;
+ }
+
+ public static boolean isOMSHeader(String value) {
+ for (Field field : MessageHeader.class.getDeclaredFields()) {
+ try {
+ if (field.get(MessageHeader.class).equals(value)) {
+ return true;
+ }
+ } catch (IllegalAccessException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Convert a RocketMQ SEND_OK SendResult instance to a OMS SendResult.
+ */
+ public static SendResult sendResultConvert(org.apache.rocketmq.client.producer.SendResult rmqResult) {
+ assert rmqResult.getSendStatus().equals(SendStatus.SEND_OK);
+ return new SendResultImpl(rmqResult.getMsgId(), OMS.newKeyValue());
+ }
+
+ public static KeyValue buildKeyValue(KeyValue... keyValues) {
+ KeyValue keyValue = OMS.newKeyValue();
+ for (KeyValue properties : keyValues) {
+ for (String key : properties.keySet()) {
+ keyValue.put(key, properties.getString(key));
+ }
+ }
+ return keyValue;
+ }
+
+ /**
+ * Returns an iterator that cycles indefinitely over the elements of {@code Iterable}.
+ */
+ public static <T> Iterator<T> cycle(final Iterable<T> iterable) {
+ return new Iterator<T>() {
+ Iterator<T> iterator = new Iterator<T>() {
+ @Override
+ public synchronized boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public synchronized T next() {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ public synchronized void remove() {
+ //Ignore
+ }
+ };
+
+ @Override
+ public synchronized boolean hasNext() {
+ return iterator.hasNext() || iterable.iterator().hasNext();
+ }
+
+ @Override
+ public synchronized T next() {
+ if (!iterator.hasNext()) {
+ iterator = iterable.iterator();
+ if (!iterator.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ }
+ return iterator.next();
+ }
+
+ @Override
+ public synchronized void remove() {
+ iterator.remove();
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/LocalMessageCacheTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/LocalMessageCacheTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/LocalMessageCacheTest.java
new file mode 100644
index 0000000..ae4d3ed
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/LocalMessageCacheTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.ConsumeRequest;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.common.message.MessageQueue;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class LocalMessageCacheTest {
+ private LocalMessageCache localMessageCache;
+ @Mock
+ private DefaultMQPullConsumer rocketmqPullConsume;
+ @Mock
+ private ConsumeRequest consumeRequest;
+
+ @Before
+ public void init() {
+ ClientConfig clientConfig = new ClientConfig();
+ clientConfig.setRmqPullMessageBatchNums(512);
+ clientConfig.setRmqPullMessageCacheCapacity(1024);
+ localMessageCache = new LocalMessageCache(rocketmqPullConsume, clientConfig);
+ }
+
+ @Test
+ public void testNextPullBatchNums() throws Exception {
+ assertThat(localMessageCache.nextPullBatchNums()).isEqualTo(512);
+ for (int i = 0; i < 513; i++) {
+ localMessageCache.submitConsumeRequest(consumeRequest);
+ }
+ assertThat(localMessageCache.nextPullBatchNums()).isEqualTo(511);
+ }
+
+ @Test
+ public void testNextPullOffset() throws Exception {
+ MessageQueue messageQueue = new MessageQueue();
+ when(rocketmqPullConsume.fetchConsumeOffset(any(MessageQueue.class), anyBoolean()))
+ .thenReturn(123L);
+ assertThat(localMessageCache.nextPullOffset(new MessageQueue())).isEqualTo(123L);
+ }
+
+ @Test
+ public void testUpdatePullOffset() throws Exception {
+ MessageQueue messageQueue = new MessageQueue();
+ localMessageCache.updatePullOffset(messageQueue, 124L);
+ assertThat(localMessageCache.nextPullOffset(messageQueue)).isEqualTo(124L);
+ }
+
+ @Test
+ public void testSubmitConsumeRequest() throws Exception {
+ byte [] body = new byte[]{'1', '2', '3'};
+ MessageExt consumedMsg = new MessageExt();
+ consumedMsg.setMsgId("NewMsgId");
+ consumedMsg.setBody(body);
+ consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC");
+ consumedMsg.setTopic("HELLO_QUEUE");
+
+ when(consumeRequest.getMessageExt()).thenReturn(consumedMsg);
+ localMessageCache.submitConsumeRequest(consumeRequest);
+ assertThat(localMessageCache.poll()).isEqualTo(consumedMsg);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PullConsumerImplTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PullConsumerImplTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PullConsumerImplTest.java
new file mode 100644
index 0000000..277a5c6
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PullConsumerImplTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.OMS;
+import io.openmessaging.PropertyKeys;
+import io.openmessaging.PullConsumer;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import java.lang.reflect.Field;
+import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PullConsumerImplTest {
+ private PullConsumer consumer;
+ private String queueName = "HELLO_QUEUE";
+
+ @Mock
+ private DefaultMQPullConsumer rocketmqPullConsumer;
+ private LocalMessageCache localMessageCache =
+ spy(new LocalMessageCache(rocketmqPullConsumer, new ClientConfig()));
+
+ @Before
+ public void init() throws NoSuchFieldException, IllegalAccessException {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+ consumer = messagingAccessPoint.createPullConsumer(queueName,
+ OMS.newKeyValue().put(NonStandardKeys.CONSUMER_GROUP, "TestGroup"));
+
+ Field field = PullConsumerImpl.class.getDeclaredField("rocketmqPullConsumer");
+ field.setAccessible(true);
+ field.set(consumer, rocketmqPullConsumer); //Replace
+
+ field = PullConsumerImpl.class.getDeclaredField("localMessageCache");
+ field.setAccessible(true);
+ field.set(consumer, localMessageCache);
+
+ messagingAccessPoint.startup();
+ consumer.startup();
+ }
+
+ @Test
+ public void testPoll() {
+ final byte[] testBody = new byte[] {'a', 'b'};
+ MessageExt consumedMsg = new MessageExt();
+ consumedMsg.setMsgId("NewMsgId");
+ consumedMsg.setBody(testBody);
+ consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC");
+ consumedMsg.setTopic(queueName);
+
+ when(localMessageCache.poll()).thenReturn(consumedMsg);
+
+ Message message = consumer.poll();
+ assertThat(message.headers().getString(MessageHeader.MESSAGE_ID)).isEqualTo("NewMsgId");
+ assertThat(((BytesMessage) message).getBody()).isEqualTo(testBody);
+ }
+
+ @Test
+ public void testPoll_WithTimeout() {
+ //There is a default timeout value, @see ClientConfig#omsOperationTimeout.
+ Message message = consumer.poll();
+ assertThat(message).isNull();
+
+ message = consumer.poll(OMS.newKeyValue().put(PropertyKeys.OPERATION_TIMEOUT, 100));
+ assertThat(message).isNull();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PushConsumerImplTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PushConsumerImplTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PushConsumerImplTest.java
new file mode 100644
index 0000000..882e57e
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/consumer/PushConsumerImplTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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 io.openmessaging.rocketmq.consumer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.Message;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.MessageListener;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.OMS;
+import io.openmessaging.PushConsumer;
+import io.openmessaging.ReceivedMessageContext;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
+import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PushConsumerImplTest {
+ private PushConsumer consumer;
+
+ @Mock
+ private DefaultMQPushConsumer rocketmqPushConsumer;
+
+ @Before
+ public void init() throws NoSuchFieldException, IllegalAccessException {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+ consumer = messagingAccessPoint.createPushConsumer(
+ OMS.newKeyValue().put(NonStandardKeys.CONSUMER_GROUP, "TestGroup"));
+
+ Field field = PushConsumerImpl.class.getDeclaredField("rocketmqPushConsumer");
+ field.setAccessible(true);
+ DefaultMQPushConsumer innerConsumer = (DefaultMQPushConsumer) field.get(consumer);
+ field.set(consumer, rocketmqPushConsumer); //Replace
+
+ when(rocketmqPushConsumer.getMessageListener()).thenReturn(innerConsumer.getMessageListener());
+ messagingAccessPoint.startup();
+ consumer.startup();
+ }
+
+ @Test
+ public void testConsumeMessage() {
+ final byte[] testBody = new byte[] {'a', 'b'};
+
+ MessageExt consumedMsg = new MessageExt();
+ consumedMsg.setMsgId("NewMsgId");
+ consumedMsg.setBody(testBody);
+ consumedMsg.putUserProperty(NonStandardKeys.MESSAGE_DESTINATION, "TOPIC");
+ consumedMsg.setTopic("HELLO_QUEUE");
+ consumer.attachQueue("HELLO_QUEUE", new MessageListener() {
+ @Override
+ public void onMessage(final Message message, final ReceivedMessageContext context) {
+ assertThat(message.headers().getString(MessageHeader.MESSAGE_ID)).isEqualTo("NewMsgId");
+ assertThat(((BytesMessage) message).getBody()).isEqualTo(testBody);
+ context.ack();
+ }
+ });
+ ((MessageListenerConcurrently) rocketmqPushConsumer
+ .getMessageListener()).consumeMessage(Collections.singletonList(consumedMsg), null);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/ProducerImplTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/ProducerImplTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/ProducerImplTest.java
new file mode 100644
index 0000000..1db80c3
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/ProducerImplTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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 io.openmessaging.rocketmq.producer;
+
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.Producer;
+import io.openmessaging.exception.OMSRuntimeException;
+import java.lang.reflect.Field;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.exception.RemotingException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ProducerImplTest {
+ private Producer producer;
+
+ @Mock
+ private DefaultMQProducer rocketmqProducer;
+
+ @Before
+ public void init() throws NoSuchFieldException, IllegalAccessException {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+ producer = messagingAccessPoint.createProducer();
+
+ Field field = AbstractOMSProducer.class.getDeclaredField("rocketmqProducer");
+ field.setAccessible(true);
+ field.set(producer, rocketmqProducer);
+
+ messagingAccessPoint.startup();
+ producer.startup();
+ }
+
+ @Test
+ public void testSend_OK() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+ SendResult sendResult = new SendResult();
+ sendResult.setMsgId("TestMsgID");
+ sendResult.setSendStatus(SendStatus.SEND_OK);
+ when(rocketmqProducer.send(any(Message.class), anyLong())).thenReturn(sendResult);
+ io.openmessaging.SendResult omsResult =
+ producer.send(producer.createBytesMessageToTopic("HELLO_TOPIC", new byte[] {'a'}));
+
+ assertThat(omsResult.messageId()).isEqualTo("TestMsgID");
+ }
+
+ @Test
+ public void testSend_Not_OK() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+ SendResult sendResult = new SendResult();
+ sendResult.setSendStatus(SendStatus.FLUSH_DISK_TIMEOUT);
+
+ when(rocketmqProducer.send(any(Message.class), anyLong())).thenReturn(sendResult);
+ try {
+ producer.send(producer.createBytesMessageToTopic("HELLO_TOPIC", new byte[] {'a'}));
+ failBecauseExceptionWasNotThrown(OMSRuntimeException.class);
+ } catch (Exception e) {
+ assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed.");
+ }
+ }
+
+ @Test
+ public void testSend_WithException() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+ when(rocketmqProducer.send(any(Message.class), anyLong())).thenThrow(MQClientException.class);
+ try {
+ producer.send(producer.createBytesMessageToTopic("HELLO_TOPIC", new byte[] {'a'}));
+ failBecauseExceptionWasNotThrown(OMSRuntimeException.class);
+ } catch (Exception e) {
+ assertThat(e).hasMessageContaining("Send message to RocketMQ broker failed.");
+ }
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/SequenceProducerImplTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/SequenceProducerImplTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/SequenceProducerImplTest.java
new file mode 100644
index 0000000..823fe01
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/producer/SequenceProducerImplTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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 io.openmessaging.rocketmq.producer;
+
+import io.openmessaging.BytesMessage;
+import io.openmessaging.MessageHeader;
+import io.openmessaging.MessagingAccessPoint;
+import io.openmessaging.MessagingAccessPointFactory;
+import io.openmessaging.SequenceProducer;
+import java.lang.reflect.Field;
+import org.apache.rocketmq.client.exception.MQBrokerException;
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.client.producer.SendStatus;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.exception.RemotingException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SequenceProducerImplTest {
+
+ private SequenceProducer producer;
+
+ @Mock
+ private DefaultMQProducer rocketmqProducer;
+
+ @Before
+ public void init() throws NoSuchFieldException, IllegalAccessException {
+ final MessagingAccessPoint messagingAccessPoint = MessagingAccessPointFactory
+ .getMessagingAccessPoint("openmessaging:rocketmq://IP1:9876,IP2:9876/namespace");
+ producer = messagingAccessPoint.createSequenceProducer();
+
+ Field field = AbstractOMSProducer.class.getDeclaredField("rocketmqProducer");
+ field.setAccessible(true);
+ field.set(producer, rocketmqProducer);
+
+ messagingAccessPoint.startup();
+ producer.startup();
+ }
+
+ @Test
+ public void testSend_WithCommit() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
+ SendResult sendResult = new SendResult();
+ sendResult.setMsgId("TestMsgID");
+ sendResult.setSendStatus(SendStatus.SEND_OK);
+ when(rocketmqProducer.send(ArgumentMatchers.<Message>anyList())).thenReturn(sendResult);
+ when(rocketmqProducer.getMaxMessageSize()).thenReturn(1024);
+ final BytesMessage message = producer.createBytesMessageToTopic("HELLO_TOPIC", new byte[] {'a'});
+ producer.send(message);
+ producer.commit();
+ assertThat(message.headers().getString(MessageHeader.MESSAGE_ID)).isEqualTo("TestMsgID");
+ }
+
+ @Test
+ public void testRollback() {
+ when(rocketmqProducer.getMaxMessageSize()).thenReturn(1024);
+ final BytesMessage message = producer.createBytesMessageToTopic("HELLO_TOPIC", new byte[] {'a'});
+ producer.send(message);
+ producer.rollback();
+ producer.commit(); //Commit nothing.
+ assertThat(message.headers().getString(MessageHeader.MESSAGE_ID)).isEqualTo(null);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/promise/DefaultPromiseTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/promise/DefaultPromiseTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/promise/DefaultPromiseTest.java
new file mode 100644
index 0000000..2240ff2
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/promise/DefaultPromiseTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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 io.openmessaging.rocketmq.promise;
+
+import io.openmessaging.Promise;
+import io.openmessaging.PromiseListener;
+import io.openmessaging.exception.OMSRuntimeException;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Fail.failBecauseExceptionWasNotThrown;
+
+public class DefaultPromiseTest {
+ private Promise<String> promise;
+
+ @Before
+ public void init() {
+ promise = new DefaultPromise<>();
+ }
+
+ @Test
+ public void testIsCancelled() throws Exception {
+ assertThat(promise.isCancelled()).isEqualTo(false);
+ }
+
+ @Test
+ public void testIsDone() throws Exception {
+ assertThat(promise.isDone()).isEqualTo(false);
+ promise.set("Done");
+ assertThat(promise.isDone()).isEqualTo(true);
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ promise.set("Done");
+ assertThat(promise.get()).isEqualTo("Done");
+ }
+
+ @Test
+ public void testGet_WithTimeout() throws Exception {
+ try {
+ promise.get(100);
+ failBecauseExceptionWasNotThrown(OMSRuntimeException.class);
+ } catch (OMSRuntimeException e) {
+ assertThat(e).hasMessageContaining("Get request result is timeout or interrupted");
+ }
+ }
+
+ @Test
+ public void testAddListener() throws Exception {
+ promise.addListener(new PromiseListener<String>() {
+ @Override
+ public void operationCompleted(final Promise<String> promise) {
+ assertThat(promise.get()).isEqualTo("Done");
+ }
+
+ @Override
+ public void operationFailed(final Promise<String> promise) {
+
+ }
+ });
+ promise.set("Done");
+ }
+
+ @Test
+ public void testAddListener_ListenerAfterSet() throws Exception {
+ promise.set("Done");
+ promise.addListener(new PromiseListener<String>() {
+ @Override
+ public void operationCompleted(final Promise<String> promise) {
+ assertThat(promise.get()).isEqualTo("Done");
+ }
+
+ @Override
+ public void operationFailed(final Promise<String> promise) {
+
+ }
+ });
+ }
+
+ @Test
+ public void testAddListener_WithException_ListenerAfterSet() throws Exception {
+ final Throwable exception = new OMSRuntimeException("-1", "Test Error");
+ promise.setFailure(exception);
+ promise.addListener(new PromiseListener<String>() {
+ @Override
+ public void operationCompleted(final Promise<String> promise) {
+ }
+
+ @Override
+ public void operationFailed(final Promise<String> promise) {
+ assertThat(promise.getThrowable()).isEqualTo(exception);
+ }
+ });
+ }
+
+ @Test
+ public void testAddListener_WithException() throws Exception {
+ final Throwable exception = new OMSRuntimeException("-1", "Test Error");
+ promise.addListener(new PromiseListener<String>() {
+ @Override
+ public void operationCompleted(final Promise<String> promise) {
+ }
+
+ @Override
+ public void operationFailed(final Promise<String> promise) {
+ assertThat(promise.getThrowable()).isEqualTo(exception);
+ }
+ });
+ promise.setFailure(exception);
+ }
+
+ @Test
+ public void getThrowable() throws Exception {
+ assertThat(promise.getThrowable()).isNull();
+ Throwable exception = new OMSRuntimeException("-1", "Test Error");
+ promise.setFailure(exception);
+ assertThat(promise.getThrowable()).isEqualTo(exception);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/openmessaging/src/test/java/io/openmessaging/rocketmq/utils/BeanUtilsTest.java
----------------------------------------------------------------------
diff --git a/openmessaging/src/test/java/io/openmessaging/rocketmq/utils/BeanUtilsTest.java b/openmessaging/src/test/java/io/openmessaging/rocketmq/utils/BeanUtilsTest.java
new file mode 100644
index 0000000..71ca11c
--- /dev/null
+++ b/openmessaging/src/test/java/io/openmessaging/rocketmq/utils/BeanUtilsTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 io.openmessaging.rocketmq.utils;
+
+import io.openmessaging.KeyValue;
+import io.openmessaging.OMS;
+import io.openmessaging.rocketmq.config.ClientConfig;
+import io.openmessaging.rocketmq.domain.NonStandardKeys;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BeanUtilsTest {
+ private KeyValue properties = OMS.newKeyValue();
+
+ public static class CustomizedConfig extends ClientConfig {
+ final static String STRING_TEST = "string.test";
+ String stringTest = "foobar";
+
+ final static String DOUBLE_TEST = "double.test";
+ double doubleTest = 123.0;
+
+ final static String LONG_TEST = "long.test";
+ long longTest = 123L;
+
+ String getStringTest() {
+ return stringTest;
+ }
+
+ public void setStringTest(String stringTest) {
+ this.stringTest = stringTest;
+ }
+
+ double getDoubleTest() {
+ return doubleTest;
+ }
+
+ public void setDoubleTest(final double doubleTest) {
+ this.doubleTest = doubleTest;
+ }
+
+ long getLongTest() {
+ return longTest;
+ }
+
+ public void setLongTest(final long longTest) {
+ this.longTest = longTest;
+ }
+
+ CustomizedConfig() {
+ }
+ }
+
+ @Before
+ public void init() {
+ properties.put(NonStandardKeys.MAX_REDELIVERY_TIMES, 120);
+ properties.put(CustomizedConfig.STRING_TEST, "kaka");
+ properties.put(NonStandardKeys.CONSUMER_GROUP, "Default_Consumer_Group");
+ properties.put(NonStandardKeys.MESSAGE_CONSUME_TIMEOUT, 101);
+
+ properties.put(CustomizedConfig.LONG_TEST, 1234567890L);
+ properties.put(CustomizedConfig.DOUBLE_TEST, 10.234);
+ }
+
+ @Test
+ public void testPopulate() {
+ CustomizedConfig config = BeanUtils.populate(properties, CustomizedConfig.class);
+
+ //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class);
+ Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120);
+ Assert.assertEquals(config.getStringTest(), "kaka");
+ Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group");
+ Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101);
+ Assert.assertEquals(config.getLongTest(), 1234567890L);
+ Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001);
+ }
+
+ @Test
+ public void testPopulate_ExistObj() {
+ CustomizedConfig config = new CustomizedConfig();
+ config.setOmsConsumerId("NewConsumerId");
+
+ Assert.assertEquals(config.getOmsConsumerId(), "NewConsumerId");
+
+ config = BeanUtils.populate(properties, config);
+
+ //RemotingConfig config = BeanUtils.populate(properties, RemotingConfig.class);
+ Assert.assertEquals(config.getRmqMaxRedeliveryTimes(), 120);
+ Assert.assertEquals(config.getStringTest(), "kaka");
+ Assert.assertEquals(config.getRmqConsumerGroup(), "Default_Consumer_Group");
+ Assert.assertEquals(config.getRmqMessageConsumeTimeout(), 101);
+ Assert.assertEquals(config.getLongTest(), 1234567890L);
+ Assert.assertEquals(config.getDoubleTest(), 10.234, 0.000001);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/1d966b50/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 05ead63..25e4c84 100644
--- a/pom.xml
+++ b/pom.xml
@@ -181,6 +181,7 @@
<module>filter</module>
<module>test</module>
<module>distribution</module>
+ <module>openmessaging</module>
</modules>
<build>
@@ -617,6 +618,11 @@
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
+ <dependency>
+ <groupId>io.openmessaging</groupId>
+ <artifactId>openmessaging-api</artifactId>
+ <version>0.1.0-alpha</version>
+ </dependency>
</dependencies>
</dependencyManagement>
</project>