2525import org .apache .rocketmq .common .BrokerConfig ;
2626import org .apache .rocketmq .common .KeyBuilder ;
2727import org .apache .rocketmq .common .MixAll ;
28+ import org .apache .rocketmq .common .PopAckConstants ;
2829import org .apache .rocketmq .common .ServiceThread ;
2930import org .apache .rocketmq .common .TopicConfig ;
3031import org .apache .rocketmq .common .TopicFilterType ;
32+ import org .apache .rocketmq .common .attribute .TopicMessageType ;
3133import org .apache .rocketmq .common .constant .ConsumeInitMode ;
3234import org .apache .rocketmq .common .constant .LoggerName ;
3335import org .apache .rocketmq .common .constant .PermName ;
3840import org .apache .rocketmq .common .message .MessageExtBrokerInner ;
3941import org .apache .rocketmq .common .utils .ConcurrentHashMapUtils ;
4042import org .apache .rocketmq .remoting .protocol .header .ExtraInfoUtil ;
43+ import org .apache .rocketmq .remoting .protocol .subscription .SubscriptionGroupConfig ;
4144import org .apache .rocketmq .store .AppendMessageStatus ;
4245import org .apache .rocketmq .store .GetMessageResult ;
4346import org .apache .rocketmq .store .GetMessageStatus ;
@@ -324,6 +327,23 @@ protected CompletableFuture<PopConsumerContext> getMessageAsync(CompletableFutur
324327 });
325328 }
326329
330+ protected CompletableFuture <PopConsumerContext > getMessageFromTopicAsync (CompletableFuture <PopConsumerContext > future ,
331+ String clientHost , String groupId , String topicId , long requestCount , int batchSize , MessageFilter filter ,
332+ PopConsumerRecord .RetryType retryType ) {
333+ TopicConfig topicConfig = this .brokerController .getTopicConfigManager ().selectTopicConfig (topicId );
334+ if (null == topicConfig ) {
335+ return future ;
336+ }
337+ for (int i = 0 ; i < topicConfig .getReadQueueNums (); i ++) {
338+ long index = (brokerController .getBrokerConfig ().isPriorityOrderAsc () ?
339+ topicConfig .getReadQueueNums () - 1 - i : i ) + requestCount ;
340+ int current = (int ) index % topicConfig .getReadQueueNums ();
341+ future = this .getMessageAsync (future , clientHost , groupId ,
342+ topicId , current , batchSize , filter , retryType );
343+ }
344+ return future ;
345+ }
346+
327347 public CompletableFuture <PopConsumerContext > popAsync (String clientHost , long popTime , long invisibleTime ,
328348 String groupId , String topicId , int queueId , int batchSize , boolean fifo , String attemptId , int initMode ,
329349 MessageFilter filter ) {
@@ -336,6 +356,12 @@ public CompletableFuture<PopConsumerContext> popAsync(String clientHost, long po
336356 return CompletableFuture .completedFuture (popConsumerContext );
337357 }
338358
359+ SubscriptionGroupConfig subscriptionGroupConfig =
360+ this .brokerController .getSubscriptionGroupManager ().findSubscriptionGroupConfig (groupId );
361+ if (null == subscriptionGroupConfig || !subscriptionGroupConfig .isConsumeEnable ()) {
362+ return CompletableFuture .completedFuture (popConsumerContext );
363+ }
364+
339365 log .debug ("PopConsumerService popAsync, groupId={}, topicId={}, queueId={}, " +
340366 "batchSize={}, invisibleTime={}, fifo={}, attemptId={}, filter={}" ,
341367 groupId , topicId , queueId , batchSize , invisibleTime , fifo , attemptId , filter );
@@ -345,43 +371,46 @@ public CompletableFuture<PopConsumerContext> popAsync(String clientHost, long po
345371 String retryTopicV2 = KeyBuilder .buildPopRetryTopicV2 (topicId , groupId );
346372 long requestCount = Objects .requireNonNull (ConcurrentHashMapUtils .computeIfAbsent (
347373 requestCountTable , requestKey , k -> new AtomicLong (0L ))).getAndIncrement ();
348- boolean preferRetry = requestCount % 5L == 0L ;
374+ boolean usePriorityMode = TopicMessageType .PRIORITY .equals (topicConfig .getTopicMessageType ())
375+ && !fifo && requestCount % 100L < subscriptionGroupConfig .getPriorityFactor ();
376+ int probability = usePriorityMode ?
377+ brokerConfig .getPopFromRetryProbabilityForPriority () : brokerConfig .getPopFromRetryProbability ();
378+ probability = Math .max (0 , Math .min (100 , probability )); // [51, 100] means always
379+ boolean preferRetry = probability > 0 && requestCount % (100 / probability ) == 0L ;
380+ requestCount = usePriorityMode ? 0 : requestCount ; // use requestCount as randomQ
349381
350382 CompletableFuture <PopConsumerContext > getMessageFuture =
351383 CompletableFuture .completedFuture (popConsumerContext );
352384
353385 try {
354386 if (!fifo && preferRetry ) {
355387 if (brokerConfig .isRetrieveMessageFromPopRetryTopicV1 ()) {
356- getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
357- retryTopicV1 , 0 , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V1 );
388+ getMessageFuture = this .getMessageFromTopicAsync (getMessageFuture , clientHost , groupId ,
389+ retryTopicV1 , requestCount , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V1 );
358390 }
359391
360392 if (brokerConfig .isEnableRetryTopicV2 ()) {
361- getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
362- retryTopicV2 , 0 , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V2 );
393+ getMessageFuture = this .getMessageFromTopicAsync (getMessageFuture , clientHost , groupId ,
394+ retryTopicV2 , requestCount , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V2 );
363395 }
364396 }
365397
366398 if (queueId != -1 ) {
367399 getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
368400 topicId , queueId , batchSize , filter , PopConsumerRecord .RetryType .NORMAL_TOPIC );
369401 } else {
370- for (int i = 0 ; i < topicConfig .getReadQueueNums (); i ++) {
371- int current = (int ) ((requestCount + i ) % topicConfig .getReadQueueNums ());
372- getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
373- topicId , current , batchSize , filter , PopConsumerRecord .RetryType .NORMAL_TOPIC );
374- }
402+ getMessageFuture = this .getMessageFromTopicAsync (getMessageFuture , clientHost , groupId ,
403+ topicId , requestCount , batchSize , filter , PopConsumerRecord .RetryType .NORMAL_TOPIC );
375404
376405 if (!fifo && !preferRetry ) {
377406 if (brokerConfig .isRetrieveMessageFromPopRetryTopicV1 ()) {
378- getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
379- retryTopicV1 , 0 , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V1 );
407+ getMessageFuture = this .getMessageFromTopicAsync (getMessageFuture , clientHost , groupId ,
408+ retryTopicV1 , requestCount , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V1 );
380409 }
381410
382411 if (brokerConfig .isEnableRetryTopicV2 ()) {
383- getMessageFuture = this .getMessageAsync (getMessageFuture , clientHost , groupId ,
384- retryTopicV2 , 0 , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V2 );
412+ getMessageFuture = this .getMessageFromTopicAsync (getMessageFuture , clientHost , groupId ,
413+ retryTopicV2 , requestCount , batchSize , filter , PopConsumerRecord .RetryType .RETRY_TOPIC_V2 );
385414 }
386415 }
387416 }
@@ -568,21 +597,33 @@ public long revive(AtomicLong currentTime, int maxCount) {
568597 return consumerRecords .size ();
569598 }
570599
571- public void createRetryTopicIfNeeded (String groupId , String topicId ) {
572- TopicConfig topicConfig = brokerController .getTopicConfigManager ().selectTopicConfig (topicId );
573- if (topicConfig != null ) {
600+ public void createRetryTopicIfNeeded (String groupId , String retryTopic ) {
601+ TopicConfig topicConfig = brokerController .getTopicConfigManager ().selectTopicConfig (retryTopic );
602+ if (topicConfig != null && ! brokerController . getBrokerConfig (). isUseSeparateRetryQueue () ) {
574603 return ;
575604 }
576605
577- topicConfig = new TopicConfig (topicId , 1 , 1 ,
606+ int retryQueueNum = PopAckConstants .retryQueueNum ;
607+ if (brokerController .getBrokerConfig ().isUseSeparateRetryQueue ()) {
608+ String normalTopic = KeyBuilder .parseNormalTopic (retryTopic , groupId );
609+ TopicConfig normalConfig = brokerController .getTopicConfigManager ().selectTopicConfig (normalTopic ); // always exists
610+ retryQueueNum = normalConfig .getWriteQueueNums ();
611+ if (topicConfig != null && topicConfig .getWriteQueueNums () == normalConfig .getWriteQueueNums ()) {
612+ return ;
613+ }
614+ }
615+
616+ topicConfig = new TopicConfig (retryTopic , retryQueueNum , retryQueueNum ,
578617 PermName .PERM_READ | PermName .PERM_WRITE , 0 );
579618 topicConfig .setTopicFilterType (TopicFilterType .SINGLE_TAG );
580619 brokerController .getTopicConfigManager ().updateTopicConfig (topicConfig );
581620
582- long offset = this .brokerController .getConsumerOffsetManager ().queryOffset (groupId , topicId , 0 );
583- if (offset < 0 ) {
584- this .brokerController .getConsumerOffsetManager ().commitOffset (
585- "InitPopOffset" , groupId , topicId , 0 , 0 );
621+ for (int i = 0 ; i < retryQueueNum ; i ++) {
622+ long offset = this .brokerController .getConsumerOffsetManager ().queryOffset (groupId , retryTopic , i );
623+ if (offset < 0 ) {
624+ this .brokerController .getConsumerOffsetManager ().commitOffset (
625+ "InitPopOffset" , groupId , retryTopic , i , 0 );
626+ }
586627 }
587628 }
588629
@@ -605,7 +646,7 @@ public boolean reviveRetry(PopConsumerRecord record, MessageExt messageExt) {
605646 MessageExtBrokerInner msgInner = new MessageExtBrokerInner ();
606647 msgInner .setTopic (retryTopic );
607648 msgInner .setBody (messageExt .getBody () != null ? messageExt .getBody () : new byte [] {});
608- msgInner .setQueueId (0 );
649+ msgInner .setQueueId (getRetryQueueId ( retryTopic , messageExt ) );
609650 if (messageExt .getTags () != null ) {
610651 msgInner .setTags (messageExt .getTags ());
611652 } else {
@@ -647,6 +688,18 @@ public boolean reviveRetry(PopConsumerRecord record, MessageExt messageExt) {
647688 return true ;
648689 }
649690
691+ private int getRetryQueueId (String retryTopic , MessageExt oriMsg ) {
692+ if (!brokerController .getBrokerConfig ().isUseSeparateRetryQueue ()) {
693+ return 0 ;
694+ }
695+ int oriQueueId = oriMsg .getQueueId (); // original qid of normal or retry topic
696+ if (oriQueueId > brokerController .getTopicConfigManager ().selectTopicConfig (retryTopic ).getWriteQueueNums () - 1 ) {
697+ log .warn ("not expected, {}, {}, {}" , retryTopic , oriQueueId , oriMsg .getMsgId ());
698+ return 0 ; // fallback
699+ }
700+ return oriQueueId ;
701+ }
702+
650703 // Export kv store record to revive topic
651704 @ SuppressWarnings ("ExtractMethodRecommender" )
652705 public synchronized void transferToFsStore () {
0 commit comments