From bb306318499c725ba252792f29a415c8478adf33 Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Tue, 30 Jan 2018 17:55:04 -0800 Subject: [PATCH 01/10] Introduce ConsumerGroupListener for realizing if a consumer is active in a failover subscription group --- ...bstractDispatcherSingleActiveConsumer.java | 31 +- .../pulsar/broker/service/Consumer.java | 14 + ...sistentDispatcherFailoverConsumerTest.java | 157 +++++- .../service/PersistentFailoverE2ETest.java | 96 +++- .../client/api/ConsumerConfiguration.java | 29 ++ .../client/api/ConsumerGroupListener.java | 36 ++ .../apache/pulsar/client/impl/ClientCnx.java | 14 + .../pulsar/client/impl/ConsumerBase.java | 3 + .../pulsar/client/impl/ConsumerImpl.java | 14 + .../client/impl/PartitionedConsumerImpl.java | 3 + .../apache/pulsar/common/api/Commands.java | 14 + .../pulsar/common/api/PulsarDecoder.java | 12 +- .../pulsar/common/api/proto/PulsarApi.java | 489 ++++++++++++++++++ pulsar-common/src/main/proto/PulsarApi.proto | 11 + .../pulsar/common/api/PulsarDecoderTest.java | 61 +++ 15 files changed, 964 insertions(+), 20 deletions(-) create mode 100644 pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java create mode 100644 pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java index d869fc599ea7c..3ada01adbe691 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java @@ -42,6 +42,7 @@ import org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException; import org.apache.pulsar.broker.service.BrokerServiceException.ServerMetadataException; import org.apache.pulsar.client.impl.Backoff; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.utils.CopyOnWriteArrayList; import org.slf4j.Logger; @@ -81,7 +82,15 @@ public AbstractDispatcherSingleActiveConsumer(SubType subscriptionType, int part protected abstract void cancelPendingRead(); - protected void pickAndScheduleActiveConsumer() { + protected void notifyConsumerGroupChanged(Consumer activeConsumer) { + consumers.forEach(consumer -> + consumer.notifyConsumerGroupChange(activeConsumer.consumerId())); + } + + /** + * @return the previous active consumer if the consumer is changed, otherwise null. + */ + protected boolean pickAndScheduleActiveConsumer() { checkArgument(!consumers.isEmpty()); consumers.sort((c1, c2) -> c1.consumerName().compareTo(c2.consumerName())); @@ -89,12 +98,17 @@ protected void pickAndScheduleActiveConsumer() { int index = partitionIndex % consumers.size(); Consumer prevConsumer = ACTIVE_CONSUMER_UPDATER.getAndSet(this, consumers.get(index)); - if (prevConsumer == ACTIVE_CONSUMER_UPDATER.get(this)) { + Consumer activeConsumer = ACTIVE_CONSUMER_UPDATER.get(this); + if (prevConsumer == activeConsumer) { // Active consumer did not change. Do nothing at this point - return; + return false; + } else { + // If the active consumer is changed, send notification. + notifyConsumerGroupChanged(activeConsumer); } scheduleReadOnActiveConsumer(); + return true; } public synchronized void addConsumer(Consumer consumer) throws BrokerServiceException { @@ -108,8 +122,15 @@ public synchronized void addConsumer(Consumer consumer) throws BrokerServiceExce consumers.add(consumer); - // Pick an active consumer and start it - pickAndScheduleActiveConsumer(); + if (!pickAndScheduleActiveConsumer()) { + // the active consumer is not changed + Consumer currentActiveConsumer = ACTIVE_CONSUMER_UPDATER.get(this); + if (null == currentActiveConsumer) { + log.warn("Current active consumer disappears while adding consumer {}", consumer); + } else { + consumer.notifyConsumerGroupChange(currentActiveConsumer.consumerId()); + } + } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java index 64bd4243c6bce..6e7d7f2268d9f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java @@ -40,6 +40,7 @@ import org.apache.pulsar.common.api.proto.PulsarApi; import org.apache.pulsar.common.api.proto.PulsarApi.CommandAck; import org.apache.pulsar.common.api.proto.PulsarApi.CommandAck.AckType; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.common.api.proto.PulsarApi.MessageIdData; import org.apache.pulsar.common.api.proto.PulsarApi.ProtocolVersion; @@ -145,6 +146,19 @@ public String consumerName() { return consumerName; } + void notifyConsumerGroupChange(long activeConsumerId) { + if (cnx.getRemoteEndpointProtocolVersion() < ProtocolVersion.v11.getNumber()) { + // if the client is older than `v11`, we don't need to send consumer group changes. + return; + } + + if (log.isDebugEnabled()) { + log.debug("notify consumer {} - that [{}] for subscription {} has new active consumer : {}", + consumerId, topicName, subscription.getName(), activeConsumerId); + } + cnx.ctx().write(Commands.newConsumerGroupChange(consumerId, activeConsumerId)); + } + /** * Dispatch a list of entries to the consumer.
* It is also responsible to release entries data and recycle entries object. diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java index f82c17911683e..d5e2f64619bb8 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java @@ -21,24 +21,30 @@ import static org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest.createMockZooKeeper; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; import static org.mockito.Matchers.matches; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.apache.bookkeeper.mledger.AsyncCallbacks.AddEntryCallback; @@ -57,17 +63,18 @@ import org.apache.pulsar.broker.cache.ConfigurationCacheService; import org.apache.pulsar.broker.cache.LocalZooKeeperCacheService; import org.apache.pulsar.broker.namespace.NamespaceService; -import org.apache.pulsar.broker.service.BrokerService; -import org.apache.pulsar.broker.service.Consumer; -import org.apache.pulsar.broker.service.ServerCnx; import org.apache.pulsar.broker.service.persistent.PersistentDispatcherMultipleConsumers; import org.apache.pulsar.broker.service.persistent.PersistentDispatcherSingleActiveConsumer; import org.apache.pulsar.broker.service.persistent.PersistentSubscription; import org.apache.pulsar.broker.service.persistent.PersistentTopic; +import org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; +import org.apache.pulsar.common.api.proto.PulsarApi.ProtocolVersion; import org.apache.pulsar.common.naming.DestinationName; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.policies.data.Policies; +import org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream; import org.apache.pulsar.zookeeper.ZooKeeperDataCache; import org.apache.zookeeper.ZooKeeper; import org.mockito.invocation.InvocationOnMock; @@ -83,9 +90,12 @@ public class PersistentDispatcherFailoverConsumerTest { private BrokerService brokerService; private ManagedLedgerFactory mlFactoryMock; private ServerCnx serverCnx; + private ServerCnx serverCnxWithOldVersion; private ManagedLedger ledgerMock; private ManagedCursor cursorMock; private ConfigurationCacheService configCacheService; + private ChannelHandlerContext channelCtx; + private LinkedBlockingQueue consumerChanges; final String successTopicName = "persistent://part-perf/global/perf.t1/ptopic"; final String failTopicName = "persistent://part-perf/global/perf.t1/pfailTopic"; @@ -115,10 +125,50 @@ public void setup() throws Exception { brokerService = spy(new BrokerService(pulsar)); doReturn(brokerService).when(pulsar).getBrokerService(); + consumerChanges = new LinkedBlockingQueue<>(); + this.channelCtx = mock(ChannelHandlerContext.class); + doAnswer(invocationOnMock -> { + ByteBuf buf = invocationOnMock.getArgumentAt(0, ByteBuf.class); + + ByteBuf cmdBuf = buf.retainedSlice(4, buf.writerIndex() - 4); + try { + int cmdSize = (int) cmdBuf.readUnsignedInt(); + int writerIndex = cmdBuf.writerIndex(); + cmdBuf.writerIndex(cmdBuf.readerIndex() + cmdSize); + ByteBufCodedInputStream cmdInputStream = ByteBufCodedInputStream.get(cmdBuf); + + BaseCommand.Builder cmdBuilder = BaseCommand.newBuilder(); + BaseCommand cmd = cmdBuilder.mergeFrom(cmdInputStream, null).build(); + cmdBuilder.recycle(); + cmdBuf.writerIndex(writerIndex); + cmdInputStream.recycle(); + + if (cmd.hasConsumerGroupChange()) { + consumerChanges.put(cmd.getConsumerGroupChange()); + } + cmd.recycle(); + } finally { + cmdBuf.release(); + } + + return null; + }).when(channelCtx).write(any()); + serverCnx = spy(new ServerCnx(brokerService)); doReturn(true).when(serverCnx).isActive(); doReturn(true).when(serverCnx).isWritable(); doReturn(new InetSocketAddress("localhost", 1234)).when(serverCnx).clientAddress(); + when(serverCnx.getRemoteEndpointProtocolVersion()).thenReturn(ProtocolVersion.v11.getNumber()); + when(serverCnx.ctx()).thenReturn(channelCtx); + + serverCnxWithOldVersion = spy(new ServerCnx(brokerService)); + doReturn(true).when(serverCnxWithOldVersion).isActive(); + doReturn(true).when(serverCnxWithOldVersion).isWritable(); + doReturn(new InetSocketAddress("localhost", 1234)) + .when(serverCnxWithOldVersion).clientAddress(); + when(serverCnxWithOldVersion.getRemoteEndpointProtocolVersion()) + .thenReturn(ProtocolVersion.v10.getNumber()); + when(serverCnxWithOldVersion.ctx()).thenReturn(channelCtx); NamespaceService nsSvc = mock(NamespaceService.class); doReturn(nsSvc).when(pulsar).getNamespaceService(); @@ -193,6 +243,51 @@ public Object answer(InvocationOnMock invocationOnMock) throws Throwable { }).when(ledgerMock).asyncDeleteCursor(matches(".*success.*"), any(DeleteCursorCallback.class), anyObject()); } + private void verifyConsumerGroupChange(CommandConsumerGroupChange change, + long consumerId, + long activeConsumerId) { + assertEquals(consumerId, change.getConsumerId()); + assertEquals(activeConsumerId, change.getActiveConsumerId()); + change.recycle(); + } + + @Test + public void testConsumerGroupChangesWithOldNewConsumers() throws Exception { + PersistentTopic topic = new PersistentTopic(successTopicName, ledgerMock, brokerService); + PersistentSubscription sub = new PersistentSubscription(topic, "sub-1", cursorMock); + + int partitionIndex = 0; + PersistentDispatcherSingleActiveConsumer pdfc = new PersistentDispatcherSingleActiveConsumer(cursorMock, + SubType.Failover, partitionIndex, topic); + + // 1. Verify no consumers connected + assertFalse(pdfc.isConsumerConnected()); + + // 2. Add old consumer + Consumer consumer1 = new Consumer(sub, SubType.Exclusive, topic.getName(), 1 /* consumer id */, 0, + "Cons1"/* consumer name */, 50000, serverCnxWithOldVersion, "myrole-1", Collections.emptyMap()); + pdfc.addConsumer(consumer1); + List consumers = pdfc.getConsumers(); + assertTrue(consumers.get(0).consumerName() == consumer1.consumerName()); + assertEquals(1, consumers.size()); + assertNull(consumerChanges.poll()); + + verify(channelCtx, times(0)).write(any()); + + // 3. Add new consumer + Consumer consumer2 = new Consumer(sub, SubType.Exclusive, topic.getName(), 2 /* consumer id */, 0, + "Cons2"/* consumer name */, 50000, serverCnx, "myrole-1", Collections.emptyMap()); + pdfc.addConsumer(consumer2); + consumers = pdfc.getConsumers(); + assertTrue(consumers.get(0).consumerName() == consumer1.consumerName()); + assertEquals(2, consumers.size()); + + CommandConsumerGroupChange change = consumerChanges.take(); + verifyConsumerGroupChange(change, 2, 1); + + verify(channelCtx, times(1)).write(any()); + } + @Test public void testAddRemoveConsumer() throws Exception { log.info("--- Starting PersistentDispatcherFailoverConsumerTest::testAddConsumer ---"); @@ -208,12 +303,15 @@ public void testAddRemoveConsumer() throws Exception { assertFalse(pdfc.isConsumerConnected()); // 2. Add consumer - Consumer consumer1 = new Consumer(sub, SubType.Exclusive, topic.getName(), 1 /* consumer id */, 0, - "Cons1"/* consumer name */, 50000, serverCnx, "myrole-1", Collections.emptyMap()); + Consumer consumer1 = spy(new Consumer(sub, SubType.Exclusive, topic.getName(), 1 /* consumer id */, 0, + "Cons1"/* consumer name */, 50000, serverCnx, "myrole-1", Collections.emptyMap())); pdfc.addConsumer(consumer1); List consumers = pdfc.getConsumers(); assertTrue(consumers.get(0).consumerName() == consumer1.consumerName()); assertEquals(1, consumers.size()); + CommandConsumerGroupChange change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 1); + verify(consumer1, times(1)).notifyConsumerGroupChange(eq(1L)); // 3. Add again, duplicate allowed pdfc.addConsumer(consumer1); @@ -223,30 +321,56 @@ public void testAddRemoveConsumer() throws Exception { // 4. Verify active consumer assertTrue(pdfc.getActiveConsumer().consumerName() == consumer1.consumerName()); + // get the notified with who is the leader + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 1); + verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); // 5. Add another consumer which does not change active consumer - Consumer consumer2 = new Consumer(sub, SubType.Exclusive, topic.getName(), 2 /* consumer id */, 0, "Cons2"/* consumer name */, - 50000, serverCnx, "myrole-1", Collections.emptyMap()); + Consumer consumer2 = spy(new Consumer(sub, SubType.Exclusive, topic.getName(), 2 /* consumer id */, 0, "Cons2"/* consumer name */, + 50000, serverCnx, "myrole-1", Collections.emptyMap())); pdfc.addConsumer(consumer2); consumers = pdfc.getConsumers(); assertTrue(pdfc.getActiveConsumer().consumerName() == consumer1.consumerName()); assertEquals(3, consumers.size()); + // get notified with who is the leader + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 2, 1); + verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); + verify(consumer2, times(1)).notifyConsumerGroupChange(eq(1L)); // 6. Add a consumer which changes active consumer - Consumer consumer0 = new Consumer(sub, SubType.Exclusive, topic.getName(), 0 /* consumer id */, 0, - "Cons0"/* consumer name */, 50000, serverCnx, "myrole-1", Collections.emptyMap()); + Consumer consumer0 = spy(new Consumer(sub, SubType.Exclusive, topic.getName(), 0 /* consumer id */, 0, + "Cons0"/* consumer name */, 50000, serverCnx, "myrole-1", Collections.emptyMap())); pdfc.addConsumer(consumer0); consumers = pdfc.getConsumers(); assertTrue(pdfc.getActiveConsumer().consumerName() == consumer0.consumerName()); assertEquals(4, consumers.size()); + // all consumers will receive notifications + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 0, 0); + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 0); + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 0); + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 2, 0); + verify(consumer0, times(1)).notifyConsumerGroupChange(eq(0L)); + verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); + verify(consumer1, times(2)).notifyConsumerGroupChange(eq(0L)); + verify(consumer2, times(1)).notifyConsumerGroupChange(eq(1L)); + verify(consumer2, times(1)).notifyConsumerGroupChange(eq(0L)); + // 7. Remove last consumer pdfc.removeConsumer(consumer2); consumers = pdfc.getConsumers(); assertTrue(pdfc.getActiveConsumer().consumerName() == consumer0.consumerName()); assertEquals(3, consumers.size()); + // not consumer group changes + assertNull(consumerChanges.poll()); - // 8. Verify if we can unsubscribe when more than one consumer is connected + // 8. Verify if we cannot unsubscribe when more than one consumer is connected assertFalse(pdfc.canUnsubscribe(consumer0)); // 9. Remove active consumer @@ -255,6 +379,12 @@ public void testAddRemoveConsumer() throws Exception { assertTrue(pdfc.getActiveConsumer().consumerName() == consumer1.consumerName()); assertEquals(2, consumers.size()); + // the remaining consumers will receive notifications + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 1); + change = consumerChanges.take(); + verifyConsumerGroupChange(change, 1, 1); + // 10. Attempt to remove already removed consumer String cause = ""; try { @@ -269,10 +399,11 @@ public void testAddRemoveConsumer() throws Exception { consumers = pdfc.getConsumers(); assertTrue(pdfc.getActiveConsumer().consumerName() == consumer1.consumerName()); assertEquals(1, consumers.size()); + // not consumer group changes + assertNull(consumerChanges.poll()); // 11. With only one consumer, unsubscribe is allowed assertTrue(pdfc.canUnsubscribe(consumer1)); - } @Test diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java index 3385c7ad4c69c..aaac7f2d15823 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java @@ -24,10 +24,12 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; +import com.google.common.collect.Sets; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.apache.pulsar.broker.service.persistent.PersistentDispatcherSingleActiveConsumer; @@ -35,6 +37,7 @@ import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; +import org.apache.pulsar.client.api.ConsumerGroupListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.Producer; @@ -42,6 +45,7 @@ import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.SubscriptionType; import org.apache.pulsar.client.api.ProducerConfiguration.MessageRoutingMode; +import org.apache.pulsar.client.impl.MessageIdImpl; import org.apache.pulsar.client.util.FutureUtil; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.common.naming.DestinationName; @@ -68,22 +72,84 @@ protected void cleanup() throws Exception { private static final int CONSUMER_ADD_OR_REMOVE_WAIT_TIME = 2000; + private static class TestConsumerGroupStateListener implements ConsumerGroupListener { + + final LinkedBlockingQueue activeQueue = new LinkedBlockingQueue<>(); + final LinkedBlockingQueue inActiveQueue = new LinkedBlockingQueue<>(); + + @Override + public void becomeActive(Consumer consumer, int partitionId) { + try { + activeQueue.put(partitionId); + } catch (InterruptedException e) { + } + } + + @Override + public void becomeInactive(Consumer consumer, int partitionId) { + try { + inActiveQueue.put(partitionId); + } catch (InterruptedException e) { + } + } + } + + private void verifyConsumerNotReceiveAnyStateChanges(TestConsumerGroupStateListener listener) throws Exception { + assertNull(listener.activeQueue.poll()); + assertNull(listener.inActiveQueue.poll()); + } + + private void verifyConsumerActive(TestConsumerGroupStateListener listener, int partitionId) throws Exception { + assertEquals(partitionId, listener.activeQueue.take().intValue()); + assertNull(listener.inActiveQueue.poll()); + } + + private void verifyConsumerInactive(TestConsumerGroupStateListener listener, int partitionId) throws Exception { + assertEquals(partitionId, listener.inActiveQueue.take().intValue()); + assertNull(listener.activeQueue.poll()); + } + + private static class ActiveInactiveListener implements ConsumerGroupListener { + + private final Set activePtns = Sets.newHashSet(); + private final Set inactivePtns = Sets.newHashSet(); + + @Override + public synchronized void becomeActive(Consumer consumer, int partitionId) { + activePtns.add(partitionId); + inactivePtns.remove(partitionId); + } + + @Override + public synchronized void becomeInactive(Consumer consumer, int partitionId) { + activePtns.remove(partitionId); + inactivePtns.add(partitionId); + } + } + @Test public void testSimpleConsumerEventsWithoutPartition() throws Exception { final String topicName = "persistent://prop/use/ns-abc/failover-topic1"; final String subName = "sub1"; final int numMsgs = 100; + TestConsumerGroupStateListener listener1 = new TestConsumerGroupStateListener(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); + consumerConf1.setConsumerGroupListener(listener1); + + TestConsumerGroupStateListener listener2 = new TestConsumerGroupStateListener(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); + consumerConf2.setConsumerGroupListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); Consumer consumer2 = pulsarClient.subscribe(topicName, subName, consumerConf2); + verifyConsumerActive(listener1, -1); + verifyConsumerInactive(listener2, -1); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName); PersistentSubscription subRef = topicRef.getSubscription(subName); @@ -147,6 +213,9 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { } consumer1.close(); Thread.sleep(CONSUMER_ADD_OR_REMOVE_WAIT_TIME); + + verifyConsumerActive(listener2, -1); + verifyConsumerNotReceiveAnyStateChanges(listener1); for (int i = 5; i < numMsgs; i++) { msg = consumer2.receive(1, TimeUnit.SECONDS); Assert.assertNotNull(msg); @@ -195,9 +264,11 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { futures.clear(); // 7. consumer subscription should not send messages to the new consumer if its name is not highest in the list + TestConsumerGroupStateListener listener3 = new TestConsumerGroupStateListener(); ConsumerConfiguration consumerConf3 = new ConsumerConfiguration(); consumerConf3.setSubscriptionType(SubscriptionType.Failover); consumerConf3.setConsumerName("3"); + consumerConf3.setConsumerGroupListener(listener3); for (int i = 0; i < 5; i++) { msg = consumer1.receive(1, TimeUnit.SECONDS); Assert.assertNotNull(msg); @@ -206,6 +277,9 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { } Consumer consumer3 = pulsarClient.subscribe(topicName, subName, consumerConf3); Thread.sleep(CONSUMER_ADD_OR_REMOVE_WAIT_TIME); + + verifyConsumerInactive(listener3, -1); + Assert.assertNull(consumer3.receive(1, TimeUnit.SECONDS)); for (int i = 5; i < numMsgs; i++) { msg = consumer1.receive(1, TimeUnit.SECONDS); @@ -247,7 +321,7 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { admin.persistentTopics().delete(topicName); } - @Test(enabled = false) + @Test public void testSimpleConsumerEventsWithPartition() throws Exception { int numPartitions = 4; @@ -261,12 +335,18 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { ProducerConfiguration producerConf = new ProducerConfiguration(); producerConf.setMessageRoutingMode(MessageRoutingMode.RoundRobinPartition); + + ActiveInactiveListener listener1 = new ActiveInactiveListener(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); + consumerConf1.setConsumerGroupListener(listener1); + + ActiveInactiveListener listener2 = new ActiveInactiveListener(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); + consumerConf2.setConsumerGroupListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); @@ -298,6 +378,7 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { // equal distribution between both consumers int totalMessages = 0; Message msg = null; + Set receivedPtns = Sets.newHashSet(); while (true) { msg = consumer1.receive(1, TimeUnit.SECONDS); if (msg == null) { @@ -305,8 +386,16 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { } totalMessages++; consumer1.acknowledge(msg); + MessageIdImpl msgId = (MessageIdImpl) msg.getMessageId(); + receivedPtns.add(msgId.getPartitionIndex()); } + + assertTrue(Sets.difference(listener1.activePtns, receivedPtns).isEmpty()); + assertTrue(Sets.difference(listener2.inactivePtns, receivedPtns).isEmpty()); + Assert.assertEquals(totalMessages, numMsgs / 2); + + receivedPtns = Sets.newHashSet(); while (true) { msg = consumer2.receive(1, TimeUnit.SECONDS); if (msg == null) { @@ -314,7 +403,12 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { } totalMessages++; consumer2.acknowledge(msg); + MessageIdImpl msgId = (MessageIdImpl) msg.getMessageId(); + receivedPtns.add(msgId.getPartitionIndex()); } + assertTrue(Sets.difference(listener1.inactivePtns, receivedPtns).isEmpty()); + assertTrue(Sets.difference(listener2.activePtns, receivedPtns).isEmpty()); + Assert.assertEquals(totalMessages, numMsgs); Assert.assertEquals(disp0.getActiveConsumer().consumerName(), consumerConf1.getConsumerName()); Assert.assertEquals(disp1.getActiveConsumer().consumerName(), consumerConf2.getConsumerName()); diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java index 6d87cfcd4f12e..95defeb082168 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java @@ -46,6 +46,8 @@ public class ConsumerConfiguration implements Serializable { private MessageListener messageListener; + private ConsumerGroupListener consumerGroupListener; + private int receiverQueueSize = 1000; private String consumerName = null; @@ -127,6 +129,33 @@ public ConsumerConfiguration setMessageListener(MessageListener messageListener) return this; } + /** + * @return this configured {@link ConsumerGroupListener} for the consumer. + * @see #setConsumerGroupListener(ConsumerGroupListener) + * @since 1.22.0 + */ + public ConsumerGroupListener getConsumerGroupListener() { + return this.consumerGroupListener; + } + + /** + * Sets a {@link ConsumerGroupListener} for the consumer. + * + *

The consumer group listener is used for receiving consumer state change in a consumer group for failover + * subscription. Application can then react to the consumer state changes. + * + *

This change is experimental. It is subject to changes coming in release 2.0. + * + * @param listener the consumer group listener object + * @return consumer configuration + * @since 1.22.0 + */ + public ConsumerConfiguration setConsumerGroupListener(ConsumerGroupListener listener) { + checkNotNull(listener); + this.consumerGroupListener = listener; + return this; + } + /** * @return the configure receiver queue size value */ diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java new file mode 100644 index 0000000000000..82eee5b5d2ae9 --- /dev/null +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.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.pulsar.client.api; + +/** + * Listener on the consumer state changes. + */ +public interface ConsumerGroupListener { + + /** + * Notified when the consumer group is changed, and the consumer becomes the active consumer. + */ + void becomeActive(Consumer consumer, int partitionId); + + /** + * Notified when the consumer group is changed, and the consumer is still inactive or becomes inactive. + */ + void becomeInactive(Consumer consumer, int partitionId); + +} diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java index 85e286745ae8f..88483fde1ca61 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java @@ -40,6 +40,7 @@ import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseConsumer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; import org.apache.pulsar.common.api.proto.PulsarApi.CommandLookupTopicResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandMessage; @@ -225,6 +226,19 @@ protected void handleMessage(CommandMessage cmdMessage, ByteBuf headersAndPayloa } } + @Override + protected void handleConsumerGroupChange(CommandConsumerGroupChange change) { + checkArgument(state == State.Ready); + + if (log.isDebugEnabled()) { + log.debug("{} Received a consumer group change message from the server : {}", ctx.channel(), change); + } + ConsumerImpl consumer = consumers.get(change.getConsumerId()); + if (consumer != null) { + consumer.consumerGroupChanged(change.getActiveConsumerId()); + } + } + @Override protected void handleSuccess(CommandSuccess success) { checkArgument(state == State.Ready); diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java index 6ef58b26eeca3..7a0924271e647 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java @@ -30,6 +30,7 @@ import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; +import org.apache.pulsar.client.api.ConsumerGroupListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.MessageListener; @@ -54,6 +55,7 @@ enum ConsumerType { protected final String consumerName; protected final CompletableFuture subscribeFuture; protected final MessageListener listener; + protected final ConsumerGroupListener consumerGroupListener; protected final ExecutorService listenerExecutor; final BlockingQueue incomingMessages; protected final ConcurrentLinkedQueue> pendingReceives; @@ -68,6 +70,7 @@ protected ConsumerBase(PulsarClientImpl client, String topic, String subscriptio this.consumerName = conf.getConsumerName() == null ? ConsumerName.generateRandomName() : conf.getConsumerName(); this.subscribeFuture = subscribeFuture; this.listener = conf.getMessageListener(); + this.consumerGroupListener = conf.getConsumerGroupListener(); if (receiverQueueSize <= 1) { this.incomingMessages = Queues.newArrayBlockingQueue(1); } else { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java index 845ad4467c6b2..27a6e0ba108d7 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java @@ -735,6 +735,20 @@ private void failPendingReceive() { } } + void consumerGroupChanged(long activeConsumerId) { + if (consumerGroupListener == null) { + return; + } + + listenerExecutor.submit(() -> { + if (consumerId == activeConsumerId) { + consumerGroupListener.becomeActive(this, partitionIndex); + } else { + consumerGroupListener.becomeInactive(this, partitionIndex); + } + }); + } + void messageReceived(MessageIdData messageId, ByteBuf headersAndPayload, ClientCnx cnx) { if (log.isDebugEnabled()) { log.debug("[{}][{}] Received message: {}/{}", topic, subscription, messageId.getLedgerId(), diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java index 2d7830e2abbae..44037e1e01975 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java @@ -438,6 +438,9 @@ private ConsumerConfiguration getInternalConsumerConfig() { internalConsumerConfig.setReceiverQueueSize(conf.getReceiverQueueSize()); internalConsumerConfig.setSubscriptionType(conf.getSubscriptionType()); internalConsumerConfig.setConsumerName(consumerName); + if (null != conf.getConsumerGroupListener()) { + internalConsumerConfig.setConsumerGroupListener(conf.getConsumerGroupListener()); + } if (conf.getCryptoKeyReader() != null) { internalConsumerConfig.setCryptoKeyReader(conf.getCryptoKeyReader()); internalConsumerConfig.setCryptoFailureAction(conf.getCryptoFailureAction()); diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java index e7b670a63bb3b..055e46b029a89 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java @@ -37,6 +37,7 @@ import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnect; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; import org.apache.pulsar.common.api.proto.PulsarApi.CommandFlow; @@ -350,6 +351,19 @@ public static ByteBuf newUnsubscribe(long consumerId, long requestId) { return res; } + public static ByteBuf newConsumerGroupChange(long consumerId, long activeConsumerId) { + CommandConsumerGroupChange.Builder changeBuilder = CommandConsumerGroupChange.newBuilder() + .setConsumerId(consumerId) + .setActiveConsumerId(activeConsumerId); + + CommandConsumerGroupChange change = changeBuilder.build(); + ByteBuf res = serializeWithSize( + BaseCommand.newBuilder().setType(Type.CONSUMER_GROUP_CHANGE).setConsumerGroupChange(change)); + changeBuilder.recycle(); + change.recycle(); + return res; + } + public static ByteBuf newSeek(long consumerId, long requestId, long ledgerId, long entryId) { CommandSeek.Builder seekBuilder = CommandSeek.newBuilder(); seekBuilder.setConsumerId(consumerId); diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java index e9e113a571e9c..b892ea9454418 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java @@ -26,6 +26,7 @@ import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnect; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStats; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; @@ -51,7 +52,6 @@ import org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -253,6 +253,12 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception handleReachedEndOfTopic(cmd.getReachedEndOfTopic()); cmd.getReachedEndOfTopic().recycle(); break; + + case CONSUMER_GROUP_CHANGE: + handleConsumerGroupChange(cmd.getConsumerGroupChange()); + cmd.getConsumerGroupChange().recycle(); + break; + } } finally { if (cmdBuilder != null) { @@ -337,6 +343,10 @@ protected void handleSeek(CommandSeek seek) { throw new UnsupportedOperationException(); } + protected void handleConsumerGroupChange(CommandConsumerGroupChange change) { + throw new UnsupportedOperationException(); + } + protected void handleSuccess(CommandSuccess success) { throw new UnsupportedOperationException(); } diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java index 6e344cbcda457..129475c77f5ba 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java @@ -192,6 +192,7 @@ public enum ProtocolVersion v8(8, 8), v9(9, 9), v10(10, 10), + v11(11, 11), ; public static final int v0_VALUE = 0; @@ -205,6 +206,7 @@ public enum ProtocolVersion public static final int v8_VALUE = 8; public static final int v9_VALUE = 9; public static final int v10_VALUE = 10; + public static final int v11_VALUE = 11; public final int getNumber() { return value; } @@ -222,6 +224,7 @@ public static ProtocolVersion valueOf(int value) { case 8: return v8; case 9: return v9; case 10: return v10; + case 11: return v11; default: return null; } } @@ -12803,6 +12806,393 @@ public Builder removeProperties(int index) { // @@protoc_insertion_point(class_scope:pulsar.proto.CommandAck) } + public interface CommandConsumerGroupChangeOrBuilder + extends com.google.protobuf.MessageLiteOrBuilder { + + // required uint64 consumer_id = 1; + boolean hasConsumerId(); + long getConsumerId(); + + // optional uint64 active_consumer_id = 2; + boolean hasActiveConsumerId(); + long getActiveConsumerId(); + } + public static final class CommandConsumerGroupChange extends + com.google.protobuf.GeneratedMessageLite + implements CommandConsumerGroupChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStream.ByteBufGeneratedMessage { + // Use CommandConsumerGroupChange.newBuilder() to construct. + private final io.netty.util.Recycler.Handle handle; + private CommandConsumerGroupChange(io.netty.util.Recycler.Handle handle) { + this.handle = handle; + } + + private static final io.netty.util.Recycler RECYCLER = new io.netty.util.Recycler() { + protected CommandConsumerGroupChange newObject(Handle handle) { + return new CommandConsumerGroupChange(handle); + } + }; + + public void recycle() { + this.initFields(); + this.memoizedIsInitialized = -1; + this.bitField0_ = 0; + this.memoizedSerializedSize = -1; + handle.recycle(this); + } + + private CommandConsumerGroupChange(boolean noInit) { + this.handle = null; + } + + private static final CommandConsumerGroupChange defaultInstance; + public static CommandConsumerGroupChange getDefaultInstance() { + return defaultInstance; + } + + public CommandConsumerGroupChange getDefaultInstanceForType() { + return defaultInstance; + } + + private int bitField0_; + // required uint64 consumer_id = 1; + public static final int CONSUMER_ID_FIELD_NUMBER = 1; + private long consumerId_; + public boolean hasConsumerId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public long getConsumerId() { + return consumerId_; + } + + // optional uint64 active_consumer_id = 2; + public static final int ACTIVE_CONSUMER_ID_FIELD_NUMBER = 2; + private long activeConsumerId_; + public boolean hasActiveConsumerId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public long getActiveConsumerId() { + return activeConsumerId_; + } + + private void initFields() { + consumerId_ = 0L; + activeConsumerId_ = 0L; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasConsumerId()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + throw new RuntimeException("Cannot use CodedOutputStream"); + } + + public void writeTo(org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeUInt64(1, consumerId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeUInt64(2, activeConsumerId_); + } + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(1, consumerId_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt64Size(2, activeConsumerId_); + } + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + throw new RuntimeException("Disabled"); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + throw new RuntimeException("Disabled"); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange, Builder> + implements org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream.ByteBufMessageBuilder { + // Construct using org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder() + private final io.netty.util.Recycler.Handle handle; + private Builder(io.netty.util.Recycler.Handle handle) { + this.handle = handle; + maybeForceBuilderInitialization(); + } + private final static io.netty.util.Recycler RECYCLER = new io.netty.util.Recycler() { + protected Builder newObject(io.netty.util.Recycler.Handle handle) { + return new Builder(handle); + } + }; + + public void recycle() { + clear(); + handle.recycle(this); + } + + private void maybeForceBuilderInitialization() { + } + private static Builder create() { + return RECYCLER.get(); + } + + public Builder clear() { + super.clear(); + consumerId_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + activeConsumerId_ = 0L; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getDefaultInstanceForType() { + return org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + } + + public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange build() { + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange buildPartial() { + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.RECYCLER.get(); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.consumerId_ = consumerId_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.activeConsumerId_ = activeConsumerId_; + result.bitField0_ = to_bitField0_; + return result; + } + + public Builder mergeFrom(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange other) { + if (other == org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance()) return this; + if (other.hasConsumerId()) { + setConsumerId(other.getConsumerId()); + } + if (other.hasActiveConsumerId()) { + setActiveConsumerId(other.getActiveConsumerId()); + } + return this; + } + + public final boolean isInitialized() { + if (!hasConsumerId()) { + + return false; + } + return true; + } + + public Builder mergeFrom(com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + throw new java.io.IOException("Merge from CodedInputStream is disabled"); + } + public Builder mergeFrom( + org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + + return this; + default: { + if (!input.skipField(tag)) { + + return this; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + consumerId_ = input.readUInt64(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + activeConsumerId_ = input.readUInt64(); + break; + } + } + } + } + + private int bitField0_; + + // required uint64 consumer_id = 1; + private long consumerId_ ; + public boolean hasConsumerId() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public long getConsumerId() { + return consumerId_; + } + public Builder setConsumerId(long value) { + bitField0_ |= 0x00000001; + consumerId_ = value; + + return this; + } + public Builder clearConsumerId() { + bitField0_ = (bitField0_ & ~0x00000001); + consumerId_ = 0L; + + return this; + } + + // optional uint64 active_consumer_id = 2; + private long activeConsumerId_ ; + public boolean hasActiveConsumerId() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public long getActiveConsumerId() { + return activeConsumerId_; + } + public Builder setActiveConsumerId(long value) { + bitField0_ |= 0x00000002; + activeConsumerId_ = value; + + return this; + } + public Builder clearActiveConsumerId() { + bitField0_ = (bitField0_ & ~0x00000002); + activeConsumerId_ = 0L; + + return this; + } + + // @@protoc_insertion_point(builder_scope:pulsar.proto.CommandConsumerGroupChange) + } + + static { + defaultInstance = new CommandConsumerGroupChange(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:pulsar.proto.CommandConsumerGroupChange) + } + public interface CommandFlowOrBuilder extends com.google.protobuf.MessageLiteOrBuilder { @@ -19363,6 +19753,10 @@ public interface BaseCommandOrBuilder // optional .pulsar.proto.CommandSeek seek = 28; boolean hasSeek(); org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek getSeek(); + + // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; + boolean hasConsumerGroupChange(); + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange(); } public static final class BaseCommand extends com.google.protobuf.GeneratedMessageLite @@ -19429,6 +19823,7 @@ public enum Type CONSUMER_STATS_RESPONSE(24, 26), REACHED_END_OF_TOPIC(25, 27), SEEK(26, 28), + CONSUMER_GROUP_CHANGE(27, 29), ; public static final int CONNECT_VALUE = 2; @@ -19458,6 +19853,7 @@ public enum Type public static final int CONSUMER_STATS_RESPONSE_VALUE = 26; public static final int REACHED_END_OF_TOPIC_VALUE = 27; public static final int SEEK_VALUE = 28; + public static final int CONSUMER_GROUP_CHANGE_VALUE = 29; public final int getNumber() { return value; } @@ -19491,6 +19887,7 @@ public static Type valueOf(int value) { case 26: return CONSUMER_STATS_RESPONSE; case 27: return REACHED_END_OF_TOPIC; case 28: return SEEK; + case 29: return CONSUMER_GROUP_CHANGE; default: return null; } } @@ -19797,6 +20194,16 @@ public org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek getSeek() { return seek_; } + // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; + public static final int CONSUMER_GROUP_CHANGE_FIELD_NUMBER = 29; + private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange consumerGroupChange_; + public boolean hasConsumerGroupChange() { + return ((bitField0_ & 0x10000000) == 0x10000000); + } + public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange() { + return consumerGroupChange_; + } + private void initFields() { type_ = org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand.Type.CONNECT; connect_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConnect.getDefaultInstance(); @@ -19826,6 +20233,7 @@ private void initFields() { consumerStatsResponse_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse.getDefaultInstance(); reachedEndOfTopic_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandReachedEndOfTopic.getDefaultInstance(); seek_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek.getDefaultInstance(); + consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -19986,6 +20394,12 @@ public final boolean isInitialized() { return false; } } + if (hasConsumerGroupChange()) { + if (!getConsumerGroupChange().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } memoizedIsInitialized = 1; return true; } @@ -20082,6 +20496,9 @@ public void writeTo(org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStr if (((bitField0_ & 0x08000000) == 0x08000000)) { output.writeMessage(28, seek_); } + if (((bitField0_ & 0x10000000) == 0x10000000)) { + output.writeMessage(29, consumerGroupChange_); + } } private int memoizedSerializedSize = -1; @@ -20202,6 +20619,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeMessageSize(28, seek_); } + if (((bitField0_ & 0x10000000) == 0x10000000)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(29, consumerGroupChange_); + } memoizedSerializedSize = size; return size; } @@ -20371,6 +20792,8 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x04000000); seek_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x08000000); + consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + bitField0_ = (bitField0_ & ~0x10000000); return this; } @@ -20516,6 +20939,10 @@ public org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand buildPartial() { to_bitField0_ |= 0x08000000; } result.seek_ = seek_; + if (((from_bitField0_ & 0x10000000) == 0x10000000)) { + to_bitField0_ |= 0x10000000; + } + result.consumerGroupChange_ = consumerGroupChange_; result.bitField0_ = to_bitField0_; return result; } @@ -20606,6 +21033,9 @@ public Builder mergeFrom(org.apache.pulsar.common.api.proto.PulsarApi.BaseComman if (other.hasSeek()) { mergeSeek(other.getSeek()); } + if (other.hasConsumerGroupChange()) { + mergeConsumerGroupChange(other.getConsumerGroupChange()); + } return this; } @@ -20764,6 +21194,12 @@ public final boolean isInitialized() { return false; } } + if (hasConsumerGroupChange()) { + if (!getConsumerGroupChange().isInitialized()) { + + return false; + } + } return true; } @@ -21068,6 +21504,16 @@ public Builder mergeFrom( subBuilder.recycle(); break; } + case 234: { + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.Builder subBuilder = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder(); + if (hasConsumerGroupChange()) { + subBuilder.mergeFrom(getConsumerGroupChange()); + } + input.readMessage(subBuilder, extensionRegistry); + setConsumerGroupChange(subBuilder.buildPartial()); + subBuilder.recycle(); + break; + } } } } @@ -22259,6 +22705,49 @@ public Builder clearSeek() { return this; } + // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; + private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + public boolean hasConsumerGroupChange() { + return ((bitField0_ & 0x10000000) == 0x10000000); + } + public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange() { + return consumerGroupChange_; + } + public Builder setConsumerGroupChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange value) { + if (value == null) { + throw new NullPointerException(); + } + consumerGroupChange_ = value; + + bitField0_ |= 0x10000000; + return this; + } + public Builder setConsumerGroupChange( + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.Builder builderForValue) { + consumerGroupChange_ = builderForValue.build(); + + bitField0_ |= 0x10000000; + return this; + } + public Builder mergeConsumerGroupChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange value) { + if (((bitField0_ & 0x10000000) == 0x10000000) && + consumerGroupChange_ != org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance()) { + consumerGroupChange_ = + org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder(consumerGroupChange_).mergeFrom(value).buildPartial(); + } else { + consumerGroupChange_ = value; + } + + bitField0_ |= 0x10000000; + return this; + } + public Builder clearConsumerGroupChange() { + consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + + bitField0_ = (bitField0_ & ~0x10000000); + return this; + } + // @@protoc_insertion_point(builder_scope:pulsar.proto.BaseCommand) } diff --git a/pulsar-common/src/main/proto/PulsarApi.proto b/pulsar-common/src/main/proto/PulsarApi.proto index 6c86530d4355f..65a6e378d5213 100644 --- a/pulsar-common/src/main/proto/PulsarApi.proto +++ b/pulsar-common/src/main/proto/PulsarApi.proto @@ -131,6 +131,7 @@ enum ProtocolVersion { v8 = 8; // Added CommandConsumerStats - Client fetches broker side consumer stats v9 = 9; // Added end of topic notification v10 = 10;// Added proxy to broker + v11 = 11;// Added CommandConsumerGroupChange } message CommandConnect { @@ -294,6 +295,12 @@ message CommandAck { repeated KeyLongValue properties = 5; } +// changes on consumer group +message CommandConsumerGroupChange { + required uint64 consumer_id = 1; + optional uint64 active_consumer_id = 2; +} + message CommandFlow { required uint64 consumer_id = 1; @@ -457,6 +464,8 @@ message BaseCommand { REACHED_END_OF_TOPIC = 27; SEEK = 28; + + CONSUMER_GROUP_CHANGE = 29; } required Type type = 1; @@ -497,4 +506,6 @@ message BaseCommand { optional CommandReachedEndOfTopic reachedEndOfTopic = 27; optional CommandSeek seek = 28; + + optional CommandConsumerGroupChange consumer_group_change = 29; } diff --git a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java new file mode 100644 index 0000000000000..1b1121cd12f0d --- /dev/null +++ b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.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.pulsar.common.api; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +/** + * Unit test of {@link PulsarDecoder}. + */ +public class PulsarDecoderTest { + + private PulsarDecoder decoder; + + @BeforeMethod + public void setup() { + this.decoder = mock(PulsarDecoder.class, CALLS_REAL_METHODS); + } + + @Test + public void testChannelRead() throws Exception { + long consumerId = 1234L; + long activeConsumerId = 4567L; + ByteBuf changeBuf = Commands.newConsumerGroupChange(consumerId, activeConsumerId); + ByteBuf cmdBuf = changeBuf.slice(4, changeBuf.writerIndex() - 4); + + doNothing().when(decoder).handleConsumerGroupChange(any(CommandConsumerGroupChange.class)); + decoder.channelRead(mock(ChannelHandlerContext.class), cmdBuf); + + verify(decoder, times(1)) + .handleConsumerGroupChange(any(CommandConsumerGroupChange.class)); + } + + +} From d4f282044700619db90cd65eb30ab60f8b1946d7 Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Sat, 10 Feb 2018 11:30:29 +0800 Subject: [PATCH 02/10] Rename ConsumerGroupListener to ActiveConsumerListener --- .../service/PersistentFailoverE2ETest.java | 32 +++++++++---------- ...tener.java => ActiveConsumerListener.java} | 2 +- .../client/api/ConsumerConfiguration.java | 16 +++++----- .../pulsar/client/impl/ConsumerBase.java | 6 ++-- .../pulsar/client/impl/ConsumerImpl.java | 6 ++-- .../client/impl/PartitionedConsumerImpl.java | 5 ++- 6 files changed, 33 insertions(+), 34 deletions(-) rename pulsar-client/src/main/java/org/apache/pulsar/client/api/{ConsumerGroupListener.java => ActiveConsumerListener.java} (96%) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java index aaac7f2d15823..fc1760e8fecba 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java @@ -37,7 +37,7 @@ import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; -import org.apache.pulsar.client.api.ConsumerGroupListener; +import org.apache.pulsar.client.api.ActiveConsumerListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.Producer; @@ -72,7 +72,7 @@ protected void cleanup() throws Exception { private static final int CONSUMER_ADD_OR_REMOVE_WAIT_TIME = 2000; - private static class TestConsumerGroupStateListener implements ConsumerGroupListener { + private static class TestActiveConsumerStateListener implements ActiveConsumerListener { final LinkedBlockingQueue activeQueue = new LinkedBlockingQueue<>(); final LinkedBlockingQueue inActiveQueue = new LinkedBlockingQueue<>(); @@ -94,22 +94,22 @@ public void becomeInactive(Consumer consumer, int partitionId) { } } - private void verifyConsumerNotReceiveAnyStateChanges(TestConsumerGroupStateListener listener) throws Exception { + private void verifyConsumerNotReceiveAnyStateChanges(TestActiveConsumerStateListener listener) throws Exception { assertNull(listener.activeQueue.poll()); assertNull(listener.inActiveQueue.poll()); } - private void verifyConsumerActive(TestConsumerGroupStateListener listener, int partitionId) throws Exception { + private void verifyConsumerActive(TestActiveConsumerStateListener listener, int partitionId) throws Exception { assertEquals(partitionId, listener.activeQueue.take().intValue()); assertNull(listener.inActiveQueue.poll()); } - private void verifyConsumerInactive(TestConsumerGroupStateListener listener, int partitionId) throws Exception { + private void verifyConsumerInactive(TestActiveConsumerStateListener listener, int partitionId) throws Exception { assertEquals(partitionId, listener.inActiveQueue.take().intValue()); assertNull(listener.activeQueue.poll()); } - private static class ActiveInactiveListener implements ConsumerGroupListener { + private static class ActiveInactiveListenerActive implements ActiveConsumerListener { private final Set activePtns = Sets.newHashSet(); private final Set inactivePtns = Sets.newHashSet(); @@ -133,17 +133,17 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { final String subName = "sub1"; final int numMsgs = 100; - TestConsumerGroupStateListener listener1 = new TestConsumerGroupStateListener(); + TestActiveConsumerStateListener listener1 = new TestActiveConsumerStateListener(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); - consumerConf1.setConsumerGroupListener(listener1); + consumerConf1.setActiveConsumerListener(listener1); - TestConsumerGroupStateListener listener2 = new TestConsumerGroupStateListener(); + TestActiveConsumerStateListener listener2 = new TestActiveConsumerStateListener(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); - consumerConf2.setConsumerGroupListener(listener2); + consumerConf2.setActiveConsumerListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); @@ -264,11 +264,11 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { futures.clear(); // 7. consumer subscription should not send messages to the new consumer if its name is not highest in the list - TestConsumerGroupStateListener listener3 = new TestConsumerGroupStateListener(); + TestActiveConsumerStateListener listener3 = new TestActiveConsumerStateListener(); ConsumerConfiguration consumerConf3 = new ConsumerConfiguration(); consumerConf3.setSubscriptionType(SubscriptionType.Failover); consumerConf3.setConsumerName("3"); - consumerConf3.setConsumerGroupListener(listener3); + consumerConf3.setActiveConsumerListener(listener3); for (int i = 0; i < 5; i++) { msg = consumer1.receive(1, TimeUnit.SECONDS); Assert.assertNotNull(msg); @@ -336,17 +336,17 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { ProducerConfiguration producerConf = new ProducerConfiguration(); producerConf.setMessageRoutingMode(MessageRoutingMode.RoundRobinPartition); - ActiveInactiveListener listener1 = new ActiveInactiveListener(); + ActiveInactiveListenerActive listener1 = new ActiveInactiveListenerActive(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); - consumerConf1.setConsumerGroupListener(listener1); + consumerConf1.setActiveConsumerListener(listener1); - ActiveInactiveListener listener2 = new ActiveInactiveListener(); + ActiveInactiveListenerActive listener2 = new ActiveInactiveListenerActive(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); - consumerConf2.setConsumerGroupListener(listener2); + consumerConf2.setActiveConsumerListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java similarity index 96% rename from pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java rename to pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java index 82eee5b5d2ae9..52df627dc273e 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerGroupListener.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java @@ -21,7 +21,7 @@ /** * Listener on the consumer state changes. */ -public interface ConsumerGroupListener { +public interface ActiveConsumerListener { /** * Notified when the consumer group is changed, and the consumer becomes the active consumer. diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java index 95defeb082168..2f61c1f02980c 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java @@ -46,7 +46,7 @@ public class ConsumerConfiguration implements Serializable { private MessageListener messageListener; - private ConsumerGroupListener consumerGroupListener; + private ActiveConsumerListener activeConsumerListener; private int receiverQueueSize = 1000; @@ -130,16 +130,16 @@ public ConsumerConfiguration setMessageListener(MessageListener messageListener) } /** - * @return this configured {@link ConsumerGroupListener} for the consumer. - * @see #setConsumerGroupListener(ConsumerGroupListener) + * @return this configured {@link ActiveConsumerListener} for the consumer. + * @see #setActiveConsumerListener(ActiveConsumerListener) * @since 1.22.0 */ - public ConsumerGroupListener getConsumerGroupListener() { - return this.consumerGroupListener; + public ActiveConsumerListener getActiveConsumerListener() { + return this.activeConsumerListener; } /** - * Sets a {@link ConsumerGroupListener} for the consumer. + * Sets a {@link ActiveConsumerListener} for the consumer. * *

The consumer group listener is used for receiving consumer state change in a consumer group for failover * subscription. Application can then react to the consumer state changes. @@ -150,9 +150,9 @@ public ConsumerGroupListener getConsumerGroupListener() { * @return consumer configuration * @since 1.22.0 */ - public ConsumerConfiguration setConsumerGroupListener(ConsumerGroupListener listener) { + public ConsumerConfiguration setActiveConsumerListener(ActiveConsumerListener listener) { checkNotNull(listener); - this.consumerGroupListener = listener; + this.activeConsumerListener = listener; return this; } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java index 7a0924271e647..c1cc81076cc30 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java @@ -30,7 +30,7 @@ import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; -import org.apache.pulsar.client.api.ConsumerGroupListener; +import org.apache.pulsar.client.api.ActiveConsumerListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.MessageListener; @@ -55,7 +55,7 @@ enum ConsumerType { protected final String consumerName; protected final CompletableFuture subscribeFuture; protected final MessageListener listener; - protected final ConsumerGroupListener consumerGroupListener; + protected final ActiveConsumerListener activeConsumerListener; protected final ExecutorService listenerExecutor; final BlockingQueue incomingMessages; protected final ConcurrentLinkedQueue> pendingReceives; @@ -70,7 +70,7 @@ protected ConsumerBase(PulsarClientImpl client, String topic, String subscriptio this.consumerName = conf.getConsumerName() == null ? ConsumerName.generateRandomName() : conf.getConsumerName(); this.subscribeFuture = subscribeFuture; this.listener = conf.getMessageListener(); - this.consumerGroupListener = conf.getConsumerGroupListener(); + this.activeConsumerListener = conf.getActiveConsumerListener(); if (receiverQueueSize <= 1) { this.incomingMessages = Queues.newArrayBlockingQueue(1); } else { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java index 27a6e0ba108d7..a53b752e2ab72 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java @@ -736,15 +736,15 @@ private void failPendingReceive() { } void consumerGroupChanged(long activeConsumerId) { - if (consumerGroupListener == null) { + if (activeConsumerListener == null) { return; } listenerExecutor.submit(() -> { if (consumerId == activeConsumerId) { - consumerGroupListener.becomeActive(this, partitionIndex); + activeConsumerListener.becomeActive(this, partitionIndex); } else { - consumerGroupListener.becomeInactive(this, partitionIndex); + activeConsumerListener.becomeInactive(this, partitionIndex); } }); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java index 44037e1e01975..8ab1c3f52da3e 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java @@ -32,7 +32,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; -import com.google.common.collect.ImmutableMap; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; import org.apache.pulsar.client.api.Message; @@ -438,8 +437,8 @@ private ConsumerConfiguration getInternalConsumerConfig() { internalConsumerConfig.setReceiverQueueSize(conf.getReceiverQueueSize()); internalConsumerConfig.setSubscriptionType(conf.getSubscriptionType()); internalConsumerConfig.setConsumerName(consumerName); - if (null != conf.getConsumerGroupListener()) { - internalConsumerConfig.setConsumerGroupListener(conf.getConsumerGroupListener()); + if (null != conf.getActiveConsumerListener()) { + internalConsumerConfig.setActiveConsumerListener(conf.getActiveConsumerListener()); } if (conf.getCryptoKeyReader() != null) { internalConsumerConfig.setCryptoKeyReader(conf.getCryptoKeyReader()); From e8399af74269336254c8b8f37642581dc3701ff9 Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Sat, 10 Feb 2018 11:44:52 +0800 Subject: [PATCH 03/10] Fail subscribe if active consumer listener is provided with non-failover subscription. --- .../org/apache/pulsar/client/impl/PulsarClientImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java index 9f108211e5eaf..6a8c8567a6b08 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java @@ -40,6 +40,7 @@ import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.Reader; import org.apache.pulsar.client.api.ReaderConfiguration; +import org.apache.pulsar.client.api.SubscriptionType; import org.apache.pulsar.client.util.ExecutorProvider; import org.apache.pulsar.client.util.FutureUtil; import org.apache.pulsar.common.naming.DestinationName; @@ -241,6 +242,13 @@ public CompletableFuture subscribeAsync(final String topic, final Stri new PulsarClientException.InvalidConfigurationException("Consumer configuration undefined")); } + if (conf.getActiveConsumerListener() != null + && conf.getSubscriptionType() != SubscriptionType.Failover) { + return FutureUtil.failedFuture( + new PulsarClientException.InvalidConfigurationException( + "Active consumer listener is only supported for failover subscription")); + } + CompletableFuture consumerSubscribedFuture = new CompletableFuture<>(); getPartitionedTopicMetadata(topic).thenAccept(metadata -> { From 44adf2ffd1f461cacc3fbef04d83b35df3e84e7a Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Sat, 10 Feb 2018 12:19:48 +0800 Subject: [PATCH 04/10] Notify consumer state change only after the cursor is rewinded. --- .../AbstractDispatcherSingleActiveConsumer.java | 12 ++++++------ .../PersistentDispatcherSingleActiveConsumer.java | 10 ++++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java index 3ada01adbe691..12bb84269c105 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java @@ -83,8 +83,10 @@ public AbstractDispatcherSingleActiveConsumer(SubType subscriptionType, int part protected abstract void cancelPendingRead(); protected void notifyConsumerGroupChanged(Consumer activeConsumer) { - consumers.forEach(consumer -> - consumer.notifyConsumerGroupChange(activeConsumer.consumerId())); + if (null != activeConsumer && subscriptionType == SubType.Failover) { + consumers.forEach(consumer -> + consumer.notifyConsumerGroupChange(activeConsumer.consumerId())); + } } /** @@ -104,11 +106,9 @@ protected boolean pickAndScheduleActiveConsumer() { return false; } else { // If the active consumer is changed, send notification. - notifyConsumerGroupChanged(activeConsumer); + scheduleReadOnActiveConsumer(); + return true; } - - scheduleReadOnActiveConsumer(); - return true; } public synchronized void addConsumer(Consumer consumer) throws BrokerServiceException { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java index 4e3fd00b5acd8..e8cebcb063dd4 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java @@ -85,7 +85,10 @@ protected void scheduleReadOnActiveConsumer() { log.debug("[{}] Rewind cursor and read more entries without delay", name); } cursor.rewind(); - readMoreEntries(ACTIVE_CONSUMER_UPDATER.get(this)); + + Consumer activeConsumer = ACTIVE_CONSUMER_UPDATER.get(this); + notifyConsumerGroupChanged(activeConsumer); + readMoreEntries(activeConsumer); return; } @@ -102,7 +105,10 @@ protected void scheduleReadOnActiveConsumer() { serviceConfig.getActiveConsumerFailoverDelayTimeMillis()); } cursor.rewind(); - readMoreEntries(ACTIVE_CONSUMER_UPDATER.get(this)); + + Consumer activeConsumer = ACTIVE_CONSUMER_UPDATER.get(this); + notifyConsumerGroupChanged(activeConsumer); + readMoreEntries(activeConsumer); readOnActiveConsumerTask = null; }, serviceConfig.getActiveConsumerFailoverDelayTimeMillis(), TimeUnit.MILLISECONDS); } From 0317289755e4f51041ae935bb99f0cd7022b579c Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Wed, 14 Feb 2018 00:39:17 +0800 Subject: [PATCH 05/10] Address comments --- ...bstractDispatcherSingleActiveConsumer.java | 5 +- .../pulsar/broker/service/Consumer.java | 7 +- ...sistentDispatcherFailoverConsumerTest.java | 40 ++-- .../apache/pulsar/client/impl/ClientCnx.java | 6 +- .../pulsar/client/impl/ConsumerImpl.java | 4 +- .../apache/pulsar/common/api/Commands.java | 16 +- .../pulsar/common/api/PulsarDecoder.java | 8 +- .../pulsar/common/api/proto/PulsarApi.java | 214 +++++++++--------- pulsar-common/src/main/proto/PulsarApi.proto | 12 +- .../pulsar/common/api/PulsarDecoderTest.java | 8 +- 10 files changed, 163 insertions(+), 157 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java index 12bb84269c105..6d7d0b323eeb7 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java @@ -42,7 +42,6 @@ import org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException; import org.apache.pulsar.broker.service.BrokerServiceException.ServerMetadataException; import org.apache.pulsar.client.impl.Backoff; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.utils.CopyOnWriteArrayList; import org.slf4j.Logger; @@ -126,7 +125,9 @@ public synchronized void addConsumer(Consumer consumer) throws BrokerServiceExce // the active consumer is not changed Consumer currentActiveConsumer = ACTIVE_CONSUMER_UPDATER.get(this); if (null == currentActiveConsumer) { - log.warn("Current active consumer disappears while adding consumer {}", consumer); + if (log.isDebugEnabled()) { + log.debug("Current active consumer disappears while adding consumer {}", consumer); + } } else { consumer.notifyConsumerGroupChange(currentActiveConsumer.consumerId()); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java index 6e7d7f2268d9f..e9993b609784e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java @@ -40,7 +40,6 @@ import org.apache.pulsar.common.api.proto.PulsarApi; import org.apache.pulsar.common.api.proto.PulsarApi.CommandAck; import org.apache.pulsar.common.api.proto.PulsarApi.CommandAck.AckType; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.common.api.proto.PulsarApi.MessageIdData; import org.apache.pulsar.common.api.proto.PulsarApi.ProtocolVersion; @@ -147,7 +146,7 @@ public String consumerName() { } void notifyConsumerGroupChange(long activeConsumerId) { - if (cnx.getRemoteEndpointProtocolVersion() < ProtocolVersion.v11.getNumber()) { + if (Commands.peerSupportsActiveConsumerListener(cnx.getRemoteEndpointProtocolVersion())) { // if the client is older than `v11`, we don't need to send consumer group changes. return; } @@ -156,7 +155,9 @@ void notifyConsumerGroupChange(long activeConsumerId) { log.debug("notify consumer {} - that [{}] for subscription {} has new active consumer : {}", consumerId, topicName, subscription.getName(), activeConsumerId); } - cnx.ctx().write(Commands.newConsumerGroupChange(consumerId, activeConsumerId)); + cnx.ctx().writeAndFlush( + Commands.newActiveConsumerChange(consumerId, activeConsumerId), + cnx.ctx().voidPromise()); } /** diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java index d5e2f64619bb8..b5141e2c0f056 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java @@ -68,7 +68,7 @@ import org.apache.pulsar.broker.service.persistent.PersistentSubscription; import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.common.api.proto.PulsarApi.ProtocolVersion; import org.apache.pulsar.common.naming.DestinationName; @@ -95,7 +95,7 @@ public class PersistentDispatcherFailoverConsumerTest { private ManagedCursor cursorMock; private ConfigurationCacheService configCacheService; private ChannelHandlerContext channelCtx; - private LinkedBlockingQueue consumerChanges; + private LinkedBlockingQueue consumerChanges; final String successTopicName = "persistent://part-perf/global/perf.t1/ptopic"; final String failTopicName = "persistent://part-perf/global/perf.t1/pfailTopic"; @@ -143,8 +143,8 @@ public void setup() throws Exception { cmdBuf.writerIndex(writerIndex); cmdInputStream.recycle(); - if (cmd.hasConsumerGroupChange()) { - consumerChanges.put(cmd.getConsumerGroupChange()); + if (cmd.hasActiveConsumerChange()) { + consumerChanges.put(cmd.getActiveConsumerChange()); } cmd.recycle(); } finally { @@ -243,11 +243,11 @@ public Object answer(InvocationOnMock invocationOnMock) throws Throwable { }).when(ledgerMock).asyncDeleteCursor(matches(".*success.*"), any(DeleteCursorCallback.class), anyObject()); } - private void verifyConsumerGroupChange(CommandConsumerGroupChange change, - long consumerId, - long activeConsumerId) { + private void verifyActiveConsumerChange(CommandActiveConsumerChange change, + long consumerId, + boolean isActive) { assertEquals(consumerId, change.getConsumerId()); - assertEquals(activeConsumerId, change.getActiveConsumerId()); + assertEquals(isActive, change.getIsActive()); change.recycle(); } @@ -282,8 +282,8 @@ public void testConsumerGroupChangesWithOldNewConsumers() throws Exception { assertTrue(consumers.get(0).consumerName() == consumer1.consumerName()); assertEquals(2, consumers.size()); - CommandConsumerGroupChange change = consumerChanges.take(); - verifyConsumerGroupChange(change, 2, 1); + CommandActiveConsumerChange change = consumerChanges.take(); + verifyActiveConsumerChange(change, 2, false); verify(channelCtx, times(1)).write(any()); } @@ -309,8 +309,8 @@ public void testAddRemoveConsumer() throws Exception { List consumers = pdfc.getConsumers(); assertTrue(consumers.get(0).consumerName() == consumer1.consumerName()); assertEquals(1, consumers.size()); - CommandConsumerGroupChange change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 1); + CommandActiveConsumerChange change = consumerChanges.take(); + verifyActiveConsumerChange(change, 1, true); verify(consumer1, times(1)).notifyConsumerGroupChange(eq(1L)); // 3. Add again, duplicate allowed @@ -323,7 +323,7 @@ public void testAddRemoveConsumer() throws Exception { assertTrue(pdfc.getActiveConsumer().consumerName() == consumer1.consumerName()); // get the notified with who is the leader change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 1); + verifyActiveConsumerChange(change, 1, true); verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); // 5. Add another consumer which does not change active consumer @@ -335,7 +335,7 @@ public void testAddRemoveConsumer() throws Exception { assertEquals(3, consumers.size()); // get notified with who is the leader change = consumerChanges.take(); - verifyConsumerGroupChange(change, 2, 1); + verifyActiveConsumerChange(change, 2, false); verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); verify(consumer2, times(1)).notifyConsumerGroupChange(eq(1L)); @@ -349,13 +349,13 @@ public void testAddRemoveConsumer() throws Exception { // all consumers will receive notifications change = consumerChanges.take(); - verifyConsumerGroupChange(change, 0, 0); + verifyActiveConsumerChange(change, 0, true); change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 0); + verifyActiveConsumerChange(change, 1, false); change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 0); + verifyActiveConsumerChange(change, 1, false); change = consumerChanges.take(); - verifyConsumerGroupChange(change, 2, 0); + verifyActiveConsumerChange(change, 2, false); verify(consumer0, times(1)).notifyConsumerGroupChange(eq(0L)); verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); verify(consumer1, times(2)).notifyConsumerGroupChange(eq(0L)); @@ -381,9 +381,9 @@ public void testAddRemoveConsumer() throws Exception { // the remaining consumers will receive notifications change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 1); + verifyActiveConsumerChange(change, 1, true); change = consumerChanges.take(); - verifyConsumerGroupChange(change, 1, 1); + verifyActiveConsumerChange(change, 1, true); // 10. Attempt to remove already removed consumer String cause = ""; diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java index 88483fde1ca61..863e4b080ada6 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ClientCnx.java @@ -37,10 +37,10 @@ import org.apache.pulsar.client.impl.BinaryProtoLookupService.LookupDataResult; import org.apache.pulsar.common.api.Commands; import org.apache.pulsar.common.api.PulsarHandler; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseConsumer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; import org.apache.pulsar.common.api.proto.PulsarApi.CommandLookupTopicResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandMessage; @@ -227,7 +227,7 @@ protected void handleMessage(CommandMessage cmdMessage, ByteBuf headersAndPayloa } @Override - protected void handleConsumerGroupChange(CommandConsumerGroupChange change) { + protected void handleActiveConsumerChange(CommandActiveConsumerChange change) { checkArgument(state == State.Ready); if (log.isDebugEnabled()) { @@ -235,7 +235,7 @@ protected void handleConsumerGroupChange(CommandConsumerGroupChange change) { } ConsumerImpl consumer = consumers.get(change.getConsumerId()); if (consumer != null) { - consumer.consumerGroupChanged(change.getActiveConsumerId()); + consumer.activeConsumerChanged(change.getIsActive()); } } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java index a53b752e2ab72..9c74da3f564f5 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java @@ -735,13 +735,13 @@ private void failPendingReceive() { } } - void consumerGroupChanged(long activeConsumerId) { + void activeConsumerChanged(boolean isActive) { if (activeConsumerListener == null) { return; } listenerExecutor.submit(() -> { - if (consumerId == activeConsumerId) { + if (isActive) { activeConsumerListener.becomeActive(this, partitionIndex); } else { activeConsumerListener.becomeInactive(this, partitionIndex); diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java index 055e46b029a89..4bfb47f109512 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java @@ -37,7 +37,7 @@ import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnect; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; import org.apache.pulsar.common.api.proto.PulsarApi.CommandFlow; @@ -351,14 +351,14 @@ public static ByteBuf newUnsubscribe(long consumerId, long requestId) { return res; } - public static ByteBuf newConsumerGroupChange(long consumerId, long activeConsumerId) { - CommandConsumerGroupChange.Builder changeBuilder = CommandConsumerGroupChange.newBuilder() + public static ByteBuf newActiveConsumerChange(long consumerId, long activeConsumerId) { + CommandActiveConsumerChange.Builder changeBuilder = CommandActiveConsumerChange.newBuilder() .setConsumerId(consumerId) - .setActiveConsumerId(activeConsumerId); + .setIsActive(activeConsumerId == consumerId); - CommandConsumerGroupChange change = changeBuilder.build(); + CommandActiveConsumerChange change = changeBuilder.build(); ByteBuf res = serializeWithSize( - BaseCommand.newBuilder().setType(Type.CONSUMER_GROUP_CHANGE).setConsumerGroupChange(change)); + BaseCommand.newBuilder().setType(Type.CONSUMER_GROUP_CHANGE).setActiveConsumerChange(change)); changeBuilder.recycle(); change.recycle(); return res; @@ -905,4 +905,8 @@ public static enum ChecksumType { Crc32c, None; } + + public static boolean peerSupportsActiveConsumerListener(int protocolVersion) { + return protocolVersion < ProtocolVersion.v11.getNumber(); + } } diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java index b892ea9454418..18e817cac8e52 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/PulsarDecoder.java @@ -22,11 +22,11 @@ import org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand; import org.apache.pulsar.common.api.proto.PulsarApi.CommandAck; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseConsumer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandCloseProducer; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnect; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConnected; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStats; import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse; import org.apache.pulsar.common.api.proto.PulsarApi.CommandError; @@ -255,8 +255,8 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception break; case CONSUMER_GROUP_CHANGE: - handleConsumerGroupChange(cmd.getConsumerGroupChange()); - cmd.getConsumerGroupChange().recycle(); + handleActiveConsumerChange(cmd.getActiveConsumerChange()); + cmd.getActiveConsumerChange().recycle(); break; } @@ -343,7 +343,7 @@ protected void handleSeek(CommandSeek seek) { throw new UnsupportedOperationException(); } - protected void handleConsumerGroupChange(CommandConsumerGroupChange change) { + protected void handleActiveConsumerChange(CommandActiveConsumerChange change) { throw new UnsupportedOperationException(); } diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java index 129475c77f5ba..b7d8b45b90aa8 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/proto/PulsarApi.java @@ -12806,29 +12806,29 @@ public Builder removeProperties(int index) { // @@protoc_insertion_point(class_scope:pulsar.proto.CommandAck) } - public interface CommandConsumerGroupChangeOrBuilder + public interface CommandActiveConsumerChangeOrBuilder extends com.google.protobuf.MessageLiteOrBuilder { // required uint64 consumer_id = 1; boolean hasConsumerId(); long getConsumerId(); - // optional uint64 active_consumer_id = 2; - boolean hasActiveConsumerId(); - long getActiveConsumerId(); + // optional bool is_active = 2 [default = false]; + boolean hasIsActive(); + boolean getIsActive(); } - public static final class CommandConsumerGroupChange extends + public static final class CommandActiveConsumerChange extends com.google.protobuf.GeneratedMessageLite - implements CommandConsumerGroupChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStream.ByteBufGeneratedMessage { - // Use CommandConsumerGroupChange.newBuilder() to construct. - private final io.netty.util.Recycler.Handle handle; - private CommandConsumerGroupChange(io.netty.util.Recycler.Handle handle) { + implements CommandActiveConsumerChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStream.ByteBufGeneratedMessage { + // Use CommandActiveConsumerChange.newBuilder() to construct. + private final io.netty.util.Recycler.Handle handle; + private CommandActiveConsumerChange(io.netty.util.Recycler.Handle handle) { this.handle = handle; } - private static final io.netty.util.Recycler RECYCLER = new io.netty.util.Recycler() { - protected CommandConsumerGroupChange newObject(Handle handle) { - return new CommandConsumerGroupChange(handle); + private static final io.netty.util.Recycler RECYCLER = new io.netty.util.Recycler() { + protected CommandActiveConsumerChange newObject(Handle handle) { + return new CommandActiveConsumerChange(handle); } }; @@ -12840,16 +12840,16 @@ public void recycle() { handle.recycle(this); } - private CommandConsumerGroupChange(boolean noInit) { + private CommandActiveConsumerChange(boolean noInit) { this.handle = null; } - private static final CommandConsumerGroupChange defaultInstance; - public static CommandConsumerGroupChange getDefaultInstance() { + private static final CommandActiveConsumerChange defaultInstance; + public static CommandActiveConsumerChange getDefaultInstance() { return defaultInstance; } - public CommandConsumerGroupChange getDefaultInstanceForType() { + public CommandActiveConsumerChange getDefaultInstanceForType() { return defaultInstance; } @@ -12864,19 +12864,19 @@ public long getConsumerId() { return consumerId_; } - // optional uint64 active_consumer_id = 2; - public static final int ACTIVE_CONSUMER_ID_FIELD_NUMBER = 2; - private long activeConsumerId_; - public boolean hasActiveConsumerId() { + // optional bool is_active = 2 [default = false]; + public static final int IS_ACTIVE_FIELD_NUMBER = 2; + private boolean isActive_; + public boolean hasIsActive() { return ((bitField0_ & 0x00000002) == 0x00000002); } - public long getActiveConsumerId() { - return activeConsumerId_; + public boolean getIsActive() { + return isActive_; } private void initFields() { consumerId_ = 0L; - activeConsumerId_ = 0L; + isActive_ = false; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -12903,7 +12903,7 @@ public void writeTo(org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStr output.writeUInt64(1, consumerId_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeUInt64(2, activeConsumerId_); + output.writeBool(2, isActive_); } } @@ -12919,7 +12919,7 @@ public int getSerializedSize() { } if (((bitField0_ & 0x00000002) == 0x00000002)) { size += com.google.protobuf.CodedOutputStream - .computeUInt64Size(2, activeConsumerId_); + .computeBoolSize(2, isActive_); } memoizedSerializedSize = size; return size; @@ -12932,40 +12932,40 @@ protected java.lang.Object writeReplace() return super.writeReplace(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { throw new RuntimeException("Disabled"); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { throw new RuntimeException("Disabled"); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom(byte[] data) + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data).buildParsed(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return newBuilder().mergeFrom(data, extensionRegistry) .buildParsed(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom(java.io.InputStream input) + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom(java.io.InputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return newBuilder().mergeFrom(input, extensionRegistry) .buildParsed(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseDelimitedFrom(java.io.InputStream input) + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { Builder builder = newBuilder(); if (builder.mergeDelimitedFrom(input)) { @@ -12974,7 +12974,7 @@ public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupC return null; } } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseDelimitedFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -12985,12 +12985,12 @@ public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupC return null; } } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return newBuilder().mergeFrom(input).buildParsed(); } - public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange parseFrom( + public static org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { @@ -13000,16 +13000,16 @@ public static org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupC public static Builder newBuilder() { return Builder.create(); } public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange prototype) { + public static Builder newBuilder(org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange prototype) { return newBuilder().mergeFrom(prototype); } public Builder toBuilder() { return newBuilder(this); } public static final class Builder extends com.google.protobuf.GeneratedMessageLite.Builder< - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange, Builder> - implements org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream.ByteBufMessageBuilder { - // Construct using org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder() + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange, Builder> + implements org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChangeOrBuilder, org.apache.pulsar.common.util.protobuf.ByteBufCodedInputStream.ByteBufMessageBuilder { + // Construct using org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.newBuilder() private final io.netty.util.Recycler.Handle handle; private Builder(io.netty.util.Recycler.Handle handle) { this.handle = handle; @@ -13036,7 +13036,7 @@ public Builder clear() { super.clear(); consumerId_ = 0L; bitField0_ = (bitField0_ & ~0x00000001); - activeConsumerId_ = 0L; + isActive_ = false; bitField0_ = (bitField0_ & ~0x00000002); return this; } @@ -13045,21 +13045,21 @@ public Builder clone() { return create().mergeFrom(buildPartial()); } - public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getDefaultInstanceForType() { - return org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + public org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange getDefaultInstanceForType() { + return org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance(); } - public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange build() { - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = buildPartial(); + public org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange build() { + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } - private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange buildParsed() + private org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange buildParsed() throws com.google.protobuf.InvalidProtocolBufferException { - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = buildPartial(); + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException( result).asInvalidProtocolBufferException(); @@ -13067,8 +13067,8 @@ private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange return result; } - public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange buildPartial() { - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange result = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.RECYCLER.get(); + public org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange buildPartial() { + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange result = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.RECYCLER.get(); int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) == 0x00000001)) { @@ -13078,18 +13078,18 @@ public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange b if (((from_bitField0_ & 0x00000002) == 0x00000002)) { to_bitField0_ |= 0x00000002; } - result.activeConsumerId_ = activeConsumerId_; + result.isActive_ = isActive_; result.bitField0_ = to_bitField0_; return result; } - public Builder mergeFrom(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange other) { - if (other == org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance()) return this; + public Builder mergeFrom(org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange other) { + if (other == org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance()) return this; if (other.hasConsumerId()) { setConsumerId(other.getConsumerId()); } - if (other.hasActiveConsumerId()) { - setActiveConsumerId(other.getActiveConsumerId()); + if (other.hasIsActive()) { + setIsActive(other.getIsActive()); } return this; } @@ -13131,7 +13131,7 @@ public Builder mergeFrom( } case 16: { bitField0_ |= 0x00000002; - activeConsumerId_ = input.readUInt64(); + isActive_ = input.readBool(); break; } } @@ -13161,36 +13161,36 @@ public Builder clearConsumerId() { return this; } - // optional uint64 active_consumer_id = 2; - private long activeConsumerId_ ; - public boolean hasActiveConsumerId() { + // optional bool is_active = 2 [default = false]; + private boolean isActive_ ; + public boolean hasIsActive() { return ((bitField0_ & 0x00000002) == 0x00000002); } - public long getActiveConsumerId() { - return activeConsumerId_; + public boolean getIsActive() { + return isActive_; } - public Builder setActiveConsumerId(long value) { + public Builder setIsActive(boolean value) { bitField0_ |= 0x00000002; - activeConsumerId_ = value; + isActive_ = value; return this; } - public Builder clearActiveConsumerId() { + public Builder clearIsActive() { bitField0_ = (bitField0_ & ~0x00000002); - activeConsumerId_ = 0L; + isActive_ = false; return this; } - // @@protoc_insertion_point(builder_scope:pulsar.proto.CommandConsumerGroupChange) + // @@protoc_insertion_point(builder_scope:pulsar.proto.CommandActiveConsumerChange) } static { - defaultInstance = new CommandConsumerGroupChange(true); + defaultInstance = new CommandActiveConsumerChange(true); defaultInstance.initFields(); } - // @@protoc_insertion_point(class_scope:pulsar.proto.CommandConsumerGroupChange) + // @@protoc_insertion_point(class_scope:pulsar.proto.CommandActiveConsumerChange) } public interface CommandFlowOrBuilder @@ -19754,9 +19754,9 @@ public interface BaseCommandOrBuilder boolean hasSeek(); org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek getSeek(); - // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; - boolean hasConsumerGroupChange(); - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange(); + // optional .pulsar.proto.CommandActiveConsumerChange active_consumer_change = 29; + boolean hasActiveConsumerChange(); + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange getActiveConsumerChange(); } public static final class BaseCommand extends com.google.protobuf.GeneratedMessageLite @@ -20194,14 +20194,14 @@ public org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek getSeek() { return seek_; } - // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; - public static final int CONSUMER_GROUP_CHANGE_FIELD_NUMBER = 29; - private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange consumerGroupChange_; - public boolean hasConsumerGroupChange() { + // optional .pulsar.proto.CommandActiveConsumerChange active_consumer_change = 29; + public static final int ACTIVE_CONSUMER_CHANGE_FIELD_NUMBER = 29; + private org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange activeConsumerChange_; + public boolean hasActiveConsumerChange() { return ((bitField0_ & 0x10000000) == 0x10000000); } - public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange() { - return consumerGroupChange_; + public org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange getActiveConsumerChange() { + return activeConsumerChange_; } private void initFields() { @@ -20233,7 +20233,7 @@ private void initFields() { consumerStatsResponse_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerStatsResponse.getDefaultInstance(); reachedEndOfTopic_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandReachedEndOfTopic.getDefaultInstance(); seek_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek.getDefaultInstance(); - consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + activeConsumerChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -20394,8 +20394,8 @@ public final boolean isInitialized() { return false; } } - if (hasConsumerGroupChange()) { - if (!getConsumerGroupChange().isInitialized()) { + if (hasActiveConsumerChange()) { + if (!getActiveConsumerChange().isInitialized()) { memoizedIsInitialized = 0; return false; } @@ -20497,7 +20497,7 @@ public void writeTo(org.apache.pulsar.common.util.protobuf.ByteBufCodedOutputStr output.writeMessage(28, seek_); } if (((bitField0_ & 0x10000000) == 0x10000000)) { - output.writeMessage(29, consumerGroupChange_); + output.writeMessage(29, activeConsumerChange_); } } @@ -20621,7 +20621,7 @@ public int getSerializedSize() { } if (((bitField0_ & 0x10000000) == 0x10000000)) { size += com.google.protobuf.CodedOutputStream - .computeMessageSize(29, consumerGroupChange_); + .computeMessageSize(29, activeConsumerChange_); } memoizedSerializedSize = size; return size; @@ -20792,7 +20792,7 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x04000000); seek_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandSeek.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x08000000); - consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + activeConsumerChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x10000000); return this; } @@ -20942,7 +20942,7 @@ public org.apache.pulsar.common.api.proto.PulsarApi.BaseCommand buildPartial() { if (((from_bitField0_ & 0x10000000) == 0x10000000)) { to_bitField0_ |= 0x10000000; } - result.consumerGroupChange_ = consumerGroupChange_; + result.activeConsumerChange_ = activeConsumerChange_; result.bitField0_ = to_bitField0_; return result; } @@ -21033,8 +21033,8 @@ public Builder mergeFrom(org.apache.pulsar.common.api.proto.PulsarApi.BaseComman if (other.hasSeek()) { mergeSeek(other.getSeek()); } - if (other.hasConsumerGroupChange()) { - mergeConsumerGroupChange(other.getConsumerGroupChange()); + if (other.hasActiveConsumerChange()) { + mergeActiveConsumerChange(other.getActiveConsumerChange()); } return this; } @@ -21194,8 +21194,8 @@ public final boolean isInitialized() { return false; } } - if (hasConsumerGroupChange()) { - if (!getConsumerGroupChange().isInitialized()) { + if (hasActiveConsumerChange()) { + if (!getActiveConsumerChange().isInitialized()) { return false; } @@ -21505,12 +21505,12 @@ public Builder mergeFrom( break; } case 234: { - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.Builder subBuilder = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder(); - if (hasConsumerGroupChange()) { - subBuilder.mergeFrom(getConsumerGroupChange()); + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.Builder subBuilder = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.newBuilder(); + if (hasActiveConsumerChange()) { + subBuilder.mergeFrom(getActiveConsumerChange()); } input.readMessage(subBuilder, extensionRegistry); - setConsumerGroupChange(subBuilder.buildPartial()); + setActiveConsumerChange(subBuilder.buildPartial()); subBuilder.recycle(); break; } @@ -22705,44 +22705,44 @@ public Builder clearSeek() { return this; } - // optional .pulsar.proto.CommandConsumerGroupChange consumer_group_change = 29; - private org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); - public boolean hasConsumerGroupChange() { + // optional .pulsar.proto.CommandActiveConsumerChange active_consumer_change = 29; + private org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange activeConsumerChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance(); + public boolean hasActiveConsumerChange() { return ((bitField0_ & 0x10000000) == 0x10000000); } - public org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange getConsumerGroupChange() { - return consumerGroupChange_; + public org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange getActiveConsumerChange() { + return activeConsumerChange_; } - public Builder setConsumerGroupChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange value) { + public Builder setActiveConsumerChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange value) { if (value == null) { throw new NullPointerException(); } - consumerGroupChange_ = value; + activeConsumerChange_ = value; bitField0_ |= 0x10000000; return this; } - public Builder setConsumerGroupChange( - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.Builder builderForValue) { - consumerGroupChange_ = builderForValue.build(); + public Builder setActiveConsumerChange( + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.Builder builderForValue) { + activeConsumerChange_ = builderForValue.build(); bitField0_ |= 0x10000000; return this; } - public Builder mergeConsumerGroupChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange value) { + public Builder mergeActiveConsumerChange(org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange value) { if (((bitField0_ & 0x10000000) == 0x10000000) && - consumerGroupChange_ != org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance()) { - consumerGroupChange_ = - org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.newBuilder(consumerGroupChange_).mergeFrom(value).buildPartial(); + activeConsumerChange_ != org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance()) { + activeConsumerChange_ = + org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.newBuilder(activeConsumerChange_).mergeFrom(value).buildPartial(); } else { - consumerGroupChange_ = value; + activeConsumerChange_ = value; } bitField0_ |= 0x10000000; return this; } - public Builder clearConsumerGroupChange() { - consumerGroupChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange.getDefaultInstance(); + public Builder clearActiveConsumerChange() { + activeConsumerChange_ = org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange.getDefaultInstance(); bitField0_ = (bitField0_ & ~0x10000000); return this; diff --git a/pulsar-common/src/main/proto/PulsarApi.proto b/pulsar-common/src/main/proto/PulsarApi.proto index 65a6e378d5213..ab715818e7a38 100644 --- a/pulsar-common/src/main/proto/PulsarApi.proto +++ b/pulsar-common/src/main/proto/PulsarApi.proto @@ -131,7 +131,7 @@ enum ProtocolVersion { v8 = 8; // Added CommandConsumerStats - Client fetches broker side consumer stats v9 = 9; // Added end of topic notification v10 = 10;// Added proxy to broker - v11 = 11;// Added CommandConsumerGroupChange + v11 = 11;// Added CommandActiveConsumerChange } message CommandConnect { @@ -295,10 +295,10 @@ message CommandAck { repeated KeyLongValue properties = 5; } -// changes on consumer group -message CommandConsumerGroupChange { - required uint64 consumer_id = 1; - optional uint64 active_consumer_id = 2; +// changes on active consumer +message CommandActiveConsumerChange { + required uint64 consumer_id = 1; + optional bool is_active = 2 [default = false]; } message CommandFlow { @@ -507,5 +507,5 @@ message BaseCommand { optional CommandSeek seek = 28; - optional CommandConsumerGroupChange consumer_group_change = 29; + optional CommandActiveConsumerChange active_consumer_change = 29; } diff --git a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java index 1b1121cd12f0d..309383510c5fb 100644 --- a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java +++ b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java @@ -27,7 +27,7 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; -import org.apache.pulsar.common.api.proto.PulsarApi.CommandConsumerGroupChange; +import org.apache.pulsar.common.api.proto.PulsarApi.CommandActiveConsumerChange; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -47,14 +47,14 @@ public void setup() { public void testChannelRead() throws Exception { long consumerId = 1234L; long activeConsumerId = 4567L; - ByteBuf changeBuf = Commands.newConsumerGroupChange(consumerId, activeConsumerId); + ByteBuf changeBuf = Commands.newActiveConsumerChange(consumerId, activeConsumerId); ByteBuf cmdBuf = changeBuf.slice(4, changeBuf.writerIndex() - 4); - doNothing().when(decoder).handleConsumerGroupChange(any(CommandConsumerGroupChange.class)); + doNothing().when(decoder).handleActiveConsumerChange(any(CommandActiveConsumerChange.class)); decoder.channelRead(mock(ChannelHandlerContext.class), cmdBuf); verify(decoder, times(1)) - .handleConsumerGroupChange(any(CommandConsumerGroupChange.class)); + .handleActiveConsumerChange(any(CommandActiveConsumerChange.class)); } From b8411ba1dbafcd240199998b9c484bd81a9125fe Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Wed, 14 Feb 2018 23:53:44 +0800 Subject: [PATCH 06/10] Rename ActiveConsumerListener to ConsumerEventListener Use consumer object as identifier for comparison --- ...bstractDispatcherSingleActiveConsumer.java | 20 ++---------- .../pulsar/broker/service/Consumer.java | 6 ++-- ...sistentDispatcherSingleActiveConsumer.java | 4 +-- ...sistentDispatcherFailoverConsumerTest.java | 20 ++++++------ .../service/PersistentFailoverE2ETest.java | 32 +++++++++---------- .../client/api/ConsumerConfiguration.java | 20 ++++++------ ...stener.java => ConsumerEventListener.java} | 2 +- .../pulsar/client/impl/ConsumerBase.java | 6 ++-- .../pulsar/client/impl/ConsumerImpl.java | 6 ++-- .../client/impl/PartitionedConsumerImpl.java | 4 +-- .../pulsar/client/impl/PulsarClientImpl.java | 2 +- .../apache/pulsar/common/api/Commands.java | 4 +-- .../pulsar/common/api/PulsarDecoderTest.java | 3 +- 13 files changed, 57 insertions(+), 72 deletions(-) rename pulsar-client/src/main/java/org/apache/pulsar/client/api/{ActiveConsumerListener.java => ConsumerEventListener.java} (96%) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java index 6d7d0b323eeb7..05b78102ece09 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/AbstractDispatcherSingleActiveConsumer.java @@ -21,27 +21,13 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import org.apache.bookkeeper.mledger.AsyncCallbacks.ReadEntriesCallback; -import org.apache.bookkeeper.mledger.Entry; -import org.apache.bookkeeper.mledger.ManagedCursor; -import org.apache.bookkeeper.mledger.ManagedLedgerException; -import org.apache.bookkeeper.mledger.ManagedLedgerException.NoMoreEntriesToReadException; -import org.apache.bookkeeper.mledger.ManagedLedgerException.TooManyRequestsException; -import org.apache.bookkeeper.mledger.impl.PositionImpl; -import org.apache.pulsar.broker.service.BrokerServiceException; -import org.apache.pulsar.broker.service.Consumer; -import org.apache.pulsar.broker.service.Dispatcher; -import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException; import org.apache.pulsar.broker.service.BrokerServiceException.ServerMetadataException; -import org.apache.pulsar.client.impl.Backoff; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; import org.apache.pulsar.utils.CopyOnWriteArrayList; import org.slf4j.Logger; @@ -81,10 +67,10 @@ public AbstractDispatcherSingleActiveConsumer(SubType subscriptionType, int part protected abstract void cancelPendingRead(); - protected void notifyConsumerGroupChanged(Consumer activeConsumer) { + protected void notifyActiveConsumerChanged(Consumer activeConsumer) { if (null != activeConsumer && subscriptionType == SubType.Failover) { consumers.forEach(consumer -> - consumer.notifyConsumerGroupChange(activeConsumer.consumerId())); + consumer.notifyActiveConsumerChange(activeConsumer)); } } @@ -129,7 +115,7 @@ public synchronized void addConsumer(Consumer consumer) throws BrokerServiceExce log.debug("Current active consumer disappears while adding consumer {}", consumer); } } else { - consumer.notifyConsumerGroupChange(currentActiveConsumer.consumerId()); + consumer.notifyActiveConsumerChange(currentActiveConsumer); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java index e9993b609784e..eae2f4659fbef 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Consumer.java @@ -145,7 +145,7 @@ public String consumerName() { return consumerName; } - void notifyConsumerGroupChange(long activeConsumerId) { + void notifyActiveConsumerChange(Consumer activeConsumer) { if (Commands.peerSupportsActiveConsumerListener(cnx.getRemoteEndpointProtocolVersion())) { // if the client is older than `v11`, we don't need to send consumer group changes. return; @@ -153,10 +153,10 @@ void notifyConsumerGroupChange(long activeConsumerId) { if (log.isDebugEnabled()) { log.debug("notify consumer {} - that [{}] for subscription {} has new active consumer : {}", - consumerId, topicName, subscription.getName(), activeConsumerId); + consumerId, topicName, subscription.getName(), activeConsumer); } cnx.ctx().writeAndFlush( - Commands.newActiveConsumerChange(consumerId, activeConsumerId), + Commands.newActiveConsumerChange(consumerId, this == activeConsumer), cnx.ctx().voidPromise()); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java index e8cebcb063dd4..6c30bcaf75c45 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentDispatcherSingleActiveConsumer.java @@ -87,7 +87,7 @@ protected void scheduleReadOnActiveConsumer() { cursor.rewind(); Consumer activeConsumer = ACTIVE_CONSUMER_UPDATER.get(this); - notifyConsumerGroupChanged(activeConsumer); + notifyActiveConsumerChanged(activeConsumer); readMoreEntries(activeConsumer); return; } @@ -107,7 +107,7 @@ protected void scheduleReadOnActiveConsumer() { cursor.rewind(); Consumer activeConsumer = ACTIVE_CONSUMER_UPDATER.get(this); - notifyConsumerGroupChanged(activeConsumer); + notifyActiveConsumerChanged(activeConsumer); readMoreEntries(activeConsumer); readOnActiveConsumerTask = null; }, serviceConfig.getActiveConsumerFailoverDelayTimeMillis(), TimeUnit.MILLISECONDS); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java index b5141e2c0f056..47d515d26bbec 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java @@ -21,8 +21,8 @@ import static org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest.createMockZooKeeper; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.eq; import static org.mockito.Matchers.matches; +import static org.mockito.Matchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -311,7 +311,7 @@ public void testAddRemoveConsumer() throws Exception { assertEquals(1, consumers.size()); CommandActiveConsumerChange change = consumerChanges.take(); verifyActiveConsumerChange(change, 1, true); - verify(consumer1, times(1)).notifyConsumerGroupChange(eq(1L)); + verify(consumer1, times(1)).notifyActiveConsumerChange(same(consumer1)); // 3. Add again, duplicate allowed pdfc.addConsumer(consumer1); @@ -324,7 +324,7 @@ public void testAddRemoveConsumer() throws Exception { // get the notified with who is the leader change = consumerChanges.take(); verifyActiveConsumerChange(change, 1, true); - verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); + verify(consumer1, times(2)).notifyActiveConsumerChange(same(consumer1)); // 5. Add another consumer which does not change active consumer Consumer consumer2 = spy(new Consumer(sub, SubType.Exclusive, topic.getName(), 2 /* consumer id */, 0, "Cons2"/* consumer name */, @@ -336,8 +336,8 @@ public void testAddRemoveConsumer() throws Exception { // get notified with who is the leader change = consumerChanges.take(); verifyActiveConsumerChange(change, 2, false); - verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); - verify(consumer2, times(1)).notifyConsumerGroupChange(eq(1L)); + verify(consumer1, times(2)).notifyActiveConsumerChange(same(consumer1)); + verify(consumer2, times(1)).notifyActiveConsumerChange(same(consumer1)); // 6. Add a consumer which changes active consumer Consumer consumer0 = spy(new Consumer(sub, SubType.Exclusive, topic.getName(), 0 /* consumer id */, 0, @@ -356,11 +356,11 @@ public void testAddRemoveConsumer() throws Exception { verifyActiveConsumerChange(change, 1, false); change = consumerChanges.take(); verifyActiveConsumerChange(change, 2, false); - verify(consumer0, times(1)).notifyConsumerGroupChange(eq(0L)); - verify(consumer1, times(2)).notifyConsumerGroupChange(eq(1L)); - verify(consumer1, times(2)).notifyConsumerGroupChange(eq(0L)); - verify(consumer2, times(1)).notifyConsumerGroupChange(eq(1L)); - verify(consumer2, times(1)).notifyConsumerGroupChange(eq(0L)); + verify(consumer0, times(1)).notifyActiveConsumerChange(same(consumer0)); + verify(consumer1, times(2)).notifyActiveConsumerChange(same(consumer1)); + verify(consumer1, times(2)).notifyActiveConsumerChange(same(consumer0)); + verify(consumer2, times(1)).notifyActiveConsumerChange(same(consumer1)); + verify(consumer2, times(1)).notifyActiveConsumerChange(same(consumer0)); // 7. Remove last consumer pdfc.removeConsumer(consumer2); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java index fc1760e8fecba..da9f1c2051c9b 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java @@ -37,7 +37,7 @@ import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; -import org.apache.pulsar.client.api.ActiveConsumerListener; +import org.apache.pulsar.client.api.ConsumerEventListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.Producer; @@ -72,7 +72,7 @@ protected void cleanup() throws Exception { private static final int CONSUMER_ADD_OR_REMOVE_WAIT_TIME = 2000; - private static class TestActiveConsumerStateListener implements ActiveConsumerListener { + private static class TestConsumerStateEventListener implements ConsumerEventListener { final LinkedBlockingQueue activeQueue = new LinkedBlockingQueue<>(); final LinkedBlockingQueue inActiveQueue = new LinkedBlockingQueue<>(); @@ -94,22 +94,22 @@ public void becomeInactive(Consumer consumer, int partitionId) { } } - private void verifyConsumerNotReceiveAnyStateChanges(TestActiveConsumerStateListener listener) throws Exception { + private void verifyConsumerNotReceiveAnyStateChanges(TestConsumerStateEventListener listener) throws Exception { assertNull(listener.activeQueue.poll()); assertNull(listener.inActiveQueue.poll()); } - private void verifyConsumerActive(TestActiveConsumerStateListener listener, int partitionId) throws Exception { + private void verifyConsumerActive(TestConsumerStateEventListener listener, int partitionId) throws Exception { assertEquals(partitionId, listener.activeQueue.take().intValue()); assertNull(listener.inActiveQueue.poll()); } - private void verifyConsumerInactive(TestActiveConsumerStateListener listener, int partitionId) throws Exception { + private void verifyConsumerInactive(TestConsumerStateEventListener listener, int partitionId) throws Exception { assertEquals(partitionId, listener.inActiveQueue.take().intValue()); assertNull(listener.activeQueue.poll()); } - private static class ActiveInactiveListenerActive implements ActiveConsumerListener { + private static class ActiveInactiveListenerEvent implements ConsumerEventListener { private final Set activePtns = Sets.newHashSet(); private final Set inactivePtns = Sets.newHashSet(); @@ -133,17 +133,17 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { final String subName = "sub1"; final int numMsgs = 100; - TestActiveConsumerStateListener listener1 = new TestActiveConsumerStateListener(); + TestConsumerStateEventListener listener1 = new TestConsumerStateEventListener(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); - consumerConf1.setActiveConsumerListener(listener1); + consumerConf1.setConsumerEventListener(listener1); - TestActiveConsumerStateListener listener2 = new TestActiveConsumerStateListener(); + TestConsumerStateEventListener listener2 = new TestConsumerStateEventListener(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); - consumerConf2.setActiveConsumerListener(listener2); + consumerConf2.setConsumerEventListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); @@ -264,11 +264,11 @@ public void testSimpleConsumerEventsWithoutPartition() throws Exception { futures.clear(); // 7. consumer subscription should not send messages to the new consumer if its name is not highest in the list - TestActiveConsumerStateListener listener3 = new TestActiveConsumerStateListener(); + TestConsumerStateEventListener listener3 = new TestConsumerStateEventListener(); ConsumerConfiguration consumerConf3 = new ConsumerConfiguration(); consumerConf3.setSubscriptionType(SubscriptionType.Failover); consumerConf3.setConsumerName("3"); - consumerConf3.setActiveConsumerListener(listener3); + consumerConf3.setConsumerEventListener(listener3); for (int i = 0; i < 5; i++) { msg = consumer1.receive(1, TimeUnit.SECONDS); Assert.assertNotNull(msg); @@ -336,17 +336,17 @@ public void testSimpleConsumerEventsWithPartition() throws Exception { ProducerConfiguration producerConf = new ProducerConfiguration(); producerConf.setMessageRoutingMode(MessageRoutingMode.RoundRobinPartition); - ActiveInactiveListenerActive listener1 = new ActiveInactiveListenerActive(); + ActiveInactiveListenerEvent listener1 = new ActiveInactiveListenerEvent(); ConsumerConfiguration consumerConf1 = new ConsumerConfiguration(); consumerConf1.setSubscriptionType(SubscriptionType.Failover); consumerConf1.setConsumerName("1"); - consumerConf1.setActiveConsumerListener(listener1); + consumerConf1.setConsumerEventListener(listener1); - ActiveInactiveListenerActive listener2 = new ActiveInactiveListenerActive(); + ActiveInactiveListenerEvent listener2 = new ActiveInactiveListenerEvent(); ConsumerConfiguration consumerConf2 = new ConsumerConfiguration(); consumerConf2.setSubscriptionType(SubscriptionType.Failover); consumerConf2.setConsumerName("2"); - consumerConf2.setActiveConsumerListener(listener2); + consumerConf2.setConsumerEventListener(listener2); // 1. two consumers on the same subscription Consumer consumer1 = pulsarClient.subscribe(topicName, subName, consumerConf1); diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java index 2f61c1f02980c..88a186c0ef2a4 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerConfiguration.java @@ -46,7 +46,7 @@ public class ConsumerConfiguration implements Serializable { private MessageListener messageListener; - private ActiveConsumerListener activeConsumerListener; + private ConsumerEventListener consumerEventListener; private int receiverQueueSize = 1000; @@ -130,16 +130,16 @@ public ConsumerConfiguration setMessageListener(MessageListener messageListener) } /** - * @return this configured {@link ActiveConsumerListener} for the consumer. - * @see #setActiveConsumerListener(ActiveConsumerListener) - * @since 1.22.0 + * @return this configured {@link ConsumerEventListener} for the consumer. + * @see #setConsumerEventListener(ConsumerEventListener) + * @since 2.0 */ - public ActiveConsumerListener getActiveConsumerListener() { - return this.activeConsumerListener; + public ConsumerEventListener getConsumerEventListener() { + return this.consumerEventListener; } /** - * Sets a {@link ActiveConsumerListener} for the consumer. + * Sets a {@link ConsumerEventListener} for the consumer. * *

The consumer group listener is used for receiving consumer state change in a consumer group for failover * subscription. Application can then react to the consumer state changes. @@ -148,11 +148,11 @@ public ActiveConsumerListener getActiveConsumerListener() { * * @param listener the consumer group listener object * @return consumer configuration - * @since 1.22.0 + * @since 2.0 */ - public ConsumerConfiguration setActiveConsumerListener(ActiveConsumerListener listener) { + public ConsumerConfiguration setConsumerEventListener(ConsumerEventListener listener) { checkNotNull(listener); - this.activeConsumerListener = listener; + this.consumerEventListener = listener; return this; } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java similarity index 96% rename from pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java rename to pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java index 52df627dc273e..3729ae400b228 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ActiveConsumerListener.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java @@ -21,7 +21,7 @@ /** * Listener on the consumer state changes. */ -public interface ActiveConsumerListener { +public interface ConsumerEventListener { /** * Notified when the consumer group is changed, and the consumer becomes the active consumer. diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java index c1cc81076cc30..22641f5b1a671 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java @@ -30,7 +30,7 @@ import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.ConsumerConfiguration; -import org.apache.pulsar.client.api.ActiveConsumerListener; +import org.apache.pulsar.client.api.ConsumerEventListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.MessageListener; @@ -55,7 +55,7 @@ enum ConsumerType { protected final String consumerName; protected final CompletableFuture subscribeFuture; protected final MessageListener listener; - protected final ActiveConsumerListener activeConsumerListener; + protected final ConsumerEventListener consumerEventListener; protected final ExecutorService listenerExecutor; final BlockingQueue incomingMessages; protected final ConcurrentLinkedQueue> pendingReceives; @@ -70,7 +70,7 @@ protected ConsumerBase(PulsarClientImpl client, String topic, String subscriptio this.consumerName = conf.getConsumerName() == null ? ConsumerName.generateRandomName() : conf.getConsumerName(); this.subscribeFuture = subscribeFuture; this.listener = conf.getMessageListener(); - this.activeConsumerListener = conf.getActiveConsumerListener(); + this.consumerEventListener = conf.getConsumerEventListener(); if (receiverQueueSize <= 1) { this.incomingMessages = Queues.newArrayBlockingQueue(1); } else { diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java index 9c74da3f564f5..4751658c6a4c0 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java @@ -736,15 +736,15 @@ private void failPendingReceive() { } void activeConsumerChanged(boolean isActive) { - if (activeConsumerListener == null) { + if (consumerEventListener == null) { return; } listenerExecutor.submit(() -> { if (isActive) { - activeConsumerListener.becomeActive(this, partitionIndex); + consumerEventListener.becomeActive(this, partitionIndex); } else { - activeConsumerListener.becomeInactive(this, partitionIndex); + consumerEventListener.becomeInactive(this, partitionIndex); } }); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java index 8ab1c3f52da3e..b884ff1c27cec 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PartitionedConsumerImpl.java @@ -437,8 +437,8 @@ private ConsumerConfiguration getInternalConsumerConfig() { internalConsumerConfig.setReceiverQueueSize(conf.getReceiverQueueSize()); internalConsumerConfig.setSubscriptionType(conf.getSubscriptionType()); internalConsumerConfig.setConsumerName(consumerName); - if (null != conf.getActiveConsumerListener()) { - internalConsumerConfig.setActiveConsumerListener(conf.getActiveConsumerListener()); + if (null != conf.getConsumerEventListener()) { + internalConsumerConfig.setConsumerEventListener(conf.getConsumerEventListener()); } if (conf.getCryptoKeyReader() != null) { internalConsumerConfig.setCryptoKeyReader(conf.getCryptoKeyReader()); diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java index 6a8c8567a6b08..3d67a7170980b 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java @@ -242,7 +242,7 @@ public CompletableFuture subscribeAsync(final String topic, final Stri new PulsarClientException.InvalidConfigurationException("Consumer configuration undefined")); } - if (conf.getActiveConsumerListener() != null + if (conf.getConsumerEventListener() != null && conf.getSubscriptionType() != SubscriptionType.Failover) { return FutureUtil.failedFuture( new PulsarClientException.InvalidConfigurationException( diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java index 4bfb47f109512..2e238f83ca433 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/api/Commands.java @@ -351,10 +351,10 @@ public static ByteBuf newUnsubscribe(long consumerId, long requestId) { return res; } - public static ByteBuf newActiveConsumerChange(long consumerId, long activeConsumerId) { + public static ByteBuf newActiveConsumerChange(long consumerId, boolean isActive) { CommandActiveConsumerChange.Builder changeBuilder = CommandActiveConsumerChange.newBuilder() .setConsumerId(consumerId) - .setIsActive(activeConsumerId == consumerId); + .setIsActive(isActive); CommandActiveConsumerChange change = changeBuilder.build(); ByteBuf res = serializeWithSize( diff --git a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java index 309383510c5fb..6a5f4d3e581bf 100644 --- a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java +++ b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java @@ -46,8 +46,7 @@ public void setup() { @Test public void testChannelRead() throws Exception { long consumerId = 1234L; - long activeConsumerId = 4567L; - ByteBuf changeBuf = Commands.newActiveConsumerChange(consumerId, activeConsumerId); + ByteBuf changeBuf = Commands.newActiveConsumerChange(consumerId, true); ByteBuf cmdBuf = changeBuf.slice(4, changeBuf.writerIndex() - 4); doNothing().when(decoder).handleActiveConsumerChange(any(CommandActiveConsumerChange.class)); From 91fe3a284aa4f2fd6caadbe3de392d73cf9055e2 Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Thu, 15 Feb 2018 01:45:15 +0800 Subject: [PATCH 07/10] Fix test after rebase --- .../service/PersistentDispatcherFailoverConsumerTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java index ea2f284ab5dc1..922b35bc54d3d 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentDispatcherFailoverConsumerTest.java @@ -152,13 +152,13 @@ public void setup() throws Exception { } return null; - }).when(channelCtx).write(any()); + }).when(channelCtx).writeAndFlush(any(), any()); serverCnx = spy(new ServerCnx(brokerService)); doReturn(true).when(serverCnx).isActive(); doReturn(true).when(serverCnx).isWritable(); doReturn(new InetSocketAddress("localhost", 1234)).when(serverCnx).clientAddress(); - when(serverCnx.getRemoteEndpointProtocolVersion()).thenReturn(ProtocolVersion.v11.getNumber()); + when(serverCnx.getRemoteEndpointProtocolVersion()).thenReturn(ProtocolVersion.v12.getNumber()); when(serverCnx.ctx()).thenReturn(channelCtx); serverCnxWithOldVersion = spy(new ServerCnx(brokerService)); @@ -167,7 +167,7 @@ public void setup() throws Exception { doReturn(new InetSocketAddress("localhost", 1234)) .when(serverCnxWithOldVersion).clientAddress(); when(serverCnxWithOldVersion.getRemoteEndpointProtocolVersion()) - .thenReturn(ProtocolVersion.v10.getNumber()); + .thenReturn(ProtocolVersion.v11.getNumber()); when(serverCnxWithOldVersion.ctx()).thenReturn(channelCtx); NamespaceService nsSvc = mock(NamespaceService.class); @@ -285,7 +285,7 @@ public void testConsumerGroupChangesWithOldNewConsumers() throws Exception { CommandActiveConsumerChange change = consumerChanges.take(); verifyActiveConsumerChange(change, 2, false); - verify(channelCtx, times(1)).write(any()); + verify(channelCtx, times(1)).writeAndFlush(any(), any()); } @Test From 28559f110a8b9042605285ab0ef4b2bcec3a8a1f Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Thu, 15 Feb 2018 07:30:11 +0800 Subject: [PATCH 08/10] Fix license headers --- .../org/apache/pulsar/client/api/ConsumerEventListener.java | 2 +- .../java/org/apache/pulsar/common/api/PulsarDecoderTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java index 3729ae400b228..3dbe2ce0ad936 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java @@ -1,4 +1,4 @@ -/* +/** * 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 diff --git a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java index 6a5f4d3e581bf..c57a8c873e9a6 100644 --- a/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java +++ b/pulsar-common/src/test/java/org/apache/pulsar/common/api/PulsarDecoderTest.java @@ -1,4 +1,4 @@ -/* +/** * 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 From 358c772ef9ddd5ca11702bda06a7a31186ab26fd Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Thu, 15 Feb 2018 08:20:13 +0800 Subject: [PATCH 09/10] Ignore active consumer change command in cpp client --- pulsar-client-cpp/lib/ClientConnection.cc | 7 +++++++ pulsar-client-cpp/lib/Commands.cc | 3 +++ 2 files changed, 10 insertions(+) diff --git a/pulsar-client-cpp/lib/ClientConnection.cc b/pulsar-client-cpp/lib/ClientConnection.cc index fc773fedf19e5..018f4ab885309 100644 --- a/pulsar-client-cpp/lib/ClientConnection.cc +++ b/pulsar-client-cpp/lib/ClientConnection.cc @@ -921,6 +921,13 @@ void ClientConnection::handleIncomingCommand() { break; } + case BaseCommand::ACTIVE_CONSUMER_CHANGE: { + LOG_DEBUG(cnxString_ << "Received notification about active consumer changes"); + // ignore this message for now. + // TODO: @link{https://github.com/apache/incubator-pulsar/issues/1240} + break; + } + default: { LOG_WARN(cnxString_ << "Received invalid message from server"); close(); diff --git a/pulsar-client-cpp/lib/Commands.cc b/pulsar-client-cpp/lib/Commands.cc index 70d61dfa19d03..e0245c55526bd 100644 --- a/pulsar-client-cpp/lib/Commands.cc +++ b/pulsar-client-cpp/lib/Commands.cc @@ -381,6 +381,9 @@ std::string Commands::messageType(BaseCommand_Type type) { case BaseCommand::SEEK: return "SEEK"; break; + case BaseCommand::ACTIVE_CONSUMER_CHANGE: + return "ACTIVE_CONSUMER_CHANGE"; + break; }; } From 647624b4e6c3cb39e9801024c440b32f892a5d84 Mon Sep 17 00:00:00 2001 From: Sijie Guo Date: Thu, 15 Feb 2018 09:02:47 +0800 Subject: [PATCH 10/10] rename "become" to "became" --- .../pulsar/broker/service/PersistentFailoverE2ETest.java | 8 ++++---- .../apache/pulsar/client/api/ConsumerEventListener.java | 4 ++-- .../java/org/apache/pulsar/client/impl/ConsumerImpl.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java index 3065edb69782c..7bc31415505c7 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentFailoverE2ETest.java @@ -78,7 +78,7 @@ private static class TestConsumerStateEventListener implements ConsumerEventList final LinkedBlockingQueue inActiveQueue = new LinkedBlockingQueue<>(); @Override - public void becomeActive(Consumer consumer, int partitionId) { + public void becameActive(Consumer consumer, int partitionId) { try { activeQueue.put(partitionId); } catch (InterruptedException e) { @@ -86,7 +86,7 @@ public void becomeActive(Consumer consumer, int partitionId) { } @Override - public void becomeInactive(Consumer consumer, int partitionId) { + public void becameInactive(Consumer consumer, int partitionId) { try { inActiveQueue.put(partitionId); } catch (InterruptedException e) { @@ -115,13 +115,13 @@ private static class ActiveInactiveListenerEvent implements ConsumerEventListene private final Set inactivePtns = Sets.newHashSet(); @Override - public synchronized void becomeActive(Consumer consumer, int partitionId) { + public synchronized void becameActive(Consumer consumer, int partitionId) { activePtns.add(partitionId); inactivePtns.remove(partitionId); } @Override - public synchronized void becomeInactive(Consumer consumer, int partitionId) { + public synchronized void becameInactive(Consumer consumer, int partitionId) { activePtns.remove(partitionId); inactivePtns.add(partitionId); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java index 3dbe2ce0ad936..aeb8bbbb5dfff 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/api/ConsumerEventListener.java @@ -26,11 +26,11 @@ public interface ConsumerEventListener { /** * Notified when the consumer group is changed, and the consumer becomes the active consumer. */ - void becomeActive(Consumer consumer, int partitionId); + void becameActive(Consumer consumer, int partitionId); /** * Notified when the consumer group is changed, and the consumer is still inactive or becomes inactive. */ - void becomeInactive(Consumer consumer, int partitionId); + void becameInactive(Consumer consumer, int partitionId); } diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java index ea61bb20a7c27..219479f538599 100644 --- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java +++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerImpl.java @@ -754,9 +754,9 @@ void activeConsumerChanged(boolean isActive) { listenerExecutor.submit(() -> { if (isActive) { - consumerEventListener.becomeActive(this, partitionIndex); + consumerEventListener.becameActive(this, partitionIndex); } else { - consumerEventListener.becomeInactive(this, partitionIndex); + consumerEventListener.becameInactive(this, partitionIndex); } }); }