2424import org .apache .commons .lang3 .tuple .Triple ;
2525import org .apache .rocketmq .broker .BrokerController ;
2626import org .apache .rocketmq .broker .offset .ConsumerOffsetManager ;
27+ import org .apache .rocketmq .common .BrokerConfig ;
2728import org .apache .rocketmq .common .ServiceThread ;
2829import org .apache .rocketmq .common .constant .LoggerName ;
2930import org .apache .rocketmq .common .entity .ClientGroup ;
@@ -445,15 +446,36 @@ protected class ClientEventSet {
445446 private final String group ;
446447 private volatile long lastAccessTime = System .currentTimeMillis ();
447448 private volatile long lastConsumeTime = System .currentTimeMillis ();
449+ /**
450+ * Cache resolved max capacity to avoid per-offer SubscriptionGroupConfig lookup + attribute
451+ * parsing on the hot dispatch path. Soft-cap semantics tolerate a short staleness window,
452+ * so refresh lazily by TTL {@link BrokerConfig#getLiteEventCapacityCacheTtlMs()}.
453+ */
454+ private volatile int maxCapacityCache ;
455+ private volatile long capacityRefreshTime = System .currentTimeMillis ();
448456
449457 public ClientEventSet (String group ) {
450458 this .group = group ;
451- events = new LinkedBlockingQueue <>(LiteMetadataUtil .getMaxClientEventCount (group , brokerController ));
459+ // Use a large bounded queue as a hard ceiling; the effective capacity is enforced
460+ // dynamically via soft-cap in offer() so that maxClientEventCount can be changed
461+ // at runtime without restart.
462+ this .events = new LinkedBlockingQueue <>(100_000 );
463+ this .maxCapacityCache = LiteMetadataUtil .getMaxClientEventCount (group , brokerController );
464+ }
465+
466+ private int getMaxCapacity () {
467+ long now = System .currentTimeMillis ();
468+ long ttl = brokerController .getBrokerConfig ().getLiteEventCapacityCacheTtlMs ();
469+ if (now - capacityRefreshTime > ttl ) {
470+ maxCapacityCache = LiteMetadataUtil .getMaxClientEventCount (group , brokerController );
471+ capacityRefreshTime = now ;
472+ }
473+ return maxCapacityCache ;
452474 }
453475
454476 // return false if and only if the queue is full, has race condition with poll(), but no side effect.
455477 public boolean offer (String event ) {
456- if (events .remainingCapacity () == 0 ) {
478+ if (events .size () >= getMaxCapacity () ) {
457479 return false ;
458480 }
459481 boolean rst ;
@@ -486,7 +508,8 @@ public boolean maybeBlock() {
486508
487509 public boolean isLowWaterMark () {
488510 int used = events .size ();
489- return (double ) used / (used + events .remainingCapacity ()) < LOW_WATER_MARK ;
511+ int maxCapacity = getMaxCapacity ();
512+ return maxCapacity <= 0 || (double ) used / maxCapacity < LOW_WATER_MARK ;
490513 }
491514
492515 public boolean isActiveConsuming () {
@@ -516,7 +539,7 @@ public void onUnregister(String clientId, String group, String lmqName) {
516539 }
517540
518541 /**
519- * Mostly triggered when client channel closed, ensure that lite subscriptions is cleared before.
542+ * Mostly triggered when client channel closed, ensure that lite subscriptions is cleared before.
520543 */
521544 @ Override
522545 public void onRemoveAll (String clientId , String group ) {
@@ -553,10 +576,12 @@ public String next() {
553576 static class LiteSubscriptionIterator implements Iterator <String > {
554577 private final Iterator <String > iterator ;
555578 private final String parentTopic ;
579+
556580 public LiteSubscriptionIterator (String parentTopic , Iterator <String > iterator ) {
557581 this .parentTopic = parentTopic ;
558582 this .iterator = iterator ;
559583 }
584+
560585 @ Override
561586 public boolean hasNext () {
562587 return iterator .hasNext ();
@@ -572,6 +597,7 @@ protected static class FullDispatchRequest {
572597 private final String clientId ;
573598 private final String group ;
574599 private final long timestamp ;
600+
575601 public FullDispatchRequest (String clientId , String group , long delayMillis ) {
576602 this .clientId = clientId ;
577603 this .group = group ;
0 commit comments