From d90bf1ac4ab05941d85a050af5524c71141b8fa4 Mon Sep 17 00:00:00 2001 From: Penghui Li Date: Thu, 15 Aug 2019 10:28:46 +0800 Subject: [PATCH 01/31] Introduce system topic --- conf/broker.conf | 8 + conf/standalone.conf | 7 + .../pulsar/broker/ServiceConfiguration.java | 10 ++ .../apache/pulsar/broker/PulsarService.java | 21 +++ .../broker/cache/TopicPoliciesCache.java | 42 ++++++ .../pulsar/broker/service/BrokerService.java | 14 +- .../apache/pulsar/broker/service/Topic.java | 4 + .../service/persistent/PersistentTopic.java | 25 +++- .../pulsar/broker/systopic/ActionType.java | 30 ++++ .../systopic/CachedSystemTopicService.java | 60 ++++++++ .../pulsar/broker/systopic/EventType.java | 30 ++++ .../NamespaceEventsSystemTopicFactory.java | 49 +++++++ .../NamespaceEventsSystemTopicService.java | 46 ++++++ .../pulsar/broker/systopic/PulsarEvent.java | 35 +++++ .../pulsar/broker/systopic/SystemTopic.java | 100 +++++++++++++ .../broker/systopic/SystemTopicBase.java | 87 +++++++++++ .../broker/systopic/SystemTopicFactory.java | 36 +++++ .../broker/systopic/SystemTopicService.java | 40 +++++ .../pulsar/broker/systopic/TopicEvent.java | 38 +++++ .../systopic/TopicPolicySystemTopic.java | 112 ++++++++++++++ ...NamespaceEventsSystemTopicServiceTest.java | 137 ++++++++++++++++++ .../pulsar/client/impl/KeySharedConsumer.java | 35 +++++ .../client/impl/KeySharedConsumer1.java | 35 +++++ .../client/impl/KeySharedConsumer2.java | 35 +++++ .../pulsar/client/impl/KeySharedProducer.java | 33 +++++ .../common/policies/data/TopicPolicies.java | 75 ++++++++++ 26 files changed, 1136 insertions(+), 8 deletions(-) create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java create mode 100644 pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java create mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java create mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java create mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java create mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java create mode 100644 pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java diff --git a/conf/broker.conf b/conf/broker.conf index 7594e1e4a8e37..d3d51cdbb96c3 100644 --- a/conf/broker.conf +++ b/conf/broker.conf @@ -337,6 +337,7 @@ replicatedSubscriptionsSnapshotTimeoutSeconds=30 # Max number of snapshot to be cached per subscription. replicatedSubscriptionsSnapshotMaxCachedPerSubscription=10 +<<<<<<< HEAD # Max memory size for broker handling messages sending from producers. # If the processing message size exceed this value, broker will stop read data # from the connection. The processing messages means messages are sends to broker @@ -357,6 +358,13 @@ retentionCheckIntervalInSeconds=120 # Use 0 or negative number to disable the check maxNumPartitionsPerPartitionedTopic=0 +# Enable or disable system topic +systemTopicEnable=true + +# Enable or disable topic level policies, topic level policies depends on the system topic +# Please enable the system topic first. +topicLevelPoliciesEnable=true + ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with #role as proxyRoles - it will demand to see a valid original principal. diff --git a/conf/standalone.conf b/conf/standalone.conf index c2a464c85f7fe..50dcf96bda6f4 100644 --- a/conf/standalone.conf +++ b/conf/standalone.conf @@ -221,6 +221,7 @@ maxConsumersPerTopic=0 # Using a value of 0, is disabling maxConsumersPerSubscription-limit check. maxConsumersPerSubscription=0 +<<<<<<< HEAD # Max number of partitions per partitioned topic # Use 0 or negative number to disable the check maxNumPartitionsPerPartitionedTopic=0 @@ -321,6 +322,12 @@ brokerClientTlsCiphers= # used by the internal client to authenticate with Pulsar brokers brokerClientTlsProtocols= +# Enable or disable system topic +systemTopicEnable=true + +# Enable topic level policies +topicLevelPoliciesEnable=true + ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with #role as proxyRoles - it will demand to see a valid original principal. diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java index 34163b489380a..a83a3ca49a09d 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java @@ -674,6 +674,16 @@ public class ServiceConfiguration implements PulsarConfiguration { ) private Set messagingProtocols = Sets.newTreeSet(); + @FieldContext( + category = CATEGORY_SERVER, + doc = "Enable or disable system topic.") + private boolean systemTopicEnable = true; + + @FieldContext( + category = CATEGORY_SERVER, + doc = "Enable topic level policies.") + private boolean topicLevelPoliciesEnable = true; + /***** --- TLS --- ****/ @FieldContext( category = CATEGORY_TLS, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index 21a73a0b6bdc2..2e867ad987459 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -75,6 +75,7 @@ import org.apache.pulsar.broker.authorization.AuthorizationService; import org.apache.pulsar.broker.cache.ConfigurationCacheService; import org.apache.pulsar.broker.cache.LocalZooKeeperCacheService; +import org.apache.pulsar.broker.cache.TopicPoliciesCache; import org.apache.pulsar.broker.loadbalance.LeaderElectionService; import org.apache.pulsar.broker.loadbalance.LeaderElectionService.LeaderListener; import org.apache.pulsar.broker.loadbalance.LoadManager; @@ -89,6 +90,7 @@ import org.apache.pulsar.broker.service.schema.SchemaRegistryService; import org.apache.pulsar.broker.stats.MetricsGenerator; import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsServlet; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; import org.apache.pulsar.broker.web.WebService; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminBuilder; @@ -190,6 +192,9 @@ public class PulsarService implements AutoCloseable { private ShutdownService shutdownService; + private NamespaceEventsSystemTopicService namespaceEventsSystemTopicService; + private TopicPoliciesCache topicPoliciesCache; + private MetricsGenerator metricsGenerator; private TransactionMetadataStoreService transactionMetadataStoreService; @@ -418,6 +423,14 @@ public void start() throws PulsarServerException { brokerService.start(); + if (config.isSystemTopicEnable()) { + namespaceEventsSystemTopicService = new NamespaceEventsSystemTopicService(getClient()); + } + + if (config.isTopicLevelPoliciesEnable()) { + topicPoliciesCache = new TopicPoliciesCache(); + } + this.webService = new WebService(this); Map attributeMap = Maps.newHashMap(); attributeMap.put(WebService.ATTRIBUTE_PULSAR_NAME, this); @@ -1122,6 +1135,14 @@ public static String bookieMetadataServiceUri(ServiceConfiguration config) { return metadataServiceUri; } + public NamespaceEventsSystemTopicService getNamespaceEventsSystemTopicService() { + return namespaceEventsSystemTopicService; + } + + public TopicPoliciesCache getTopicPoliciesCache() { + return topicPoliciesCache; + } + private void startWorkerService(AuthenticationService authenticationService, AuthorizationService authorizationService) throws InterruptedException, IOException, KeeperException { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java new file mode 100644 index 0000000000000..6190c6b0421da --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.cache; + +import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.policies.data.TopicPolicies; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Cache for topic policies + */ +public class TopicPoliciesCache { + + private final Map cache = new ConcurrentHashMap<>(); + + public TopicPolicies getTopicPolicies(TopicName topicName) { + return cache.get(topicName); + } + + public void updateTopicPolicies(TopicName topicName, TopicPolicies policies) { + cache.put(topicName, policies); + } + +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java index 490b6f8ba8598..189415914a0f8 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java @@ -103,11 +103,13 @@ import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.broker.stats.ClusterReplicationMetrics; import org.apache.pulsar.broker.stats.prometheus.metrics.Summary; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.web.PulsarWebResource; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect.EventListner; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminBuilder; + import org.apache.pulsar.client.api.ClientBuilder; import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; @@ -929,8 +931,9 @@ private void createPersistentTopic(final String topic, boolean createIfMissing, @Override public void openLedgerComplete(ManagedLedger ledger, Object ctx) { try { - PersistentTopic persistentTopic = new PersistentTopic(topic, ledger, - BrokerService.this); + PersistentTopic persistentTopic = isSystemTopic(topic) + ? new PersistentTopic(topic, ledger, BrokerService.this, true) + : new PersistentTopic(topic, ledger, BrokerService.this, false); CompletableFuture replicationFuture = persistentTopic.checkReplication(); replicationFuture.thenCompose(v -> { // Also check dedup status @@ -1257,6 +1260,9 @@ public BacklogQuotaManager getBacklogQuotaManager() { * @return determine if quota enforcement needs to be done for topic */ public boolean isBacklogExceeded(PersistentTopic topic) { + if (topic.isSystemTopic()) { + return false; + } TopicName topicName = TopicName.get(topic.getName()); long backlogQuotaLimitInBytes = getBacklogQuotaManager().getBacklogQuotaLimit(topicName.getNamespace()); if (backlogQuotaLimitInBytes < 0) { @@ -2115,7 +2121,6 @@ public Optional getListenPortTls() { return Optional.empty(); } } - private void checkMessagePublishBuffer() { AtomicLong currentMessagePublishBufferBytes = new AtomicLong(); foreachProducer(producer -> currentMessagePublishBufferBytes.addAndGet(producer.getCnx().getMessagePublishBufferSize())); @@ -2228,4 +2233,7 @@ private AutoSubscriptionCreationOverride getAutoSubscriptionCreationOverride(fin log.warn("No autoSubscriptionCreateOverride policy found for {}", topicName); return null; } + private boolean isSystemTopic(String topic) { + return NamespaceEventsSystemTopicFactory.LOCAL_TOPIC_NAME.equals(TopicName.get(topic).getLocalName()); + } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Topic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Topic.java index aa147d4798bb8..b2b1882ec2c24 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Topic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/Topic.java @@ -210,4 +210,8 @@ void updateRates(NamespaceStats nsStats, NamespaceBundleStats currentBundleStats default Optional getDispatchRateLimiter() { return Optional.empty(); } + + default boolean isSystemTopic() { + return false; + } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java index 25a4d30a8ed00..23b1aa2be52e4 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java @@ -167,6 +167,8 @@ public class PersistentTopic extends AbstractTopic implements Topic, AddEntryCal private CompletableFuture currentCompaction = CompletableFuture.completedFuture(COMPACTION_NEVER_RUN); private final CompactedTopic compactedTopic; + private final boolean isSystemTopic; + private CompletableFuture currentOffload = CompletableFuture.completedFuture( (MessageIdImpl)MessageId.earliest); @@ -210,9 +212,11 @@ public void reset() { } } - public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerService) throws NamingException { + public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerService, + boolean isSystemTopic) throws NamingException { super(topic, brokerService); this.ledger = ledger; + this.isSystemTopic = isSystemTopic; this.subscriptions = new ConcurrentOpenHashMap<>(16, 1); this.replicators = new ConcurrentOpenHashMap<>(16, 1); USAGE_COUNT_UPDATER.set(this, 0); @@ -231,7 +235,7 @@ public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerS boolean isReplicatorStarted = addReplicationCluster(remoteCluster, this, cursor.getName(), localCluster); if (!isReplicatorStarted) { throw new NamingException( - PersistentTopic.this.getName() + " Failed to start replicator " + remoteCluster); + PersistentTopic.this.getName() + " Failed to start replicator " + remoteCluster); } } else if (cursor.getName().equals(DEDUPLICATION_CURSOR_NAME)) { // This is not a regular subscription, we are going to ignore it for now and let the message dedup logic @@ -239,7 +243,7 @@ public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerS } else { final String subscriptionName = Codec.decode(cursor.getName()); subscriptions.put(subscriptionName, createPersistentSubscription(subscriptionName, cursor, - PersistentSubscription.isCursorFromReplicatedSubscription(cursor))); + PersistentSubscription.isCursorFromReplicatedSubscription(cursor))); // subscription-cursor gets activated by default: deactivate as there is no active subscription right // now subscriptions.get(subscriptionName).deactivateCursor(); @@ -267,7 +271,6 @@ public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerS checkReplicatedSubscriptionControllerState(); } - // for testing purposes @VisibleForTesting PersistentTopic(String topic, BrokerService brokerService, ManagedLedger ledger, MessageDeduplication messageDeduplication) { @@ -278,6 +281,7 @@ public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerS this.replicators = new ConcurrentOpenHashMap<>(16, 1); this.compactedTopic = new CompactedTopicImpl(brokerService.pulsar().getBookKeeperClient()); this.backloggedCursorThresholdEntries = brokerService.pulsar().getConfiguration().getManagedLedgerCursorBackloggedThreshold(); + this.isSystemTopic = false; } private void initializeDispatchRateLimiterIfNeeded(Optional policies) { @@ -1120,6 +1124,9 @@ public CompletableFuture checkReplication() { @Override public void checkMessageExpiry() { + if (isSystemTopic) { + return; + } TopicName name = TopicName.get(topic); Policies policies; try { @@ -1153,7 +1160,7 @@ public void checkCompaction() { .orElseThrow(() -> new KeeperException.NoNodeException()); - if (policies.compaction_threshold != 0 + if (isSystemTopic || policies.compaction_threshold != 0 && currentCompaction.isDone()) { long backlogEstimate = 0; @@ -1633,6 +1640,9 @@ private boolean hasBacklogs() { @Override public void checkGC(int maxInactiveDurationInSec, InactiveTopicDeleteMode deleteMode) { + if (isSystemTopic) { + return; + } if (isActive(deleteMode)) { lastActive = System.nanoTime(); } else if (System.nanoTime() - lastActive < TimeUnit.SECONDS.toNanos(maxInactiveDurationInSec)) { @@ -2135,4 +2145,9 @@ Optional getReplicatedSubscriptionController( public CompactedTopic getCompactedTopic() { return compactedTopic; } + + @Override + public boolean isSystemTopic() { + return isSystemTopic; + } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java new file mode 100644 index 0000000000000..e251e4a4e32e3 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +/** + * Pulsar event action type + */ +public enum ActionType { + + INSERT, + DELETE, + UPDATE, + NONE +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java new file mode 100644 index 0000000000000..3c809422b6a3b --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java @@ -0,0 +1,60 @@ +/** + * 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.broker.systopic; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Cached system topic topic framework. + * + * The cached system topic service can cache up system topics and maintain them by a map. + * + * While the system topic for key is exists, cached system topic will return + * the exists system topic instead of create a new system topic. + * + * While the system topic for key is not exists, cached system topic service will load + * a new system topic and cache up the system topic. + */ +public abstract class CachedSystemTopicService implements SystemTopicService { + + protected final SystemTopicFactory systemTopicFactory; + private final Map> caches; + + protected CachedSystemTopicService(SystemTopicFactory systemTopicFactory) { + this.systemTopicFactory = systemTopicFactory; + this.caches = new ConcurrentHashMap<>(); + this.caches.put(EventType.TOPIC_POLICY, new ConcurrentHashMap<>()); + } + + @Override + public SystemTopic getSystemTopic(String key, EventType eventType) { + return caches.get(eventType).computeIfAbsent(key, k -> loadSystemTopic(k, eventType)); + } + + @Override + public void destroySystemTopic(String key, EventType eventType) { + SystemTopic systemTopic = caches.get(eventType).remove(key); + if (systemTopic != null) { + systemTopic.close(); + } + } + + abstract SystemTopic loadSystemTopic(String key, EventType eventType); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java new file mode 100644 index 0000000000000..ab3c22985731f --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +/** + * Pulsar system event type + */ +public enum EventType { + + /** + * Topic policy events + */ + TOPIC_POLICY +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java new file mode 100644 index 0000000000000..819f8f3f650e3 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java @@ -0,0 +1,49 @@ +/** + * 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.broker.systopic; + +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.naming.TopicName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NamespaceEventsSystemTopicFactory implements SystemTopicFactory { + + public static final String LOCAL_TOPIC_NAME = "__change_events"; + private final PulsarClient client; + + public NamespaceEventsSystemTopicFactory(PulsarClient client) { + this.client = client; + } + + @Override + public SystemTopic createSystemTopic(String key, EventType eventType) { + switch (eventType) { + case TOPIC_POLICY: + TopicName topicName = TopicName.get("persistent", NamespaceName.get(key), LOCAL_TOPIC_NAME); + log.info("Create system topic {} for topic policy.", topicName.toString()); + return new TopicPolicySystemTopic(client, topicName); + default: + return null; + } + } + + private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicFactory.class); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java new file mode 100644 index 0000000000000..fd89b23ad6d14 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * System topic service for namespace events + */ +public class NamespaceEventsSystemTopicService extends CachedSystemTopicService { + + public NamespaceEventsSystemTopicService(PulsarClient client) { + super(new NamespaceEventsSystemTopicFactory(client)); + } + + @Override + SystemTopic loadSystemTopic(String key, EventType eventType) { + try { + return systemTopicFactory.createSystemTopic(key, eventType); + } catch (PulsarClientException e) { + log.error("Create system topic for key {} failed", e); + return null; + } + } + + private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicService.class); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java new file mode 100644 index 0000000000000..b5641139ab384 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class PulsarEvent { + + private EventType eventType; + private ActionType actionType; + private TopicEvent topicEvent; +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java new file mode 100644 index 0000000000000..60967a2cf74af --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java @@ -0,0 +1,100 @@ +/** + * 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.broker.systopic; + +import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.client.api.MessageId; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.TopicName; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +/** + * Pulsar system topic + */ +public interface SystemTopic { + + /** + * Get topic name of the system topic. + * @return topic name + */ + TopicName getTopicName(); + + /** + * Create a reader for the system topic. + * @return a new reader for the system topic + */ + Reader createReader() throws PulsarClientException; + + /** + * Get a writer for the system topic. + * @return writer for the system topic + */ + Writer getWriter() throws PulsarClientException; + + /** + * Close the system topic. + * + * Close system topic will close producer and consumer of the system topic + */ + void close(); + + /** + * Writer for system topic + */ + interface Writer { + /** + * Write event to the system topic + * @param event pulsar event + * @return message id + * @throws PulsarClientException exception while write event cause + */ + MessageId write(PulsarEvent event) throws PulsarClientException; + + /** + * Close the system topic writer. + */ + void close() throws IOException; + } + + /** + * Reader for system topic + */ + interface Reader { + + /** + * Read event from system topic + * @return pulsar event + */ + Message readNext() throws PulsarClientException; + + /** + * Async read event from system topic + * @return pulsar event future + */ + CompletableFuture> readNextAsync(); + + /** + * Close the system topic reader. + */ + void close() throws IOException; + } + +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java new file mode 100644 index 0000000000000..b40b2ab4b1f23 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java @@ -0,0 +1,87 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.TopicName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public abstract class SystemTopicBase implements SystemTopic { + + protected final TopicName topicName; + protected final PulsarClient client; + + protected Writer writer; + protected final List readers; + + public SystemTopicBase(PulsarClient client, TopicName topicName) { + this.client = client; + this.topicName = topicName; + this.readers = Collections.synchronizedList(new ArrayList<>()); + } + + @Override + public TopicName getTopicName() { + return topicName; + } + + protected abstract Writer createWriter() throws PulsarClientException; + + protected abstract Reader createReaderInternal() throws PulsarClientException; + + @Override + public Writer getWriter() throws PulsarClientException { + synchronized (this) { + if (writer == null) { + writer = createWriter(); + } + } + return writer; + } + + @Override + public Reader createReader() throws PulsarClientException { + Reader reader = createReaderInternal(); + readers.add(reader); + return reader; + } + + @Override + public void close() { + try { + if (writer != null) { + writer.close(); + } + for (Reader reader : readers) { + reader.close(); + } + } catch (IOException e) { + log.error("Close system topic [{}] error.", topicName.toString(), e); + } + } + + private static final Logger log = LoggerFactory.getLogger(SystemTopicBase.class); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java new file mode 100644 index 0000000000000..22f88e427f1cd --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.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.broker.systopic; + +import org.apache.pulsar.client.api.PulsarClientException; + +/** + * System topic factory + */ +public interface SystemTopicFactory { + + /** + * Create a new system topic + * @param key key of the system topic + * @param eventType event type + * @return system topic + * @throws PulsarClientException exception cause while create system topic + */ + SystemTopic createSystemTopic(String key, EventType eventType) throws PulsarClientException; +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java new file mode 100644 index 0000000000000..476e92348fd7a --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +/** + * System Topic Service + */ +public interface SystemTopicService { + + /** + * Get system topic by key. + * @param key key of the system topic + * @param eventType event type + * @return system topic or null while error cause + */ + SystemTopic getSystemTopic(String key, EventType eventType); + + /** + * Destroy the system topic for a key + * @param key key of the system topic + * @param eventType event type + */ + void destroySystemTopic(String key, EventType eventType); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java new file mode 100644 index 0000000000000..d71b2d0427217 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.systopic; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.pulsar.common.policies.data.TopicPolicies; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TopicEvent { + + private String domain; + private String tenant; + private String namespace; + private String topic; + private TopicPolicies policies; +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java new file mode 100644 index 0000000000000..da15310e00268 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java @@ -0,0 +1,112 @@ +/** + * 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.broker.systopic; + +import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.client.api.MessageId; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.common.naming.TopicName; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +/** + * System topic for topic policy + */ +public class TopicPolicySystemTopic extends SystemTopicBase { + + public TopicPolicySystemTopic(PulsarClient client, TopicName topicName) { + super(client, topicName); + } + + @Override + protected Writer createWriter() throws PulsarClientException { + Producer producer = client.newProducer(Schema.AVRO(PulsarEvent.class)) + .topic(topicName.toString()) + .create(); + return new TopicPolicyWriter(producer); + } + + @Override + protected Reader createReaderInternal() throws PulsarClientException { + org.apache.pulsar.client.api.Reader reader = client.newReader(Schema.AVRO(PulsarEvent.class)) + .topic(topicName.toString()) + .startMessageId(MessageId.earliest) + .readCompacted(true) + .create(); + return new TopicPolicyReader(reader, this); + } + + private static class TopicPolicyWriter implements Writer { + + private Producer producer; + + private TopicPolicyWriter(Producer producer) { + this.producer = producer; + } + + @Override + public MessageId write(PulsarEvent event) throws PulsarClientException { + return producer.newMessage().key(getEventKey(event)).value(event).send(); + } + + private String getEventKey(PulsarEvent event) { + return TopicName.get(event.getTopicEvent().getDomain(), + event.getTopicEvent().getTenant(), + event.getTopicEvent().getNamespace(), + event.getTopicEvent().getTopic()).toString(); + } + + @Override + public void close() throws IOException { + this.producer.close(); + } + } + + public static class TopicPolicyReader implements Reader { + + private org.apache.pulsar.client.api.Reader reader; + private final TopicPolicySystemTopic systemTopic; + + private TopicPolicyReader(org.apache.pulsar.client.api.Reader reader, + TopicPolicySystemTopic systemTopic) { + this.reader = reader; + this.systemTopic = systemTopic; + } + + @Override + public Message readNext() throws PulsarClientException { + return reader.readNext(); + } + + @Override + public CompletableFuture> readNextAsync() { + return reader.readNextAsync(); + } + + @Override + public void close() throws IOException { + systemTopic.readers.remove(this); + this.reader.close(); + } + } +} diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java new file mode 100644 index 0000000000000..42735ac9a7455 --- /dev/null +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java @@ -0,0 +1,137 @@ +/** + * 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.broker.system; + +import com.google.common.collect.Sets; +import org.apache.bookkeeper.common.util.JsonUtil.ParseJsonException; +import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; +import org.apache.pulsar.broker.systopic.ActionType; +import org.apache.pulsar.broker.systopic.EventType; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; +import org.apache.pulsar.broker.systopic.PulsarEvent; +import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicService; +import org.apache.pulsar.broker.systopic.TopicEvent; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.policies.data.ClusterData; +import org.apache.pulsar.common.policies.data.TenantInfo; +import org.apache.pulsar.common.policies.data.TopicPolicies; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBaseTest { + + private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicServiceTest.class); + + private static final String NAMESPACE1 = "system-topic/namespace-1"; + private static final String NAMESPACE2 = "system-topic/namespace-2"; + private static final String NAMESPACE3 = "system-topic/namespace-3"; + + private static final String LOCAL_TOPIC_NAME = "__change_events"; + + private SystemTopicService systemTopicService; + + @BeforeMethod + @Override + protected void setup() throws Exception { + super.internalSetup(); + prepareData(); + } + + @AfterMethod + @Override + protected void cleanup() throws Exception { + super.internalCleanup(); + } + + @Test + public void testGetSystemTopic() { + + SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + Assert.assertEquals(systemTopicForNamespace1.getTopicName().getNamespace(), NAMESPACE1); + Assert.assertEquals(systemTopicForNamespace1.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); + + SystemTopic systemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE2, EventType.TOPIC_POLICY); + Assert.assertEquals(systemTopicForNamespace2.getTopicName().getNamespace(), NAMESPACE2); + Assert.assertEquals(systemTopicForNamespace2.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); + + SystemTopic systemTopicForNamespace3 = systemTopicService.getSystemTopic(NAMESPACE3, EventType.TOPIC_POLICY); + Assert.assertEquals(systemTopicForNamespace3.getTopicName().getNamespace(), NAMESPACE3); + Assert.assertEquals(systemTopicForNamespace3.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); + + SystemTopic cachedSystemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + Assert.assertSame(cachedSystemTopicForNamespace1, systemTopicForNamespace1); + + SystemTopic cachedSystemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE2, EventType.TOPIC_POLICY); + Assert.assertSame(cachedSystemTopicForNamespace2, systemTopicForNamespace2); + + SystemTopic cachedSystemTopicForNamespace3 = systemTopicService.getSystemTopic(NAMESPACE3, EventType.TOPIC_POLICY); + Assert.assertSame(cachedSystemTopicForNamespace3, systemTopicForNamespace3); + } + + @Test + public void testDestroySystemTopic() { + SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + systemTopicService.destroySystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + SystemTopic systemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + Assert.assertNotSame(systemTopicForNamespace1, systemTopicForNamespace2); + systemTopicService.destroySystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + } + + @Test + public void testSendAndReceiveNamespaceEvents() throws PulsarClientException, ParseJsonException { + SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + TopicPolicies policies = TopicPolicies.builder() + .maxProducerPerTopic(10) + .build(); + PulsarEvent event = PulsarEvent.builder() + .eventType(EventType.TOPIC_POLICY) + .actionType(ActionType.INSERT) + .topicEvent(TopicEvent.builder() + .domain("persistent") + .tenant("system-topic") + .namespace(NamespaceName.get(NAMESPACE1).getLocalName()) + .topic("my-topic") + .policies(policies) + .build()) + .build(); + systemTopicForNamespace1.getWriter().write(event); + SystemTopic.Reader reader = systemTopicForNamespace1.createReader(); + Message received = reader.readNext(); + log.info("Receive pulsar event from system topic : {}", received.getValue()); + Assert.assertEquals(received.getValue(), event); + } + + private void prepareData() throws PulsarAdminException { + admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); + admin.tenants().createTenant("system-topic", + new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); + admin.namespaces().createNamespace(NAMESPACE1); + admin.namespaces().createNamespace(NAMESPACE2); + admin.namespaces().createNamespace(NAMESPACE3); + systemTopicService = new NamespaceEventsSystemTopicService(pulsarClient); + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java new file mode 100644 index 0000000000000..5129f71db8b77 --- /dev/null +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java @@ -0,0 +1,35 @@ +package org.apache.pulsar.client.impl; + +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionType; + +import java.util.concurrent.TimeUnit; + +public class KeySharedConsumer { + + public static void main(String[] args) throws PulsarClientException { + PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); + + for (int i = 0; i < 3000; i++) { + new Thread(() -> { + try { + Consumer consumer = client.newConsumer(Schema.STRING) + .topic("key_shared_latency-1") + .subscriptionType(SubscriptionType.Key_Shared) + .receiverQueueSize(1000) + .subscriptionName("test") + .subscribe(); + while (true) { + consumer.acknowledge(consumer.receive()); + } + } catch (PulsarClientException e) { + e.printStackTrace(); + } + }).start(); + } + + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java new file mode 100644 index 0000000000000..f965a971fa7d6 --- /dev/null +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java @@ -0,0 +1,35 @@ +package org.apache.pulsar.client.impl; + +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionType; + +import java.util.concurrent.TimeUnit; + +public class KeySharedConsumer1 { + + public static void main(String[] args) throws PulsarClientException { + PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); + + for (int i = 0; i < 2000; i++) { + new Thread(() -> { + try { + Consumer consumer = client.newConsumer(Schema.STRING) + .topic("key_shared_latency-1") + .subscriptionType(SubscriptionType.Key_Shared) + .receiverQueueSize(1000) + .subscriptionName("test") + .subscribe(); + while (true) { + consumer.acknowledge(consumer.receive()); + } + } catch (PulsarClientException e) { + e.printStackTrace(); + } + }).start(); + } + + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java new file mode 100644 index 0000000000000..edb6c63c812d8 --- /dev/null +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java @@ -0,0 +1,35 @@ +package org.apache.pulsar.client.impl; + +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionType; + +import java.util.concurrent.TimeUnit; + +public class KeySharedConsumer2 { + + public static void main(String[] args) throws PulsarClientException { + PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); + + for (int i = 0; i < 2000; i++) { + new Thread(() -> { + try { + Consumer consumer = client.newConsumer(Schema.STRING) + .topic("key_shared_latency-1") + .subscriptionType(SubscriptionType.Key_Shared) + .receiverQueueSize(1000) + .subscriptionName("test") + .subscribe(); + while (true) { + consumer.acknowledge(consumer.receive()); + } + } catch (PulsarClientException e) { + e.printStackTrace(); + } + }).start(); + } + + } +} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java new file mode 100644 index 0000000000000..7f737f9391f46 --- /dev/null +++ b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java @@ -0,0 +1,33 @@ +package org.apache.pulsar.client.impl; + +import org.apache.pulsar.client.api.BatcherBuilder; +import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.client.api.SubscriptionType; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class KeySharedProducer { + + public static void main(String[] args) throws PulsarClientException, InterruptedException { + PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); + Producer producer = client.newProducer(Schema.STRING) + .topic("key_shared_latency-1") + .enableBatching(false) + .batcherBuilder(BatcherBuilder.KEY_BASED) + .maxPendingMessages(5000) + .create(); + + int i = 0; + while (true) { + producer.newMessage().key(UUID.randomUUID().toString()).value("test").sendAsync(); + if (++i % 20 == 0) { +// Thread.sleep(1); + } + } + } +} diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java new file mode 100644 index 0000000000000..9b1e581230446 --- /dev/null +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.common.policies.data; + +import com.google.common.collect.Maps; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TopicPolicies { + + private Map backLogQuotaMap = Maps.newHashMap(); + private PersistencePolicies persistence = null; + private RetentionPolicies retention_policies = null; + private Boolean deduplicationEnabled = null; + private Integer messageTTLInSeconds = null; + private Integer maxProducerPerTopic = null; + private Integer maxConsumerPerTopic = null; + private Integer maxConsumersPerSubscription = null; + + public boolean isBacklogQuotaSet() { + return !backLogQuotaMap.isEmpty(); + } + + public boolean isPersistentPolicySet() { + return persistence != null; + } + + public boolean isRetentionSet() { + return retention_policies != null; + } + + public boolean isDeduplicationSet() { + return deduplicationEnabled != null; + } + + public boolean isMessageTTLSet() { + return messageTTLInSeconds != null; + } + + public boolean isMaxProducerPerTopicSet() { + return maxProducerPerTopic != null; + } + + public boolean isMaxConsumerPerTopicSet() { + return maxConsumerPerTopic != null; + } + + public boolean isMaxConsumersPerSubscription() { + return maxConsumersPerSubscription != null; + } +} From 3469750dee44df876f678bafb92599b079d855a3 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Fri, 16 Aug 2019 19:32:47 +0800 Subject: [PATCH 02/31] Add asynchronous method for system topic. --- .../broker/service/TopicPoliciesService.java | 97 +++++++++++++++++++ .../systopic/CachedSystemTopicService.java | 9 +- .../NamespaceEventsSystemTopicService.java | 12 +-- .../pulsar/broker/systopic/SystemTopic.java | 83 ++++++++++++++-- .../broker/systopic/SystemTopicBase.java | 86 ++++++++++------ .../broker/systopic/SystemTopicFactory.java | 5 +- .../broker/systopic/SystemTopicService.java | 6 -- .../systopic/TopicPolicySystemTopic.java | 87 +++++++++++++---- ...NamespaceEventsSystemTopicServiceTest.java | 36 +++++-- 9 files changed, 342 insertions(+), 79 deletions(-) create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java new file mode 100644 index 0000000000000..842d8c3dd3e9d --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.service; + +import org.apache.pulsar.broker.PulsarServerException; +import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.broker.cache.TopicPoliciesCache; +import org.apache.pulsar.broker.systopic.EventType; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; +import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.TopicEvent; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.policies.data.TopicPolicies; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Topic policies service + */ +public class TopicPoliciesService { + + private final PulsarService pulsarService; + private final TopicPoliciesCache topicPoliciesCache; + private NamespaceEventsSystemTopicService namespaceEventsSystemTopicService; + private Map readers; + + public TopicPoliciesService(PulsarService pulsarService, TopicPoliciesCache topicPoliciesCache) { + this.pulsarService = pulsarService; + this.topicPoliciesCache = topicPoliciesCache; + this.readers = new ConcurrentHashMap<>(); + } + + public TopicPolicies getTopicPolicies(TopicName topicName) { + return topicPoliciesCache.getTopicPolicies(topicName); + } + + public void namespaceOwned(NamespaceName namespaceName) { + try { + synchronized (this) { + if (namespaceEventsSystemTopicService == null) { + namespaceEventsSystemTopicService = new NamespaceEventsSystemTopicService(pulsarService.getClient()); + } + if (readers.containsKey(namespaceName)) { + return; + } + } + SystemTopic systemTopic = namespaceEventsSystemTopicService.getTopicPoliciesSystemTopic(namespaceName); + if (systemTopic != null) { + SystemTopic.Reader reader = systemTopic.newReader(); + readers.put(namespaceName, reader); + processEvents(reader); + } + } catch (PulsarServerException e) { + e.printStackTrace(); + } catch (PulsarClientException e) { + e.printStackTrace(); + } + } + + void processEvents(SystemTopic.Reader reader) { + reader.readNextAsync().thenAccept(event -> { + if (EventType.TOPIC_POLICY.equals(event.getValue().getEventType())) { + TopicEvent topicEvent = event.getValue().getTopicEvent(); + TopicName topicName = TopicName.get(topicEvent.getDomain(), topicEvent.getTenant(), + topicEvent.getNamespace(), topicEvent.getTopic()); + topicPoliciesCache.updateTopicPolicies(topicName, topicEvent.getPolicies()); + } + processEvents(reader); + }).exceptionally(ex -> { + processEvents(reader); + return null; + }); + } + + private static final Logger log = LoggerFactory.getLogger(TopicPoliciesService.class); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java index 3c809422b6a3b..fda9c9b202a25 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java @@ -48,11 +48,10 @@ public SystemTopic getSystemTopic(String key, EventType eventType) { return caches.get(eventType).computeIfAbsent(key, k -> loadSystemTopic(k, eventType)); } - @Override - public void destroySystemTopic(String key, EventType eventType) { - SystemTopic systemTopic = caches.get(eventType).remove(key); - if (systemTopic != null) { - systemTopic.close(); + public void invalidate(String key, EventType eventType) { + SystemTopic toInvalidate = caches.get(eventType).remove(key); + if (toInvalidate != null) { + toInvalidate.closeAsync(); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java index fd89b23ad6d14..c8508750d1d56 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java @@ -20,6 +20,7 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.NamespaceName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,12 +35,11 @@ public NamespaceEventsSystemTopicService(PulsarClient client) { @Override SystemTopic loadSystemTopic(String key, EventType eventType) { - try { - return systemTopicFactory.createSystemTopic(key, eventType); - } catch (PulsarClientException e) { - log.error("Create system topic for key {} failed", e); - return null; - } + return systemTopicFactory.createSystemTopic(key, eventType); + } + + public SystemTopic getTopicPoliciesSystemTopic(NamespaceName namespaceName) { + return getSystemTopic(namespaceName.toString(), EventType.TOPIC_POLICY); } private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicService.class); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java index 60967a2cf74af..c73c8e6f5dd2f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java @@ -24,6 +24,7 @@ import org.apache.pulsar.common.naming.TopicName; import java.io.IOException; +import java.util.List; import java.util.concurrent.CompletableFuture; /** @@ -41,20 +42,46 @@ public interface SystemTopic { * Create a reader for the system topic. * @return a new reader for the system topic */ - Reader createReader() throws PulsarClientException; + Reader newReader() throws PulsarClientException; /** - * Get a writer for the system topic. + * Create a reader for the system topic asynchronously. + */ + CompletableFuture newReaderAsync(); + + /** + * Create a writer for the system topic. * @return writer for the system topic */ - Writer getWriter() throws PulsarClientException; + Writer newWriter() throws PulsarClientException; + + /** + * Create a writer for the system topic asynchronously. + */ + CompletableFuture newWriterAsync(); /** - * Close the system topic. - * - * Close system topic will close producer and consumer of the system topic + * Close the system topic */ - void close(); + void close() throws Exception; + + /** + * Close the system topic asynchronously. + * @return + */ + CompletableFuture closeAsync(); + + /** + * Get all writers of the system topic + * @return writer list + */ + List getWriters(); + + /** + * Get all readers of the system topic + * @return reader list + */ + List getReaders(); /** * Writer for system topic @@ -68,10 +95,29 @@ interface Writer { */ MessageId write(PulsarEvent event) throws PulsarClientException; + /** + * Async write event to the system topic + * @param event pulsar event + * @return message id future + */ + CompletableFuture writeAsync(PulsarEvent event); + /** * Close the system topic writer. */ void close() throws IOException; + + /** + * Close the writer of the system topic asynchronously. + */ + CompletableFuture closeAsync(); + + /** + * Get the system topic of the writer + * @return system topic + */ + SystemTopic getSystemTopic(); + } /** @@ -91,10 +137,33 @@ interface Reader { */ CompletableFuture> readNextAsync(); + /** + * Check has more events available for the reader. + * @return true if has remaining events, otherwise false + */ + boolean hasMoreEvents() throws PulsarClientException; + + /** + * Check has more events available for the reader asynchronously. + * @return true if has remaining events, otherwise false + */ + CompletableFuture hasMoreEventsAsync(); + /** * Close the system topic reader. */ void close() throws IOException; + + /** + * Close the reader of the system topic asynchronously. + */ + CompletableFuture closeAsync(); + + /** + * Get the system topic of the reader + * @return system topic + */ + SystemTopic getSystemTopic(); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java index b40b2ab4b1f23..aed17b9d94219 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java @@ -21,66 +21,96 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.util.FutureUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.CompletableFuture; public abstract class SystemTopicBase implements SystemTopic { protected final TopicName topicName; protected final PulsarClient client; - protected Writer writer; + protected final List writers; protected final List readers; public SystemTopicBase(PulsarClient client, TopicName topicName) { this.client = client; this.topicName = topicName; + this.writers = Collections.synchronizedList(new ArrayList<>()); this.readers = Collections.synchronizedList(new ArrayList<>()); } @Override - public TopicName getTopicName() { - return topicName; + public Reader newReader() throws PulsarClientException { + try { + return newReaderAsync().get(); + } catch (Exception e) { + throw new PulsarClientException(e); + } } - protected abstract Writer createWriter() throws PulsarClientException; - - protected abstract Reader createReaderInternal() throws PulsarClientException; + @Override + public CompletableFuture newReaderAsync() { + return newReaderAsyncInternal().thenCompose(reader -> { + readers.add(reader); + return CompletableFuture.completedFuture(reader); + }); + } @Override - public Writer getWriter() throws PulsarClientException { - synchronized (this) { - if (writer == null) { - writer = createWriter(); - } + public Writer newWriter() throws PulsarClientException { + try { + return newWriterAsync().get(); + } catch (Exception e) { + throw new PulsarClientException(e); } - return writer; } @Override - public Reader createReader() throws PulsarClientException { - Reader reader = createReaderInternal(); - readers.add(reader); - return reader; + public CompletableFuture newWriterAsync() { + return newWriterAsyncInternal().thenCompose(writer -> { + writers.add(writer); + return CompletableFuture.completedFuture(writer); + }); } + protected abstract CompletableFuture newWriterAsyncInternal(); + + protected abstract CompletableFuture newReaderAsyncInternal(); + @Override - public void close() { - try { - if (writer != null) { - writer.close(); - } - for (Reader reader : readers) { - reader.close(); - } - } catch (IOException e) { - log.error("Close system topic [{}] error.", topicName.toString(), e); - } + public CompletableFuture closeAsync() { + List> futures = new ArrayList<>(); + writers.forEach(writer -> futures.add(writer.closeAsync())); + readers.forEach(reader -> futures.add(reader.closeAsync())); + writers.clear(); + readers.clear(); + return FutureUtil.waitForAll(futures); + } + + @Override + public void close() throws Exception { + closeAsync().get(); + } + + @Override + public TopicName getTopicName() { + return topicName; + } + + @Override + public List getReaders() { + return readers; + } + + @Override + public List getWriters() { + return writers; } private static final Logger log = LoggerFactory.getLogger(SystemTopicBase.class); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java index 22f88e427f1cd..3f87822bbe87c 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java @@ -18,8 +18,6 @@ */ package org.apache.pulsar.broker.systopic; -import org.apache.pulsar.client.api.PulsarClientException; - /** * System topic factory */ @@ -30,7 +28,6 @@ public interface SystemTopicFactory { * @param key key of the system topic * @param eventType event type * @return system topic - * @throws PulsarClientException exception cause while create system topic */ - SystemTopic createSystemTopic(String key, EventType eventType) throws PulsarClientException; + SystemTopic createSystemTopic(String key, EventType eventType); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java index 476e92348fd7a..93a7a219657a3 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java @@ -31,10 +31,4 @@ public interface SystemTopicService { */ SystemTopic getSystemTopic(String key, EventType eventType); - /** - * Destroy the system topic for a key - * @param key key of the system topic - * @param eventType event type - */ - void destroySystemTopic(String key, EventType eventType); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java index da15310e00268..119459f09a1c1 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java @@ -25,6 +25,8 @@ import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.common.naming.TopicName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.concurrent.CompletableFuture; @@ -39,29 +41,39 @@ public TopicPolicySystemTopic(PulsarClient client, TopicName topicName) { } @Override - protected Writer createWriter() throws PulsarClientException { - Producer producer = client.newProducer(Schema.AVRO(PulsarEvent.class)) - .topic(topicName.toString()) - .create(); - return new TopicPolicyWriter(producer); + protected CompletableFuture newWriterAsyncInternal() { + return client.newProducer(Schema.AVRO(PulsarEvent.class)) + .topic(topicName.toString()) + .createAsync().thenCompose(producer -> { + if (log.isDebugEnabled()) { + log.debug("[{}] A new writer is created", topicName); + } + return CompletableFuture.completedFuture(new TopicPolicyWriter(producer, TopicPolicySystemTopic.this)); + }); } @Override - protected Reader createReaderInternal() throws PulsarClientException { - org.apache.pulsar.client.api.Reader reader = client.newReader(Schema.AVRO(PulsarEvent.class)) - .topic(topicName.toString()) - .startMessageId(MessageId.earliest) - .readCompacted(true) - .create(); - return new TopicPolicyReader(reader, this); + protected CompletableFuture newReaderAsyncInternal() { + return client.newReader(Schema.AVRO(PulsarEvent.class)) + .topic(topicName.toString()) + .startMessageId(MessageId.earliest) + .readCompacted(true).createAsync() + .thenCompose(reader -> { + if (log.isDebugEnabled()) { + log.debug("[{}] A new reader is created", topicName); + } + return CompletableFuture.completedFuture(new TopicPolicyReader(reader, TopicPolicySystemTopic.this)); + }); } private static class TopicPolicyWriter implements Writer { - private Producer producer; + private final Producer producer; + private final SystemTopic systemTopic; - private TopicPolicyWriter(Producer producer) { + private TopicPolicyWriter(Producer producer, SystemTopic systemTopic) { this.producer = producer; + this.systemTopic = systemTopic; } @Override @@ -69,6 +81,11 @@ public MessageId write(PulsarEvent event) throws PulsarClientException { return producer.newMessage().key(getEventKey(event)).value(event).send(); } + @Override + public CompletableFuture writeAsync(PulsarEvent event) { + return producer.newMessage().key(getEventKey(event)).value(event).sendAsync(); + } + private String getEventKey(PulsarEvent event) { return TopicName.get(event.getTopicEvent().getDomain(), event.getTopicEvent().getTenant(), @@ -79,12 +96,23 @@ private String getEventKey(PulsarEvent event) { @Override public void close() throws IOException { this.producer.close(); + systemTopic.getWriters().remove(TopicPolicyWriter.this); + } + + @Override + public CompletableFuture closeAsync() { + return producer.closeAsync(); + } + + @Override + public SystemTopic getSystemTopic() { + return systemTopic; } } - public static class TopicPolicyReader implements Reader { + private static class TopicPolicyReader implements Reader { - private org.apache.pulsar.client.api.Reader reader; + private final org.apache.pulsar.client.api.Reader reader; private final TopicPolicySystemTopic systemTopic; private TopicPolicyReader(org.apache.pulsar.client.api.Reader reader, @@ -103,10 +131,35 @@ public CompletableFuture> readNextAsync() { return reader.readNextAsync(); } + @Override + public boolean hasMoreEvents() throws PulsarClientException { + return reader.hasMessageAvailable(); + } + + @Override + public CompletableFuture hasMoreEventsAsync() { + return reader.hasMessageAvailableAsync(); + } + @Override public void close() throws IOException { - systemTopic.readers.remove(this); this.reader.close(); + systemTopic.getReaders().remove(TopicPolicyReader.this); + } + + @Override + public CompletableFuture closeAsync() { + return reader.closeAsync().thenCompose(v -> { + systemTopic.getReaders().remove(TopicPolicyReader.this); + return CompletableFuture.completedFuture(null); + }); + } + + @Override + public SystemTopic getSystemTopic() { + return systemTopic; } } + + private static final Logger log = LoggerFactory.getLogger(TopicPolicySystemTopic.class); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java index 42735ac9a7455..db16e443b0fcf 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java @@ -42,6 +42,8 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; + public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBaseTest { private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicServiceTest.class); @@ -52,7 +54,7 @@ public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBa private static final String LOCAL_TOPIC_NAME = "__change_events"; - private SystemTopicService systemTopicService; + private NamespaceEventsSystemTopicService systemTopicService; @BeforeMethod @Override @@ -95,14 +97,14 @@ public void testGetSystemTopic() { @Test public void testDestroySystemTopic() { SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); - systemTopicService.destroySystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + systemTopicService.invalidate(NAMESPACE1, EventType.TOPIC_POLICY); SystemTopic systemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); Assert.assertNotSame(systemTopicForNamespace1, systemTopicForNamespace2); - systemTopicService.destroySystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + systemTopicService.invalidate(NAMESPACE1, EventType.TOPIC_POLICY); } @Test - public void testSendAndReceiveNamespaceEvents() throws PulsarClientException, ParseJsonException { + public void testSendAndReceiveNamespaceEvents() throws Exception { SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); TopicPolicies policies = TopicPolicies.builder() .maxProducerPerTopic(10) @@ -118,11 +120,33 @@ public void testSendAndReceiveNamespaceEvents() throws PulsarClientException, Pa .policies(policies) .build()) .build(); - systemTopicForNamespace1.getWriter().write(event); - SystemTopic.Reader reader = systemTopicForNamespace1.createReader(); + systemTopicForNamespace1.newWriter().write(event); + SystemTopic.Reader reader = systemTopicForNamespace1.newReader(); Message received = reader.readNext(); log.info("Receive pulsar event from system topic : {}", received.getValue()); + + // test event send and receive Assert.assertEquals(received.getValue(), event); + Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 1); + Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 1); + + // test new reader read + SystemTopic.Reader reader1 = systemTopicForNamespace1.newReader(); + Message received1 = reader1.readNext(); + log.info("Receive pulsar event from system topic : {}", received1.getValue()); + Assert.assertEquals(received1.getValue(), event); + + // test writers and readers + Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 2); + SystemTopic.Writer writer = systemTopicForNamespace1.newWriter(); + Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 2); + writer.close(); + reader.close(); + Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 1); + Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 1); + systemTopicForNamespace1.close(); + Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 0); + Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 0); } private void prepareData() throws PulsarAdminException { From d1b4ef732060b51d0f65425eac5afb9ffd374e50 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 20 Aug 2019 15:05:52 +0800 Subject: [PATCH 03/31] Add Topic Policies Service. --- .../apache/pulsar/broker/PulsarService.java | 24 +- .../broker/cache/TopicPoliciesCache.java | 42 ---- .../broker/service/TopicPoliciesService.java | 211 ++++++++++++++---- .../systopic/CachedSystemTopicService.java | 59 ----- .../NamespaceEventsSystemTopicFactory.java | 7 +- .../NamespaceEventsSystemTopicService.java | 46 ---- .../broker/systopic/SystemTopicFactory.java | 33 --- .../broker/systopic/SystemTopicService.java | 34 --- .../service/TopicPoliciesServiceTest.java | 167 ++++++++++++++ ...NamespaceEventsSystemTopicServiceTest.java | 53 +---- 10 files changed, 354 insertions(+), 322 deletions(-) delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java create mode 100644 pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java rename pulsar-broker/src/test/java/org/apache/pulsar/broker/{system => systopic}/NamespaceEventsSystemTopicServiceTest.java (61%) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index 2e867ad987459..c2408a4958d86 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -75,7 +75,6 @@ import org.apache.pulsar.broker.authorization.AuthorizationService; import org.apache.pulsar.broker.cache.ConfigurationCacheService; import org.apache.pulsar.broker.cache.LocalZooKeeperCacheService; -import org.apache.pulsar.broker.cache.TopicPoliciesCache; import org.apache.pulsar.broker.loadbalance.LeaderElectionService; import org.apache.pulsar.broker.loadbalance.LeaderElectionService.LeaderListener; import org.apache.pulsar.broker.loadbalance.LoadManager; @@ -87,10 +86,10 @@ import org.apache.pulsar.broker.protocol.ProtocolHandlers; import org.apache.pulsar.broker.service.BrokerService; import org.apache.pulsar.broker.service.Topic; +import org.apache.pulsar.broker.service.TopicPoliciesService; import org.apache.pulsar.broker.service.schema.SchemaRegistryService; import org.apache.pulsar.broker.stats.MetricsGenerator; import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsServlet; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; import org.apache.pulsar.broker.web.WebService; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminBuilder; @@ -154,6 +153,7 @@ public class PulsarService implements AutoCloseable { private WebSocketService webSocketService = null; private ConfigurationCacheService configurationCacheService = null; private LocalZooKeeperCacheService localZkCacheService = null; + private TopicPoliciesService topicPoliciesService = null; private BookKeeperClientFactory bkClientFactory; private ZooKeeperCache localZkCache; private GlobalZooKeeperCache globalZkCache; @@ -192,9 +192,6 @@ public class PulsarService implements AutoCloseable { private ShutdownService shutdownService; - private NamespaceEventsSystemTopicService namespaceEventsSystemTopicService; - private TopicPoliciesCache topicPoliciesCache; - private MetricsGenerator metricsGenerator; private TransactionMetadataStoreService transactionMetadataStoreService; @@ -423,13 +420,12 @@ public void start() throws PulsarServerException { brokerService.start(); - if (config.isSystemTopicEnable()) { - namespaceEventsSystemTopicService = new NamespaceEventsSystemTopicService(getClient()); + // Start topic level policies service + if (config.isTopicLevelPoliciesEnable() && config.isSystemTopicEnable()) { + this.topicPoliciesService = new TopicPoliciesService(this); } - if (config.isTopicLevelPoliciesEnable()) { - topicPoliciesCache = new TopicPoliciesCache(); - } + brokerService.start(); this.webService = new WebService(this); Map attributeMap = Maps.newHashMap(); @@ -1135,12 +1131,8 @@ public static String bookieMetadataServiceUri(ServiceConfiguration config) { return metadataServiceUri; } - public NamespaceEventsSystemTopicService getNamespaceEventsSystemTopicService() { - return namespaceEventsSystemTopicService; - } - - public TopicPoliciesCache getTopicPoliciesCache() { - return topicPoliciesCache; + public TopicPoliciesService getTopicPoliciesService() { + return topicPoliciesService; } private void startWorkerService(AuthenticationService authenticationService, diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java deleted file mode 100644 index 6190c6b0421da..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/cache/TopicPoliciesCache.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * 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.broker.cache; - -import org.apache.pulsar.common.naming.TopicName; -import org.apache.pulsar.common.policies.data.TopicPolicies; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Cache for topic policies - */ -public class TopicPoliciesCache { - - private final Map cache = new ConcurrentHashMap<>(); - - public TopicPolicies getTopicPolicies(TopicName topicName) { - return cache.get(topicName); - } - - public void updateTopicPolicies(TopicName topicName, TopicPolicies policies) { - cache.put(topicName, policies); - } - -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 842d8c3dd3e9d..3cb6fa115578d 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -18,22 +18,29 @@ */ package org.apache.pulsar.broker.service; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.cache.RemovalListener; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; -import org.apache.pulsar.broker.cache.TopicPoliciesCache; import org.apache.pulsar.broker.systopic.EventType; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.broker.systopic.TopicEvent; -import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * Topic policies service @@ -41,57 +48,183 @@ public class TopicPoliciesService { private final PulsarService pulsarService; - private final TopicPoliciesCache topicPoliciesCache; - private NamespaceEventsSystemTopicService namespaceEventsSystemTopicService; - private Map readers; + private NamespaceEventsSystemTopicFactory namespaceEventsSystemTopicFactory; - public TopicPoliciesService(PulsarService pulsarService, TopicPoliciesCache topicPoliciesCache) { - this.pulsarService = pulsarService; - this.topicPoliciesCache = topicPoliciesCache; - this.readers = new ConcurrentHashMap<>(); + private final Map policiesCache = new ConcurrentHashMap<>(); + + private final LoadingCache> readerCache; + + public TopicPoliciesService(PulsarService pulsarService) { + this(pulsarService, 1000, 10, TimeUnit.MINUTES); } - public TopicPolicies getTopicPolicies(TopicName topicName) { - return topicPoliciesCache.getTopicPolicies(topicName); + public TopicPoliciesService(PulsarService pulsarService, long cacheSize, long cacheExpireDuration, TimeUnit cacheExpireUnit) { + this.pulsarService = pulsarService; + this.readerCache = CacheBuilder.newBuilder() + .maximumSize(cacheSize) + .expireAfterAccess(cacheExpireDuration, cacheExpireUnit) + .removalListener((RemovalListener>) notification -> { + NamespaceName namespaceName = notification.getKey(); + if (log.isDebugEnabled()) { + log.debug("Reader cache was evicted for namespace {}, current reader cache size is {} ", namespaceName, + TopicPoliciesService.this.readerCache.asMap().size()); + } + policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespaceName)); + if (log.isDebugEnabled()) { + log.debug("Topic policies cache deleted success, current policies cache size is {} ", policiesCache.size()); + } + notification.getValue().whenComplete((reader, ex) -> { + if (ex == null && reader != null) { + reader.closeAsync().whenComplete((v, e) -> { + if (e != null) { + log.error("Close system topic reader error for reader cache expire", e); + } else { + if (log.isDebugEnabled()) { + log.debug("Reader for system topic {} is closed.", reader.getSystemTopic().getTopicName()); + } + } + }); + } else { + TopicPoliciesService.this.readerCache.asMap().remove(namespaceName, notification.getValue()); + } + }); + }) + .build(new CacheLoader>() { + @Override + public CompletableFuture load(NamespaceName namespaceName) { + CompletableFuture readerFuture = loadSystemTopicReader(namespaceName); + readerFuture.whenComplete((r, cause) -> { + if (null != cause || r == null) { + readerCache.asMap().remove(namespaceName, readerFuture); + } + }); + return readerFuture; + } + }); } - public void namespaceOwned(NamespaceName namespaceName) { + public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { + CompletableFuture readerFuture = null; try { + readerFuture = readerCache.get(topicName.getNamespaceObject()); + } catch (ExecutionException e) { + log.error("Load reader for system topic {} error.", topicName, e); + } + if (readerFuture == null) { + return CompletableFuture.completedFuture(null); + } + CompletableFuture result = new CompletableFuture<>(); + CompletableFuture refreshFuture = new CompletableFuture<>(); + refreshFuture.whenComplete((v, ex) -> result.complete(policiesCache.get(topicName))); + readerFuture.thenAccept(reader -> refreshCacheIfNeeded(reader, refreshFuture)); + return result; + } + + public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { + CompletableFuture result = new CompletableFuture<>(); + createSystemTopicFactoryIfNeeded(); + if (namespaceEventsSystemTopicFactory == null) { + result.complete(null); + return result; + } + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject() + , EventType.TOPIC_POLICY); + systemTopic.newReaderAsync().thenAccept(r -> + fetchTopicPoliciesAsyncAndCloseReader(r, topicName, null, result)); + return result; + } + + private CompletableFuture loadSystemTopicReader(NamespaceName namespaceName) { + createSystemTopicFactoryIfNeeded(); + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespaceName + , EventType.TOPIC_POLICY); + return systemTopic.newReaderAsync(); + } + + private void createSystemTopicFactoryIfNeeded() { + if (namespaceEventsSystemTopicFactory == null) { synchronized (this) { - if (namespaceEventsSystemTopicService == null) { - namespaceEventsSystemTopicService = new NamespaceEventsSystemTopicService(pulsarService.getClient()); + if (namespaceEventsSystemTopicFactory == null) { + try { + namespaceEventsSystemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarService.getClient()); + } catch (PulsarServerException e) { + log.error("Create namespace event system topic factory error.", e); + } } - if (readers.containsKey(namespaceName)) { - return; - } - } - SystemTopic systemTopic = namespaceEventsSystemTopicService.getTopicPoliciesSystemTopic(namespaceName); - if (systemTopic != null) { - SystemTopic.Reader reader = systemTopic.newReader(); - readers.put(namespaceName, reader); - processEvents(reader); } - } catch (PulsarServerException e) { - e.printStackTrace(); - } catch (PulsarClientException e) { - e.printStackTrace(); } } - void processEvents(SystemTopic.Reader reader) { - reader.readNextAsync().thenAccept(event -> { - if (EventType.TOPIC_POLICY.equals(event.getValue().getEventType())) { - TopicEvent topicEvent = event.getValue().getTopicEvent(); - TopicName topicName = TopicName.get(topicEvent.getDomain(), topicEvent.getTenant(), - topicEvent.getNamespace(), topicEvent.getTopic()); - topicPoliciesCache.updateTopicPolicies(topicName, topicEvent.getPolicies()); + private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture refreshFuture) { + reader.hasMoreEventsAsync().whenComplete((has, ex) -> { + if (ex != null) { + refreshFuture.completeExceptionally(ex); + } + if (has) { + reader.readNextAsync().whenComplete((msg, e) -> { + if (e != null) { + refreshFuture.completeExceptionally(e); + } + if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { + TopicEvent event = msg.getValue().getTopicEvent(); + policiesCache.put( + TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), + event.getPolicies() + ); + } + refreshCacheIfNeeded(reader, refreshFuture); + }); + } else { + refreshFuture.complete(null); + } + }); + } + + private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, TopicName topicName, TopicPolicies policies, + CompletableFuture future) { + reader.hasMoreEventsAsync().whenComplete((has, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } + if (has) { + reader.readNextAsync().whenComplete((msg, e) -> { + if (e != null) { + future.completeExceptionally(e); + } + if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { + TopicEvent topicEvent = msg.getValue().getTopicEvent(); + if (topicName.equals(TopicName.get( + topicEvent.getDomain(), + topicEvent.getTenant(), + topicEvent.getNamespace(), + topicEvent.getTopic())) + ) { + fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, topicEvent.getPolicies(), future); + } else { + fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, policies, future); + } + } + }); + } else { + future.complete(policies); + reader.closeAsync().whenComplete((v, e) -> { + if (e != null) { + log.error("Close reader for system topic {} error.", topicName, e); + } + }); } - processEvents(reader); - }).exceptionally(ex -> { - processEvents(reader); - return null; }); } + @VisibleForTesting + long getPoliciesCacheSize() { + return policiesCache.size(); + } + + @VisibleForTesting + long getReaderCacheCount() { + return readerCache.size(); + } + private static final Logger log = LoggerFactory.getLogger(TopicPoliciesService.class); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java deleted file mode 100644 index fda9c9b202a25..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/CachedSystemTopicService.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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.broker.systopic; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Cached system topic topic framework. - * - * The cached system topic service can cache up system topics and maintain them by a map. - * - * While the system topic for key is exists, cached system topic will return - * the exists system topic instead of create a new system topic. - * - * While the system topic for key is not exists, cached system topic service will load - * a new system topic and cache up the system topic. - */ -public abstract class CachedSystemTopicService implements SystemTopicService { - - protected final SystemTopicFactory systemTopicFactory; - private final Map> caches; - - protected CachedSystemTopicService(SystemTopicFactory systemTopicFactory) { - this.systemTopicFactory = systemTopicFactory; - this.caches = new ConcurrentHashMap<>(); - this.caches.put(EventType.TOPIC_POLICY, new ConcurrentHashMap<>()); - } - - @Override - public SystemTopic getSystemTopic(String key, EventType eventType) { - return caches.get(eventType).computeIfAbsent(key, k -> loadSystemTopic(k, eventType)); - } - - public void invalidate(String key, EventType eventType) { - SystemTopic toInvalidate = caches.get(eventType).remove(key); - if (toInvalidate != null) { - toInvalidate.closeAsync(); - } - } - - abstract SystemTopic loadSystemTopic(String key, EventType eventType); -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java index 819f8f3f650e3..96ad52bde2e22 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class NamespaceEventsSystemTopicFactory implements SystemTopicFactory { +public class NamespaceEventsSystemTopicFactory { public static final String LOCAL_TOPIC_NAME = "__change_events"; private final PulsarClient client; @@ -33,11 +33,10 @@ public NamespaceEventsSystemTopicFactory(PulsarClient client) { this.client = client; } - @Override - public SystemTopic createSystemTopic(String key, EventType eventType) { + public SystemTopic createSystemTopic(NamespaceName namespaceName, EventType eventType) { switch (eventType) { case TOPIC_POLICY: - TopicName topicName = TopicName.get("persistent", NamespaceName.get(key), LOCAL_TOPIC_NAME); + TopicName topicName = TopicName.get("persistent", namespaceName, LOCAL_TOPIC_NAME); log.info("Create system topic {} for topic policy.", topicName.toString()); return new TopicPolicySystemTopic(client, topicName); default: diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java deleted file mode 100644 index c8508750d1d56..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicService.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * 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.broker.systopic; - -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.common.naming.NamespaceName; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * System topic service for namespace events - */ -public class NamespaceEventsSystemTopicService extends CachedSystemTopicService { - - public NamespaceEventsSystemTopicService(PulsarClient client) { - super(new NamespaceEventsSystemTopicFactory(client)); - } - - @Override - SystemTopic loadSystemTopic(String key, EventType eventType) { - return systemTopicFactory.createSystemTopic(key, eventType); - } - - public SystemTopic getTopicPoliciesSystemTopic(NamespaceName namespaceName) { - return getSystemTopic(namespaceName.toString(), EventType.TOPIC_POLICY); - } - - private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicService.class); -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java deleted file mode 100644 index 3f87822bbe87c..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicFactory.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * 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.broker.systopic; - -/** - * System topic factory - */ -public interface SystemTopicFactory { - - /** - * Create a new system topic - * @param key key of the system topic - * @param eventType event type - * @return system topic - */ - SystemTopic createSystemTopic(String key, EventType eventType); -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java deleted file mode 100644 index 93a7a219657a3..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicService.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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.broker.systopic; - -/** - * System Topic Service - */ -public interface SystemTopicService { - - /** - * Get system topic by key. - * @param key key of the system topic - * @param eventType event type - * @return system topic or null while error cause - */ - SystemTopic getSystemTopic(String key, EventType eventType); - -} diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java new file mode 100644 index 0000000000000..97ca4bfb3dbde --- /dev/null +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java @@ -0,0 +1,167 @@ +package org.apache.pulsar.broker.service; + +import com.google.common.collect.Sets; +import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; +import org.apache.pulsar.broker.systopic.ActionType; +import org.apache.pulsar.broker.systopic.EventType; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; +import org.apache.pulsar.broker.systopic.PulsarEvent; +import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.TopicEvent; +import org.apache.pulsar.client.admin.PulsarAdminException; +import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.policies.data.ClusterData; +import org.apache.pulsar.common.policies.data.TenantInfo; +import org.apache.pulsar.common.policies.data.TopicPolicies; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +public class TopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { + + private static final String NAMESPACE1 = "system-topic/namespace-1"; + private static final String NAMESPACE2 = "system-topic/namespace-2"; + private static final String NAMESPACE3 = "system-topic/namespace-3"; + + private static final TopicName TOPIC1 = TopicName.get("persistent", NamespaceName.get(NAMESPACE1), "topic-1"); + private static final TopicName TOPIC2 = TopicName.get("persistent", NamespaceName.get(NAMESPACE1), "topic-2"); + private static final TopicName TOPIC3 = TopicName.get("persistent", NamespaceName.get(NAMESPACE2), "topic-1"); + private static final TopicName TOPIC4 = TopicName.get("persistent", NamespaceName.get(NAMESPACE2), "topic-2"); + private static final TopicName TOPIC5 = TopicName.get("persistent", NamespaceName.get(NAMESPACE3), "topic-1"); + private static final TopicName TOPIC6 = TopicName.get("persistent", NamespaceName.get(NAMESPACE3), "topic-2"); + + private NamespaceEventsSystemTopicFactory systemTopicFactory; + private TopicPoliciesService topicPoliciesService; + + @BeforeMethod + @Override + protected void setup() throws Exception { + super.internalSetup(); + prepareData(); + } + + @AfterMethod + @Override + protected void cleanup() throws Exception { + super.internalCleanup(); + } + + @Test + public void testGetPolicy() throws PulsarClientException, ExecutionException, InterruptedException { + + SystemTopic systemTopicForNamespace1 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE1), EventType.TOPIC_POLICY); + + // Update policy for TOPIC1 + TopicPolicies policies1 = TopicPolicies.builder() + .maxProducerPerTopic(1) + .build(); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + + // Update policy for TOPIC2 + TopicPolicies policies2 = TopicPolicies.builder() + .maxProducerPerTopic(2) + .build(); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + + SystemTopic systemTopicForNamespace2 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE2), EventType.TOPIC_POLICY); + + // Update policy for TOPIC3 + TopicPolicies policies3 = TopicPolicies.builder() + .maxProducerPerTopic(3) + .build(); + systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC3, policies3)); + + // Update policy for TOPIC4 + TopicPolicies policies4 = TopicPolicies.builder() + .maxProducerPerTopic(4) + .build(); + systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC4, policies4)); + + SystemTopic systemTopicForNamespace3 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE3), EventType.TOPIC_POLICY); + + // Update policy for TOPIC5 + TopicPolicies policies5 = TopicPolicies.builder() + .maxProducerPerTopic(5) + .build(); + systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC5, policies5)); + + // Update policy for TOPIC6 + TopicPolicies policies6 = TopicPolicies.builder() + .maxProducerPerTopic(6) + .build(); + systemTopicForNamespace3.newWriter().write(buildEvent(TOPIC6, policies6)); + + TopicPolicies policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); + TopicPolicies policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); + TopicPolicies policiesGet3 = topicPoliciesService.getTopicPoliciesAsync(TOPIC3).get(); + TopicPolicies policiesGet4 = topicPoliciesService.getTopicPoliciesAsync(TOPIC4).get(); + TopicPolicies policiesGet5 = topicPoliciesService.getTopicPoliciesAsync(TOPIC5).get(); + TopicPolicies policiesGet6 = topicPoliciesService.getTopicPoliciesAsync(TOPIC6).get(); + + Assert.assertEquals(policies1, policiesGet1); + Assert.assertEquals(policies2, policiesGet2); + Assert.assertEquals(policies3, policiesGet3); + Assert.assertEquals(policies4, policiesGet4); + Assert.assertEquals(policies5, policiesGet5); + Assert.assertEquals(policies6, policiesGet6); + + policies1.setMaxProducerPerTopic(101); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + policies2.setMaxProducerPerTopic(102); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + policies2.setMaxProducerPerTopic(103); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + policies1.setMaxProducerPerTopic(104); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + policies2.setMaxProducerPerTopic(105); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + policies1.setMaxProducerPerTopic(106); + systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + + policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); + policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); + Assert.assertEquals(policies1, policiesGet1); + Assert.assertEquals(policies2, policiesGet2); + + // Only cache 2 readers + Assert.assertEquals(topicPoliciesService.getReaderCacheCount(), 3 - 1); + + // Remove reader cache will remove policies cache + Assert.assertEquals(topicPoliciesService.getPoliciesCacheSize(), 6 - 2); + + // Check get without cache + policiesGet1 = topicPoliciesService.getTopicPoliciesWithoutCacheAsync(TOPIC1).get(); + Assert.assertEquals(policies1, policiesGet1); + } + + private PulsarEvent buildEvent(TopicName topic, TopicPolicies policies) { + return PulsarEvent.builder() + .eventType(EventType.TOPIC_POLICY) + .actionType(ActionType.UPDATE) + .topicEvent(TopicEvent.builder() + .domain(topic.getDomain().toString()) + .tenant(topic.getTenant()) + .namespace(topic.getNamespaceObject().getLocalName()) + .topic(topic.getLocalName()) + .policies(policies) + .build()) + .build(); + } + + private void prepareData() throws PulsarAdminException { + admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); + admin.tenants().createTenant("system-topic", + new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); + admin.namespaces().createNamespace(NAMESPACE1); + admin.namespaces().createNamespace(NAMESPACE2); + admin.namespaces().createNamespace(NAMESPACE3); + systemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarClient); + topicPoliciesService = new TopicPoliciesService(pulsar, 2, 1, TimeUnit.MINUTES); + } +} diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java similarity index 61% rename from pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java rename to pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java index db16e443b0fcf..2a101f8e1aba4 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/system/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java @@ -16,21 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.pulsar.broker.system; +package org.apache.pulsar.broker.systopic; import com.google.common.collect.Sets; -import org.apache.bookkeeper.common.util.JsonUtil.ParseJsonException; import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; -import org.apache.pulsar.broker.systopic.ActionType; -import org.apache.pulsar.broker.systopic.EventType; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicService; -import org.apache.pulsar.broker.systopic.PulsarEvent; -import org.apache.pulsar.broker.systopic.SystemTopic; -import org.apache.pulsar.broker.systopic.SystemTopicService; -import org.apache.pulsar.broker.systopic.TopicEvent; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Message; -import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.policies.data.ClusterData; import org.apache.pulsar.common.policies.data.TenantInfo; @@ -42,8 +33,6 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.io.IOException; - public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBaseTest { private static final Logger log = LoggerFactory.getLogger(NamespaceEventsSystemTopicServiceTest.class); @@ -54,7 +43,7 @@ public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBa private static final String LOCAL_TOPIC_NAME = "__change_events"; - private NamespaceEventsSystemTopicService systemTopicService; + private NamespaceEventsSystemTopicFactory systemTopicFactory; @BeforeMethod @Override @@ -69,43 +58,9 @@ protected void cleanup() throws Exception { super.internalCleanup(); } - @Test - public void testGetSystemTopic() { - - SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); - Assert.assertEquals(systemTopicForNamespace1.getTopicName().getNamespace(), NAMESPACE1); - Assert.assertEquals(systemTopicForNamespace1.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); - - SystemTopic systemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE2, EventType.TOPIC_POLICY); - Assert.assertEquals(systemTopicForNamespace2.getTopicName().getNamespace(), NAMESPACE2); - Assert.assertEquals(systemTopicForNamespace2.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); - - SystemTopic systemTopicForNamespace3 = systemTopicService.getSystemTopic(NAMESPACE3, EventType.TOPIC_POLICY); - Assert.assertEquals(systemTopicForNamespace3.getTopicName().getNamespace(), NAMESPACE3); - Assert.assertEquals(systemTopicForNamespace3.getTopicName().getLocalName(), LOCAL_TOPIC_NAME); - - SystemTopic cachedSystemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); - Assert.assertSame(cachedSystemTopicForNamespace1, systemTopicForNamespace1); - - SystemTopic cachedSystemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE2, EventType.TOPIC_POLICY); - Assert.assertSame(cachedSystemTopicForNamespace2, systemTopicForNamespace2); - - SystemTopic cachedSystemTopicForNamespace3 = systemTopicService.getSystemTopic(NAMESPACE3, EventType.TOPIC_POLICY); - Assert.assertSame(cachedSystemTopicForNamespace3, systemTopicForNamespace3); - } - - @Test - public void testDestroySystemTopic() { - SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); - systemTopicService.invalidate(NAMESPACE1, EventType.TOPIC_POLICY); - SystemTopic systemTopicForNamespace2 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); - Assert.assertNotSame(systemTopicForNamespace1, systemTopicForNamespace2); - systemTopicService.invalidate(NAMESPACE1, EventType.TOPIC_POLICY); - } - @Test public void testSendAndReceiveNamespaceEvents() throws Exception { - SystemTopic systemTopicForNamespace1 = systemTopicService.getSystemTopic(NAMESPACE1, EventType.TOPIC_POLICY); + SystemTopic systemTopicForNamespace1 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE1), EventType.TOPIC_POLICY); TopicPolicies policies = TopicPolicies.builder() .maxProducerPerTopic(10) .build(); @@ -156,6 +111,6 @@ private void prepareData() throws PulsarAdminException { admin.namespaces().createNamespace(NAMESPACE1); admin.namespaces().createNamespace(NAMESPACE2); admin.namespaces().createNamespace(NAMESPACE3); - systemTopicService = new NamespaceEventsSystemTopicService(pulsarClient); + systemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarClient); } } From 65a0269c4158f61d54f3362c33fccc2e8ef3ff3d Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 20 Aug 2019 19:55:41 +0800 Subject: [PATCH 04/31] Add license header. --- .../service/TopicPoliciesServiceTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java index 97ca4bfb3dbde..c50cc09ad5e65 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java @@ -1,3 +1,21 @@ +/** + * 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.broker.service; import com.google.common.collect.Sets; From 27ee07e771d98dafcc88b8f307e62184430d7e16 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 22 Aug 2019 10:51:23 +0800 Subject: [PATCH 05/31] Fix comments --- conf/broker.conf | 4 +-- conf/standalone.conf | 7 ++-- .../pulsar/broker/ServiceConfiguration.java | 7 ++-- .../apache/pulsar/broker/PulsarService.java | 2 +- .../pulsar/broker/service/BrokerService.java | 8 ++--- .../broker/service/TopicPoliciesService.java | 31 ++++++++++-------- .../NamespaceEventsSystemTopicFactory.java | 8 +++-- .../pulsar/broker/systopic/SystemTopic.java | 1 + ...pic.java => TopicPoliciesSystemTopic.java} | 23 ++++++------- .../service/TopicPoliciesServiceTest.java | 31 ++++++++++++------ ...NamespaceEventsSystemTopicServiceTest.java | 8 +++-- .../pulsar/common/events}/ActionType.java | 2 +- .../pulsar/common/events}/EventType.java | 2 +- .../common/events/EventsTopicNames.java | 32 +++++++++++++++++++ .../pulsar/common/events}/PulsarEvent.java | 4 +-- .../common/events/TopicPoliciesEvent.java | 4 +-- 16 files changed, 115 insertions(+), 59 deletions(-) rename pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/{TopicPolicySystemTopic.java => TopicPoliciesSystemTopic.java} (87%) rename {pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic => pulsar-common/src/main/java/org/apache/pulsar/common/events}/ActionType.java (95%) rename {pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic => pulsar-common/src/main/java/org/apache/pulsar/common/events}/EventType.java (95%) create mode 100644 pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java rename {pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic => pulsar-common/src/main/java/org/apache/pulsar/common/events}/PulsarEvent.java (92%) rename pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java => pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java (94%) diff --git a/conf/broker.conf b/conf/broker.conf index d3d51cdbb96c3..b02d6a0a5d726 100644 --- a/conf/broker.conf +++ b/conf/broker.conf @@ -359,11 +359,11 @@ retentionCheckIntervalInSeconds=120 maxNumPartitionsPerPartitionedTopic=0 # Enable or disable system topic -systemTopicEnable=true +systemTopicEnabled=true # Enable or disable topic level policies, topic level policies depends on the system topic # Please enable the system topic first. -topicLevelPoliciesEnable=true +topicLevelPoliciesEnabled=true ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with diff --git a/conf/standalone.conf b/conf/standalone.conf index 50dcf96bda6f4..b215246b1066d 100644 --- a/conf/standalone.conf +++ b/conf/standalone.conf @@ -323,10 +323,11 @@ brokerClientTlsCiphers= brokerClientTlsProtocols= # Enable or disable system topic -systemTopicEnable=true +systemTopicEnabled=true -# Enable topic level policies -topicLevelPoliciesEnable=true +# Enable or disable topic level policies, topic level policies depends on the system topic +# Please enable the system topic first. +topicLevelPoliciesEnabled=true ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java index a83a3ca49a09d..41c935a72fb20 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java @@ -677,12 +677,13 @@ public class ServiceConfiguration implements PulsarConfiguration { @FieldContext( category = CATEGORY_SERVER, doc = "Enable or disable system topic.") - private boolean systemTopicEnable = true; + private boolean systemTopicEnabled = true; @FieldContext( category = CATEGORY_SERVER, - doc = "Enable topic level policies.") - private boolean topicLevelPoliciesEnable = true; + doc = "Enable or disable topic level policies, topic level policies depends on the system topic, " + + "please enable the system topic first.") + private boolean topicLevelPoliciesEnabled = true; /***** --- TLS --- ****/ @FieldContext( diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index c2408a4958d86..f87e3296bd743 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -421,7 +421,7 @@ public void start() throws PulsarServerException { brokerService.start(); // Start topic level policies service - if (config.isTopicLevelPoliciesEnable() && config.isSystemTopicEnable()) { + if (config.isTopicLevelPoliciesEnabled() && config.isSystemTopicEnabled()) { this.topicPoliciesService = new TopicPoliciesService(this); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java index 189415914a0f8..eb8d6d275dc2a 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java @@ -118,6 +118,7 @@ import org.apache.pulsar.client.impl.conf.ClientConfigurationData; import org.apache.pulsar.common.allocator.PulsarByteBufAllocator; import org.apache.pulsar.common.configuration.FieldContext; +import org.apache.pulsar.common.events.EventsTopicNames; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; import org.apache.pulsar.common.naming.NamespaceBundles; @@ -931,9 +932,8 @@ private void createPersistentTopic(final String topic, boolean createIfMissing, @Override public void openLedgerComplete(ManagedLedger ledger, Object ctx) { try { - PersistentTopic persistentTopic = isSystemTopic(topic) - ? new PersistentTopic(topic, ledger, BrokerService.this, true) - : new PersistentTopic(topic, ledger, BrokerService.this, false); + PersistentTopic persistentTopic = new PersistentTopic( + topic, ledger, BrokerService.this, isSystemTopic(topic)); CompletableFuture replicationFuture = persistentTopic.checkReplication(); replicationFuture.thenCompose(v -> { // Also check dedup status @@ -2234,6 +2234,6 @@ private AutoSubscriptionCreationOverride getAutoSubscriptionCreationOverride(fin return null; } private boolean isSystemTopic(String topic) { - return NamespaceEventsSystemTopicFactory.LOCAL_TOPIC_NAME.equals(TopicName.get(topic).getLocalName()); + return EventsTopicNames.NAMESPACE_EVENTS_LOCAL_NAME.equals(TopicName.get(topic).getLocalName()); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 3cb6fa115578d..2bf20085177c0 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -25,10 +25,10 @@ import com.google.common.cache.RemovalListener; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; -import org.apache.pulsar.broker.systopic.EventType; +import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.systopic.SystemTopic; -import org.apache.pulsar.broker.systopic.TopicEvent; +import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; @@ -156,17 +156,17 @@ private void createSystemTopicFactoryIfNeeded() { } private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture refreshFuture) { - reader.hasMoreEventsAsync().whenComplete((has, ex) -> { + reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { refreshFuture.completeExceptionally(ex); } - if (has) { + if (hasMore) { reader.readNextAsync().whenComplete((msg, e) -> { if (e != null) { refreshFuture.completeExceptionally(e); } if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { - TopicEvent event = msg.getValue().getTopicEvent(); + TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); policiesCache.put( TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), event.getPolicies() @@ -182,24 +182,24 @@ private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture future) { - reader.hasMoreEventsAsync().whenComplete((has, ex) -> { + reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { future.completeExceptionally(ex); } - if (has) { + if (hasMore) { reader.readNextAsync().whenComplete((msg, e) -> { if (e != null) { future.completeExceptionally(e); } if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { - TopicEvent topicEvent = msg.getValue().getTopicEvent(); + TopicPoliciesEvent topicPoliciesEvent = msg.getValue().getTopicPoliciesEvent(); if (topicName.equals(TopicName.get( - topicEvent.getDomain(), - topicEvent.getTenant(), - topicEvent.getNamespace(), - topicEvent.getTopic())) + topicPoliciesEvent.getDomain(), + topicPoliciesEvent.getTenant(), + topicPoliciesEvent.getNamespace(), + topicPoliciesEvent.getTopic())) ) { - fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, topicEvent.getPolicies(), future); + fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, topicPoliciesEvent.getPolicies(), future); } else { fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, policies, future); } @@ -226,5 +226,10 @@ long getReaderCacheCount() { return readerCache.size(); } + @VisibleForTesting + boolean checkReaderIsCached(NamespaceName namespaceName) { + return readerCache.getIfPresent(namespaceName) != null; + } + private static final Logger log = LoggerFactory.getLogger(TopicPoliciesService.class); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java index 96ad52bde2e22..85c95dcee7d52 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java @@ -19,6 +19,8 @@ package org.apache.pulsar.broker.systopic; import org.apache.pulsar.client.api.PulsarClient; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.common.events.EventsTopicNames; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.slf4j.Logger; @@ -26,7 +28,6 @@ public class NamespaceEventsSystemTopicFactory { - public static final String LOCAL_TOPIC_NAME = "__change_events"; private final PulsarClient client; public NamespaceEventsSystemTopicFactory(PulsarClient client) { @@ -36,9 +37,10 @@ public NamespaceEventsSystemTopicFactory(PulsarClient client) { public SystemTopic createSystemTopic(NamespaceName namespaceName, EventType eventType) { switch (eventType) { case TOPIC_POLICY: - TopicName topicName = TopicName.get("persistent", namespaceName, LOCAL_TOPIC_NAME); + TopicName topicName = TopicName.get("persistent", namespaceName, + EventsTopicNames.NAMESPACE_EVENTS_LOCAL_NAME); log.info("Create system topic {} for topic policy.", topicName.toString()); - return new TopicPolicySystemTopic(client, topicName); + return new TopicPoliciesSystemTopic(client, topicName); default: return null; } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java index c73c8e6f5dd2f..69cc2c59c28d9 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java @@ -21,6 +21,7 @@ import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.naming.TopicName; import java.io.IOException; diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java similarity index 87% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java rename to pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java index 119459f09a1c1..3d4d9f604cdd2 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPolicySystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java @@ -24,6 +24,7 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.Schema; +import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.naming.TopicName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,9 +35,9 @@ /** * System topic for topic policy */ -public class TopicPolicySystemTopic extends SystemTopicBase { +public class TopicPoliciesSystemTopic extends SystemTopicBase { - public TopicPolicySystemTopic(PulsarClient client, TopicName topicName) { + public TopicPoliciesSystemTopic(PulsarClient client, TopicName topicName) { super(client, topicName); } @@ -48,7 +49,7 @@ protected CompletableFuture newWriterAsyncInternal() { if (log.isDebugEnabled()) { log.debug("[{}] A new writer is created", topicName); } - return CompletableFuture.completedFuture(new TopicPolicyWriter(producer, TopicPolicySystemTopic.this)); + return CompletableFuture.completedFuture(new TopicPolicyWriter(producer, TopicPoliciesSystemTopic.this)); }); } @@ -62,7 +63,7 @@ protected CompletableFuture newReaderAsyncInternal() { if (log.isDebugEnabled()) { log.debug("[{}] A new reader is created", topicName); } - return CompletableFuture.completedFuture(new TopicPolicyReader(reader, TopicPolicySystemTopic.this)); + return CompletableFuture.completedFuture(new TopicPolicyReader(reader, TopicPoliciesSystemTopic.this)); }); } @@ -87,10 +88,10 @@ public CompletableFuture writeAsync(PulsarEvent event) { } private String getEventKey(PulsarEvent event) { - return TopicName.get(event.getTopicEvent().getDomain(), - event.getTopicEvent().getTenant(), - event.getTopicEvent().getNamespace(), - event.getTopicEvent().getTopic()).toString(); + return TopicName.get(event.getTopicPoliciesEvent().getDomain(), + event.getTopicPoliciesEvent().getTenant(), + event.getTopicPoliciesEvent().getNamespace(), + event.getTopicPoliciesEvent().getTopic()).toString(); } @Override @@ -113,10 +114,10 @@ public SystemTopic getSystemTopic() { private static class TopicPolicyReader implements Reader { private final org.apache.pulsar.client.api.Reader reader; - private final TopicPolicySystemTopic systemTopic; + private final TopicPoliciesSystemTopic systemTopic; private TopicPolicyReader(org.apache.pulsar.client.api.Reader reader, - TopicPolicySystemTopic systemTopic) { + TopicPoliciesSystemTopic systemTopic) { this.reader = reader; this.systemTopic = systemTopic; } @@ -161,5 +162,5 @@ public SystemTopic getSystemTopic() { } } - private static final Logger log = LoggerFactory.getLogger(TopicPolicySystemTopic.class); + private static final Logger log = LoggerFactory.getLogger(TopicPoliciesSystemTopic.class); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java index c50cc09ad5e65..6049a804f008d 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java @@ -20,12 +20,12 @@ import com.google.common.collect.Sets; import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; -import org.apache.pulsar.broker.systopic.ActionType; -import org.apache.pulsar.broker.systopic.EventType; +import org.apache.pulsar.common.events.ActionType; +import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.PulsarEvent; +import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.broker.systopic.SystemTopic; -import org.apache.pulsar.broker.systopic.TopicEvent; +import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.NamespaceName; @@ -129,6 +129,17 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertEquals(policies5, policiesGet5); Assert.assertEquals(policies6, policiesGet6); + // Only cache 2 readers, reader for NAMESPACE1 is evicted + Assert.assertEquals(topicPoliciesService.getReaderCacheCount(), 3 - 1); + + // Remove reader cache will remove policies cache + Assert.assertEquals(topicPoliciesService.getPoliciesCacheSize(), 6 - 2); + + // Check reader cache is correct. + Assert.assertFalse(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); + Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); + Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); + policies1.setMaxProducerPerTopic(101); systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); policies2.setMaxProducerPerTopic(102); @@ -142,16 +153,16 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In policies1.setMaxProducerPerTopic(106); systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + // reader for NAMESPACE1 will back fill the reader cache policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); Assert.assertEquals(policies1, policiesGet1); Assert.assertEquals(policies2, policiesGet2); - // Only cache 2 readers - Assert.assertEquals(topicPoliciesService.getReaderCacheCount(), 3 - 1); - - // Remove reader cache will remove policies cache - Assert.assertEquals(topicPoliciesService.getPoliciesCacheSize(), 6 - 2); + // Check reader cache is correct. + Assert.assertFalse(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); + Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); + Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); // Check get without cache policiesGet1 = topicPoliciesService.getTopicPoliciesWithoutCacheAsync(TOPIC1).get(); @@ -162,7 +173,7 @@ private PulsarEvent buildEvent(TopicName topic, TopicPolicies policies) { return PulsarEvent.builder() .eventType(EventType.TOPIC_POLICY) .actionType(ActionType.UPDATE) - .topicEvent(TopicEvent.builder() + .topicPoliciesEvent(TopicPoliciesEvent.builder() .domain(topic.getDomain().toString()) .tenant(topic.getTenant()) .namespace(topic.getNamespaceObject().getLocalName()) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java index 2a101f8e1aba4..98f6dbd801d46 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java @@ -22,6 +22,10 @@ import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.common.events.ActionType; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.common.events.PulsarEvent; +import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.policies.data.ClusterData; import org.apache.pulsar.common.policies.data.TenantInfo; @@ -41,8 +45,6 @@ public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBa private static final String NAMESPACE2 = "system-topic/namespace-2"; private static final String NAMESPACE3 = "system-topic/namespace-3"; - private static final String LOCAL_TOPIC_NAME = "__change_events"; - private NamespaceEventsSystemTopicFactory systemTopicFactory; @BeforeMethod @@ -67,7 +69,7 @@ public void testSendAndReceiveNamespaceEvents() throws Exception { PulsarEvent event = PulsarEvent.builder() .eventType(EventType.TOPIC_POLICY) .actionType(ActionType.INSERT) - .topicEvent(TopicEvent.builder() + .topicPoliciesEvent(TopicPoliciesEvent.builder() .domain("persistent") .tenant("system-topic") .namespace(NamespaceName.get(NAMESPACE1).getLocalName()) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java similarity index 95% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java rename to pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java index e251e4a4e32e3..ff48bbd31b385 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/ActionType.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.pulsar.broker.systopic; +package org.apache.pulsar.common.events; /** * Pulsar event action type diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java similarity index 95% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java rename to pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java index ab3c22985731f..0bbd5cd95baa3 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/EventType.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.pulsar.broker.systopic; +package org.apache.pulsar.common.events; /** * Pulsar system event type diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java new file mode 100644 index 0000000000000..19cd30e9ee16a --- /dev/null +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.common.events; + +/** + * System topic name for the event type + */ +public class EventsTopicNames { + + + /** + * Local topic name for the namespace events. + */ + public static final String NAMESPACE_EVENTS_LOCAL_NAME = "__change_events"; + +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java similarity index 92% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java rename to pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java index b5641139ab384..f8a5498e0b271 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/PulsarEvent.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.pulsar.broker.systopic; +package org.apache.pulsar.common.events; import lombok.AllArgsConstructor; import lombok.Builder; @@ -31,5 +31,5 @@ public class PulsarEvent { private EventType eventType; private ActionType actionType; - private TopicEvent topicEvent; + private TopicPoliciesEvent topicPoliciesEvent; } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java similarity index 94% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java rename to pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java index d71b2d0427217..e6ae7d9b0d4c1 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicEvent.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.pulsar.broker.systopic; +package org.apache.pulsar.common.events; import lombok.AllArgsConstructor; import lombok.Builder; @@ -28,7 +28,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class TopicEvent { +public class TopicPoliciesEvent { private String domain; private String tenant; From 6dc49ba31d0e987de1e1210c96e243d7563d6b88 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 22 Aug 2019 11:58:48 +0800 Subject: [PATCH 06/31] Add updateTopicPoliciesAsync for TopicPoliciesService --- .../broker/service/TopicPoliciesService.java | 63 +++++++++++++++++-- .../service/TopicPoliciesServiceTest.java | 62 ++++++------------ 2 files changed, 76 insertions(+), 49 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 2bf20085177c0..95f37eb41947e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -25,9 +25,12 @@ import com.google.common.cache.RemovalListener; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.client.api.MessageId; +import org.apache.pulsar.common.events.ActionType; import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; @@ -66,21 +69,23 @@ public TopicPoliciesService(PulsarService pulsarService, long cacheSize, long ca .removalListener((RemovalListener>) notification -> { NamespaceName namespaceName = notification.getKey(); if (log.isDebugEnabled()) { - log.debug("Reader cache was evicted for namespace {}, current reader cache size is {} ", namespaceName, + log.debug("[{}] Reader cache was evicted, current reader cache size is {} ", namespaceName, TopicPoliciesService.this.readerCache.asMap().size()); } policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespaceName)); if (log.isDebugEnabled()) { - log.debug("Topic policies cache deleted success, current policies cache size is {} ", policiesCache.size()); + log.debug("[{}] Topic policies cache deleted success, current policies cache size is {} ", + namespaceName, policiesCache.size()); } notification.getValue().whenComplete((reader, ex) -> { if (ex == null && reader != null) { reader.closeAsync().whenComplete((v, e) -> { if (e != null) { - log.error("Close system topic reader error for reader cache expire", e); + log.error("[{}] Close reader error for reader cache expire", namespaceName, e); } else { if (log.isDebugEnabled()) { - log.debug("Reader for system topic {} is closed.", reader.getSystemTopic().getTopicName()); + log.debug("[{}] Reader is closed for reader cache expire.", + reader.getSystemTopic().getTopicName()); } } }); @@ -103,12 +108,56 @@ public CompletableFuture load(NamespaceName namespaceName) { }); } + public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies) { + createSystemTopicFactoryIfNeeded(); + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), + EventType.TOPIC_POLICY); + CompletableFuture result = new CompletableFuture<>(); + CompletableFuture writerFuture = systemTopic.newWriterAsync(); + writerFuture.whenComplete((writer, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); + } else { + writer.writeAsync( + PulsarEvent.builder() + .actionType(ActionType.UPDATE) + .eventType(EventType.TOPIC_POLICY) + .topicPoliciesEvent( + TopicPoliciesEvent.builder() + .domain(topicName.getDomain().toString()) + .tenant(topicName.getTenant()) + .namespace(topicName.getNamespaceObject().getLocalName()) + .topic(topicName.getLocalName()) + .policies(policies) + .build()) + .build()).whenComplete(((messageId, e) -> { + if (e != null) { + result.completeExceptionally(e); + } else { + result.complete(messageId); + } + writer.closeAsync().whenComplete((v, cause) -> { + if (cause != null) { + log.error("[{}] Close writer error.", topicName, cause); + } else { + if (log.isDebugEnabled()) { + log.debug("[{}] Close writer success.", topicName); + } + } + }); + }) + ); + } + }); + return result; + } + public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { CompletableFuture readerFuture = null; try { readerFuture = readerCache.get(topicName.getNamespaceObject()); } catch (ExecutionException e) { - log.error("Load reader for system topic {} error.", topicName, e); + log.error("[{}] Load reader error.", topicName, e); } if (readerFuture == null) { return CompletableFuture.completedFuture(null); @@ -159,11 +208,13 @@ private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture { if (ex != null) { refreshFuture.completeExceptionally(ex); + readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); } if (hasMore) { reader.readNextAsync().whenComplete((msg, e) -> { if (e != null) { refreshFuture.completeExceptionally(e); + readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); } if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); @@ -209,7 +260,7 @@ private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, To future.complete(policies); reader.closeAsync().whenComplete((v, e) -> { if (e != null) { - log.error("Close reader for system topic {} error.", topicName, e); + log.error("[{}] Close reader error.", topicName, e); } }); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java index 6049a804f008d..9e6688708f1ce 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java @@ -20,12 +20,8 @@ import com.google.common.collect.Sets; import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; -import org.apache.pulsar.common.events.ActionType; -import org.apache.pulsar.common.events.EventType; + import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.common.events.PulsarEvent; -import org.apache.pulsar.broker.systopic.SystemTopic; -import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.NamespaceName; @@ -73,47 +69,41 @@ protected void cleanup() throws Exception { @Test public void testGetPolicy() throws PulsarClientException, ExecutionException, InterruptedException { - SystemTopic systemTopicForNamespace1 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE1), EventType.TOPIC_POLICY); - // Update policy for TOPIC1 TopicPolicies policies1 = TopicPolicies.builder() .maxProducerPerTopic(1) .build(); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1).get(); // Update policy for TOPIC2 TopicPolicies policies2 = TopicPolicies.builder() .maxProducerPerTopic(2) .build(); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); - - SystemTopic systemTopicForNamespace2 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE2), EventType.TOPIC_POLICY); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2).get(); // Update policy for TOPIC3 TopicPolicies policies3 = TopicPolicies.builder() .maxProducerPerTopic(3) .build(); - systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC3, policies3)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC3, policies3).get(); // Update policy for TOPIC4 TopicPolicies policies4 = TopicPolicies.builder() .maxProducerPerTopic(4) .build(); - systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC4, policies4)); - - SystemTopic systemTopicForNamespace3 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE3), EventType.TOPIC_POLICY); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC4, policies4).get(); // Update policy for TOPIC5 TopicPolicies policies5 = TopicPolicies.builder() .maxProducerPerTopic(5) .build(); - systemTopicForNamespace2.newWriter().write(buildEvent(TOPIC5, policies5)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC5, policies5).get(); // Update policy for TOPIC6 TopicPolicies policies6 = TopicPolicies.builder() .maxProducerPerTopic(6) .build(); - systemTopicForNamespace3.newWriter().write(buildEvent(TOPIC6, policies6)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC6, policies6).get(); TopicPolicies policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); TopicPolicies policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); @@ -122,12 +112,12 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In TopicPolicies policiesGet5 = topicPoliciesService.getTopicPoliciesAsync(TOPIC5).get(); TopicPolicies policiesGet6 = topicPoliciesService.getTopicPoliciesAsync(TOPIC6).get(); - Assert.assertEquals(policies1, policiesGet1); - Assert.assertEquals(policies2, policiesGet2); - Assert.assertEquals(policies3, policiesGet3); - Assert.assertEquals(policies4, policiesGet4); - Assert.assertEquals(policies5, policiesGet5); - Assert.assertEquals(policies6, policiesGet6); + Assert.assertEquals(policiesGet1, policies1); + Assert.assertEquals(policiesGet2, policies2); + Assert.assertEquals(policiesGet3, policies3); + Assert.assertEquals(policiesGet4, policies4); + Assert.assertEquals(policiesGet5, policies5); + Assert.assertEquals(policiesGet6, policies6); // Only cache 2 readers, reader for NAMESPACE1 is evicted Assert.assertEquals(topicPoliciesService.getReaderCacheCount(), 3 - 1); @@ -141,17 +131,17 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); policies1.setMaxProducerPerTopic(101); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); policies2.setMaxProducerPerTopic(102); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies2.setMaxProducerPerTopic(103); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies1.setMaxProducerPerTopic(104); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); policies2.setMaxProducerPerTopic(105); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC2, policies2)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies1.setMaxProducerPerTopic(106); - systemTopicForNamespace1.newWriter().write(buildEvent(TOPIC1, policies1)); + topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); // reader for NAMESPACE1 will back fill the reader cache policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); @@ -169,20 +159,6 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertEquals(policies1, policiesGet1); } - private PulsarEvent buildEvent(TopicName topic, TopicPolicies policies) { - return PulsarEvent.builder() - .eventType(EventType.TOPIC_POLICY) - .actionType(ActionType.UPDATE) - .topicPoliciesEvent(TopicPoliciesEvent.builder() - .domain(topic.getDomain().toString()) - .tenant(topic.getTenant()) - .namespace(topic.getNamespaceObject().getLocalName()) - .topic(topic.getLocalName()) - .policies(policies) - .build()) - .build(); - } - private void prepareData() throws PulsarAdminException { admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); admin.tenants().createTenant("system-topic", From 7fc3a9b013a48705687f1f10bda00fcf64d20bee Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 27 Aug 2019 15:41:11 +0800 Subject: [PATCH 07/31] Add topic policies service interface and rename old topic policies service to SystemTopicBasedTopicPoliciesService --- .../apache/pulsar/broker/PulsarService.java | 5 +- .../SystemTopicBasedTopicPoliciesService.java | 296 ++++++++++++++++++ .../broker/service/TopicPoliciesService.java | 275 ++-------------- ...emTopicBasedTopicPoliciesServiceTest.java} | 64 ++-- 4 files changed, 362 insertions(+), 278 deletions(-) create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java rename pulsar-broker/src/test/java/org/apache/pulsar/broker/service/{TopicPoliciesServiceTest.java => SystemTopicBasedTopicPoliciesServiceTest.java} (63%) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index f87e3296bd743..72aa1f0529467 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -85,6 +85,7 @@ import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.protocol.ProtocolHandlers; import org.apache.pulsar.broker.service.BrokerService; +import org.apache.pulsar.broker.service.SystemTopicBasedTopicPoliciesService; import org.apache.pulsar.broker.service.Topic; import org.apache.pulsar.broker.service.TopicPoliciesService; import org.apache.pulsar.broker.service.schema.SchemaRegistryService; @@ -153,7 +154,7 @@ public class PulsarService implements AutoCloseable { private WebSocketService webSocketService = null; private ConfigurationCacheService configurationCacheService = null; private LocalZooKeeperCacheService localZkCacheService = null; - private TopicPoliciesService topicPoliciesService = null; + private TopicPoliciesService topicPoliciesService = TopicPoliciesService.DISABLED; private BookKeeperClientFactory bkClientFactory; private ZooKeeperCache localZkCache; private GlobalZooKeeperCache globalZkCache; @@ -422,7 +423,7 @@ public void start() throws PulsarServerException { // Start topic level policies service if (config.isTopicLevelPoliciesEnabled() && config.isSystemTopicEnabled()) { - this.topicPoliciesService = new TopicPoliciesService(this); + this.topicPoliciesService = new SystemTopicBasedTopicPoliciesService(this); } brokerService.start(); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java new file mode 100644 index 0000000000000..1216030723674 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -0,0 +1,296 @@ +/** + * 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.broker.service; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.cache.RemovalListener; +import org.apache.pulsar.broker.PulsarServerException; +import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.common.events.ActionType; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; +import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.common.events.PulsarEvent; +import org.apache.pulsar.common.events.TopicPoliciesEvent; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.policies.data.TopicPolicies; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * Cached topic policies service will cache the system topic reader and the topic policies + * + * While reader cache for the namespace was removed, the topic policies will remove automatically. + */ +public class SystemTopicBasedTopicPoliciesService implements TopicPoliciesService { + + private final PulsarService pulsarService; + private NamespaceEventsSystemTopicFactory namespaceEventsSystemTopicFactory; + + private final Map policiesCache = new ConcurrentHashMap<>(); + + private final LoadingCache> readerCache; + + public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { + this(pulsarService, 1000, 30, TimeUnit.MINUTES); + } + + public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService, long cacheSize, long cacheExpireDuration, TimeUnit cacheExpireUnit) { + this.pulsarService = pulsarService; + this.readerCache = CacheBuilder.newBuilder() + .maximumSize(cacheSize) + .expireAfterAccess(cacheExpireDuration, cacheExpireUnit) + .removalListener((RemovalListener>) notification -> { + NamespaceName namespaceName = notification.getKey(); + if (log.isDebugEnabled()) { + log.debug("[{}] Reader cache was evicted, current reader cache size is {} ", namespaceName, + SystemTopicBasedTopicPoliciesService.this.readerCache.asMap().size()); + } + policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespaceName)); + if (log.isDebugEnabled()) { + log.debug("[{}] Topic policies cache deleted success, current policies cache size is {} ", + namespaceName, policiesCache.size()); + } + notification.getValue().whenComplete((reader, ex) -> { + if (ex == null && reader != null) { + reader.closeAsync().whenComplete((v, e) -> { + if (e != null) { + log.error("[{}] Close reader error for reader cache expire", namespaceName, e); + } else { + if (log.isDebugEnabled()) { + log.debug("[{}] Reader is closed for reader cache expire.", + reader.getSystemTopic().getTopicName()); + } + } + }); + } else { + SystemTopicBasedTopicPoliciesService.this.readerCache.asMap().remove(namespaceName, notification.getValue()); + } + }); + }) + .build(new CacheLoader>() { + @Override + public CompletableFuture load(NamespaceName namespaceName) { + CompletableFuture readerFuture = loadSystemTopicReader(namespaceName); + readerFuture.whenComplete((r, cause) -> { + if (null != cause || r == null) { + readerCache.asMap().remove(namespaceName, readerFuture); + } + }); + return readerFuture; + } + }); + } + + @Override + public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies) { + createSystemTopicFactoryIfNeeded(); + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), + EventType.TOPIC_POLICY); + CompletableFuture result = new CompletableFuture<>(); + CompletableFuture writerFuture = systemTopic.newWriterAsync(); + writerFuture.whenComplete((writer, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); + } else { + writer.writeAsync( + PulsarEvent.builder() + .actionType(ActionType.UPDATE) + .eventType(EventType.TOPIC_POLICY) + .topicPoliciesEvent( + TopicPoliciesEvent.builder() + .domain(topicName.getDomain().toString()) + .tenant(topicName.getTenant()) + .namespace(topicName.getNamespaceObject().getLocalName()) + .topic(topicName.getLocalName()) + .policies(policies) + .build()) + .build()).whenComplete(((messageId, e) -> { + if (e != null) { + result.completeExceptionally(e); + } else { + if (messageId != null) { + result.complete(null); + } else { + result.completeExceptionally(new RuntimeException("Got message id is null.")); + } + } + writer.closeAsync().whenComplete((v, cause) -> { + if (cause != null) { + log.error("[{}] Close writer error.", topicName, cause); + } else { + if (log.isDebugEnabled()) { + log.debug("[{}] Close writer success.", topicName); + } + } + }); + }) + ); + } + }); + return result; + } + + @Override + public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { + CompletableFuture readerFuture = null; + try { + readerFuture = readerCache.get(topicName.getNamespaceObject()); + } catch (ExecutionException e) { + log.error("[{}] Load reader error.", topicName, e); + } + if (readerFuture == null) { + return CompletableFuture.completedFuture(null); + } + CompletableFuture result = new CompletableFuture<>(); + CompletableFuture refreshFuture = new CompletableFuture<>(); + refreshFuture.whenComplete((v, ex) -> result.complete(policiesCache.get(topicName))); + // Must ensure the reader is reach the end of system topic + // To ensure aways get the last topic policies + readerFuture.thenAccept(reader -> refreshCacheIfNeeded(reader, refreshFuture)); + return result; + } + + @Override + public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { + CompletableFuture result = new CompletableFuture<>(); + createSystemTopicFactoryIfNeeded(); + if (namespaceEventsSystemTopicFactory == null) { + result.complete(null); + return result; + } + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject() + , EventType.TOPIC_POLICY); + systemTopic.newReaderAsync().thenAccept(r -> + fetchTopicPoliciesAsyncAndCloseReader(r, topicName, null, result)); + return result; + } + + private CompletableFuture loadSystemTopicReader(NamespaceName namespaceName) { + createSystemTopicFactoryIfNeeded(); + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespaceName + , EventType.TOPIC_POLICY); + return systemTopic.newReaderAsync(); + } + + private void createSystemTopicFactoryIfNeeded() { + if (namespaceEventsSystemTopicFactory == null) { + synchronized (this) { + if (namespaceEventsSystemTopicFactory == null) { + try { + namespaceEventsSystemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarService.getClient()); + } catch (PulsarServerException e) { + log.error("Create namespace event system topic factory error.", e); + } + } + } + } + } + + private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture refreshFuture) { + reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { + if (ex != null) { + refreshFuture.completeExceptionally(ex); + readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); + } + if (hasMore) { + reader.readNextAsync().whenComplete((msg, e) -> { + if (e != null) { + refreshFuture.completeExceptionally(e); + readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); + } + if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { + TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); + policiesCache.put( + TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), + event.getPolicies() + ); + } + refreshCacheIfNeeded(reader, refreshFuture); + }); + } else { + refreshFuture.complete(null); + } + }); + } + + private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, TopicName topicName, TopicPolicies policies, + CompletableFuture future) { + reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { + if (ex != null) { + future.completeExceptionally(ex); + } + if (hasMore) { + reader.readNextAsync().whenComplete((msg, e) -> { + if (e != null) { + future.completeExceptionally(e); + } + if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { + TopicPoliciesEvent topicPoliciesEvent = msg.getValue().getTopicPoliciesEvent(); + if (topicName.equals(TopicName.get( + topicPoliciesEvent.getDomain(), + topicPoliciesEvent.getTenant(), + topicPoliciesEvent.getNamespace(), + topicPoliciesEvent.getTopic())) + ) { + fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, topicPoliciesEvent.getPolicies(), future); + } else { + fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, policies, future); + } + } + }); + } else { + future.complete(policies); + reader.closeAsync().whenComplete((v, e) -> { + if (e != null) { + log.error("[{}] Close reader error.", topicName, e); + } + }); + } + }); + } + + @VisibleForTesting + long getPoliciesCacheSize() { + return policiesCache.size(); + } + + @VisibleForTesting + long getReaderCacheCount() { + return readerCache.size(); + } + + @VisibleForTesting + boolean checkReaderIsCached(NamespaceName namespaceName) { + return readerCache.getIfPresent(namespaceName) != null; + } + + private static final Logger log = LoggerFactory.getLogger(SystemTopicBasedTopicPoliciesService.class); +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 95f37eb41947e..6ca7f6a28127b 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -18,269 +18,56 @@ */ package org.apache.pulsar.broker.service; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; -import org.apache.pulsar.broker.PulsarServerException; -import org.apache.pulsar.broker.PulsarService; -import org.apache.pulsar.client.api.MessageId; -import org.apache.pulsar.common.events.ActionType; -import org.apache.pulsar.common.events.EventType; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopic; -import org.apache.pulsar.common.events.PulsarEvent; -import org.apache.pulsar.common.events.TopicPoliciesEvent; -import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; +import org.apache.pulsar.common.util.FutureUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; /** * Topic policies service */ -public class TopicPoliciesService { +public interface TopicPoliciesService { - private final PulsarService pulsarService; - private NamespaceEventsSystemTopicFactory namespaceEventsSystemTopicFactory; + TopicPoliciesService DISABLED = new TopicPoliciesServiceDisabled(); - private final Map policiesCache = new ConcurrentHashMap<>(); + /** + * Update policies for a topic async + * @param topicName topic name + * @param policies policies for the topic name + */ + CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies); - private final LoadingCache> readerCache; + /** + * Get policies for a topic async + * @param topicName topic name + * @return future of the topic policies + */ + CompletableFuture getTopicPoliciesAsync(TopicName topicName); - public TopicPoliciesService(PulsarService pulsarService) { - this(pulsarService, 1000, 10, TimeUnit.MINUTES); - } + /** + * Get policies for a topic without cache async + * @param topicName topic name + * @return future of the topic policies + */ + CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName); - public TopicPoliciesService(PulsarService pulsarService, long cacheSize, long cacheExpireDuration, TimeUnit cacheExpireUnit) { - this.pulsarService = pulsarService; - this.readerCache = CacheBuilder.newBuilder() - .maximumSize(cacheSize) - .expireAfterAccess(cacheExpireDuration, cacheExpireUnit) - .removalListener((RemovalListener>) notification -> { - NamespaceName namespaceName = notification.getKey(); - if (log.isDebugEnabled()) { - log.debug("[{}] Reader cache was evicted, current reader cache size is {} ", namespaceName, - TopicPoliciesService.this.readerCache.asMap().size()); - } - policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespaceName)); - if (log.isDebugEnabled()) { - log.debug("[{}] Topic policies cache deleted success, current policies cache size is {} ", - namespaceName, policiesCache.size()); - } - notification.getValue().whenComplete((reader, ex) -> { - if (ex == null && reader != null) { - reader.closeAsync().whenComplete((v, e) -> { - if (e != null) { - log.error("[{}] Close reader error for reader cache expire", namespaceName, e); - } else { - if (log.isDebugEnabled()) { - log.debug("[{}] Reader is closed for reader cache expire.", - reader.getSystemTopic().getTopicName()); - } - } - }); - } else { - TopicPoliciesService.this.readerCache.asMap().remove(namespaceName, notification.getValue()); - } - }); - }) - .build(new CacheLoader>() { - @Override - public CompletableFuture load(NamespaceName namespaceName) { - CompletableFuture readerFuture = loadSystemTopicReader(namespaceName); - readerFuture.whenComplete((r, cause) -> { - if (null != cause || r == null) { - readerCache.asMap().remove(namespaceName, readerFuture); - } - }); - return readerFuture; - } - }); - } - public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies) { - createSystemTopicFactoryIfNeeded(); - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), - EventType.TOPIC_POLICY); - CompletableFuture result = new CompletableFuture<>(); - CompletableFuture writerFuture = systemTopic.newWriterAsync(); - writerFuture.whenComplete((writer, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); - } else { - writer.writeAsync( - PulsarEvent.builder() - .actionType(ActionType.UPDATE) - .eventType(EventType.TOPIC_POLICY) - .topicPoliciesEvent( - TopicPoliciesEvent.builder() - .domain(topicName.getDomain().toString()) - .tenant(topicName.getTenant()) - .namespace(topicName.getNamespaceObject().getLocalName()) - .topic(topicName.getLocalName()) - .policies(policies) - .build()) - .build()).whenComplete(((messageId, e) -> { - if (e != null) { - result.completeExceptionally(e); - } else { - result.complete(messageId); - } - writer.closeAsync().whenComplete((v, cause) -> { - if (cause != null) { - log.error("[{}] Close writer error.", topicName, cause); - } else { - if (log.isDebugEnabled()) { - log.debug("[{}] Close writer success.", topicName); - } - } - }); - }) - ); - } - }); - return result; - } + class TopicPoliciesServiceDisabled implements TopicPoliciesService { - public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { - CompletableFuture readerFuture = null; - try { - readerFuture = readerCache.get(topicName.getNamespaceObject()); - } catch (ExecutionException e) { - log.error("[{}] Load reader error.", topicName, e); - } - if (readerFuture == null) { - return CompletableFuture.completedFuture(null); + @Override + public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies) { + return FutureUtil.failedFuture(new UnsupportedOperationException("Topic policies service is disabled.")); } - CompletableFuture result = new CompletableFuture<>(); - CompletableFuture refreshFuture = new CompletableFuture<>(); - refreshFuture.whenComplete((v, ex) -> result.complete(policiesCache.get(topicName))); - readerFuture.thenAccept(reader -> refreshCacheIfNeeded(reader, refreshFuture)); - return result; - } - public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { - CompletableFuture result = new CompletableFuture<>(); - createSystemTopicFactoryIfNeeded(); - if (namespaceEventsSystemTopicFactory == null) { - result.complete(null); - return result; + @Override + public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { + return CompletableFuture.completedFuture(null); } - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject() - , EventType.TOPIC_POLICY); - systemTopic.newReaderAsync().thenAccept(r -> - fetchTopicPoliciesAsyncAndCloseReader(r, topicName, null, result)); - return result; - } - private CompletableFuture loadSystemTopicReader(NamespaceName namespaceName) { - createSystemTopicFactoryIfNeeded(); - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespaceName - , EventType.TOPIC_POLICY); - return systemTopic.newReaderAsync(); - } - - private void createSystemTopicFactoryIfNeeded() { - if (namespaceEventsSystemTopicFactory == null) { - synchronized (this) { - if (namespaceEventsSystemTopicFactory == null) { - try { - namespaceEventsSystemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarService.getClient()); - } catch (PulsarServerException e) { - log.error("Create namespace event system topic factory error.", e); - } - } - } + @Override + public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { + return CompletableFuture.completedFuture(null); } } - - private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture refreshFuture) { - reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { - if (ex != null) { - refreshFuture.completeExceptionally(ex); - readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); - } - if (hasMore) { - reader.readNextAsync().whenComplete((msg, e) -> { - if (e != null) { - refreshFuture.completeExceptionally(e); - readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); - } - if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { - TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); - policiesCache.put( - TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), - event.getPolicies() - ); - } - refreshCacheIfNeeded(reader, refreshFuture); - }); - } else { - refreshFuture.complete(null); - } - }); - } - - private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, TopicName topicName, TopicPolicies policies, - CompletableFuture future) { - reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { - if (ex != null) { - future.completeExceptionally(ex); - } - if (hasMore) { - reader.readNextAsync().whenComplete((msg, e) -> { - if (e != null) { - future.completeExceptionally(e); - } - if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { - TopicPoliciesEvent topicPoliciesEvent = msg.getValue().getTopicPoliciesEvent(); - if (topicName.equals(TopicName.get( - topicPoliciesEvent.getDomain(), - topicPoliciesEvent.getTenant(), - topicPoliciesEvent.getNamespace(), - topicPoliciesEvent.getTopic())) - ) { - fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, topicPoliciesEvent.getPolicies(), future); - } else { - fetchTopicPoliciesAsyncAndCloseReader(reader, topicName, policies, future); - } - } - }); - } else { - future.complete(policies); - reader.closeAsync().whenComplete((v, e) -> { - if (e != null) { - log.error("[{}] Close reader error.", topicName, e); - } - }); - } - }); - } - - @VisibleForTesting - long getPoliciesCacheSize() { - return policiesCache.size(); - } - - @VisibleForTesting - long getReaderCacheCount() { - return readerCache.size(); - } - - @VisibleForTesting - boolean checkReaderIsCached(NamespaceName namespaceName) { - return readerCache.getIfPresent(namespaceName) != null; - } - - private static final Logger log = LoggerFactory.getLogger(TopicPoliciesService.class); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java similarity index 63% rename from pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java rename to pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 9e6688708f1ce..e6d60af489861 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -37,7 +37,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -public class TopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { +public class SystemTopicBasedTopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { private static final String NAMESPACE1 = "system-topic/namespace-1"; private static final String NAMESPACE2 = "system-topic/namespace-2"; @@ -51,7 +51,7 @@ public class TopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { private static final TopicName TOPIC6 = TopicName.get("persistent", NamespaceName.get(NAMESPACE3), "topic-2"); private NamespaceEventsSystemTopicFactory systemTopicFactory; - private TopicPoliciesService topicPoliciesService; + private SystemTopicBasedTopicPoliciesService systemTopicBasedTopicPoliciesService; @BeforeMethod @Override @@ -73,44 +73,44 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In TopicPolicies policies1 = TopicPolicies.builder() .maxProducerPerTopic(1) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1).get(); // Update policy for TOPIC2 TopicPolicies policies2 = TopicPolicies.builder() .maxProducerPerTopic(2) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2).get(); // Update policy for TOPIC3 TopicPolicies policies3 = TopicPolicies.builder() .maxProducerPerTopic(3) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC3, policies3).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC3, policies3).get(); // Update policy for TOPIC4 TopicPolicies policies4 = TopicPolicies.builder() .maxProducerPerTopic(4) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC4, policies4).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC4, policies4).get(); // Update policy for TOPIC5 TopicPolicies policies5 = TopicPolicies.builder() .maxProducerPerTopic(5) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC5, policies5).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC5, policies5).get(); // Update policy for TOPIC6 TopicPolicies policies6 = TopicPolicies.builder() .maxProducerPerTopic(6) .build(); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC6, policies6).get(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC6, policies6).get(); - TopicPolicies policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); - TopicPolicies policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); - TopicPolicies policiesGet3 = topicPoliciesService.getTopicPoliciesAsync(TOPIC3).get(); - TopicPolicies policiesGet4 = topicPoliciesService.getTopicPoliciesAsync(TOPIC4).get(); - TopicPolicies policiesGet5 = topicPoliciesService.getTopicPoliciesAsync(TOPIC5).get(); - TopicPolicies policiesGet6 = topicPoliciesService.getTopicPoliciesAsync(TOPIC6).get(); + TopicPolicies policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); + TopicPolicies policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); + TopicPolicies policiesGet3 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC3).get(); + TopicPolicies policiesGet4 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC4).get(); + TopicPolicies policiesGet5 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC5).get(); + TopicPolicies policiesGet6 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC6).get(); Assert.assertEquals(policiesGet1, policies1); Assert.assertEquals(policiesGet2, policies2); @@ -120,42 +120,42 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertEquals(policiesGet6, policies6); // Only cache 2 readers, reader for NAMESPACE1 is evicted - Assert.assertEquals(topicPoliciesService.getReaderCacheCount(), 3 - 1); + Assert.assertEquals(systemTopicBasedTopicPoliciesService.getReaderCacheCount(), 3 - 1); // Remove reader cache will remove policies cache - Assert.assertEquals(topicPoliciesService.getPoliciesCacheSize(), 6 - 2); + Assert.assertEquals(systemTopicBasedTopicPoliciesService.getPoliciesCacheSize(), 6 - 2); // Check reader cache is correct. - Assert.assertFalse(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); - Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); - Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); + Assert.assertFalse(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); policies1.setMaxProducerPerTopic(101); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); policies2.setMaxProducerPerTopic(102); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies2.setMaxProducerPerTopic(103); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies1.setMaxProducerPerTopic(104); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); policies2.setMaxProducerPerTopic(105); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC2, policies2); policies1.setMaxProducerPerTopic(106); - topicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); // reader for NAMESPACE1 will back fill the reader cache - policiesGet1 = topicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); - policiesGet2 = topicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); + policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); + policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); Assert.assertEquals(policies1, policiesGet1); Assert.assertEquals(policies2, policiesGet2); // Check reader cache is correct. - Assert.assertFalse(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); - Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); - Assert.assertTrue(topicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); + Assert.assertFalse(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); // Check get without cache - policiesGet1 = topicPoliciesService.getTopicPoliciesWithoutCacheAsync(TOPIC1).get(); + policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesWithoutCacheAsync(TOPIC1).get(); Assert.assertEquals(policies1, policiesGet1); } @@ -167,6 +167,6 @@ private void prepareData() throws PulsarAdminException { admin.namespaces().createNamespace(NAMESPACE2); admin.namespaces().createNamespace(NAMESPACE3); systemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarClient); - topicPoliciesService = new TopicPoliciesService(pulsar, 2, 1, TimeUnit.MINUTES); + systemTopicBasedTopicPoliciesService = new SystemTopicBasedTopicPoliciesService(pulsar, 2, 1, TimeUnit.MINUTES); } } From 9a7ff6865435751c7c98798f1223d036b80c8b0b Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 10 Sep 2019 19:46:18 +0800 Subject: [PATCH 08/31] Use namespace bundle owned notify. --- .../broker/namespace/NamespaceService.java | 4 + .../broker/namespace/OwnershipCache.java | 4 + .../SystemTopicBasedTopicPoliciesService.java | 189 ++++++++---------- .../broker/service/TopicPoliciesService.java | 32 ++- ...temTopicBasedTopicPoliciesServiceTest.java | 38 ++-- 5 files changed, 147 insertions(+), 120 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java index 24d933d0f2b3f..b1f1febaecf5f 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java @@ -1162,6 +1162,10 @@ public void unloadSLANamespace() throws Exception { LOG.info("Namespace {} unloaded successfully", namespaceName); } + public String getHeartbeatNamespace() { + return getHeartbeatNamespace(host, config); + } + public static String getHeartbeatNamespace(String host, ServiceConfiguration config) { Integer port = null; if (config.getWebServicePort().isPresent()) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java index 50e96fadf51fb..a09bb15602da1 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java @@ -150,6 +150,10 @@ public CompletableFuture asyncLoad(String namespaceBundleZNode, Exe } } + public OwnershipCache(PulsarService pulsar, NamespaceBundleFactory bundleFactory) { + this(pulsar, bundleFactory, null); + } + /** * Constructor of OwnershipCache * diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 1216030723674..d3dde6dad7483 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -19,18 +19,17 @@ package org.apache.pulsar.broker.service; import com.google.common.annotations.VisibleForTesting; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalListener; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.client.api.Message; +import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.events.ActionType; import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.events.TopicPoliciesEvent; +import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; @@ -41,8 +40,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; /** * Cached topic policies service will cache the system topic reader and the topic policies @@ -56,57 +54,12 @@ public class SystemTopicBasedTopicPoliciesService implements TopicPoliciesServic private final Map policiesCache = new ConcurrentHashMap<>(); - private final LoadingCache> readerCache; + private final Map ownedBundlesCountPerNamespace = new ConcurrentHashMap<>(); - public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { - this(pulsarService, 1000, 30, TimeUnit.MINUTES); - } + private final Map> readerCaches = new ConcurrentHashMap<>(); - public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService, long cacheSize, long cacheExpireDuration, TimeUnit cacheExpireUnit) { + public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { this.pulsarService = pulsarService; - this.readerCache = CacheBuilder.newBuilder() - .maximumSize(cacheSize) - .expireAfterAccess(cacheExpireDuration, cacheExpireUnit) - .removalListener((RemovalListener>) notification -> { - NamespaceName namespaceName = notification.getKey(); - if (log.isDebugEnabled()) { - log.debug("[{}] Reader cache was evicted, current reader cache size is {} ", namespaceName, - SystemTopicBasedTopicPoliciesService.this.readerCache.asMap().size()); - } - policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespaceName)); - if (log.isDebugEnabled()) { - log.debug("[{}] Topic policies cache deleted success, current policies cache size is {} ", - namespaceName, policiesCache.size()); - } - notification.getValue().whenComplete((reader, ex) -> { - if (ex == null && reader != null) { - reader.closeAsync().whenComplete((v, e) -> { - if (e != null) { - log.error("[{}] Close reader error for reader cache expire", namespaceName, e); - } else { - if (log.isDebugEnabled()) { - log.debug("[{}] Reader is closed for reader cache expire.", - reader.getSystemTopic().getTopicName()); - } - } - }); - } else { - SystemTopicBasedTopicPoliciesService.this.readerCache.asMap().remove(namespaceName, notification.getValue()); - } - }); - }) - .build(new CacheLoader>() { - @Override - public CompletableFuture load(NamespaceName namespaceName) { - CompletableFuture readerFuture = loadSystemTopicReader(namespaceName); - readerFuture.whenComplete((r, cause) -> { - if (null != cause || r == null) { - readerCache.asMap().remove(namespaceName, readerFuture); - } - }); - return readerFuture; - } - }); } @Override @@ -159,23 +112,8 @@ public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, Top } @Override - public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { - CompletableFuture readerFuture = null; - try { - readerFuture = readerCache.get(topicName.getNamespaceObject()); - } catch (ExecutionException e) { - log.error("[{}] Load reader error.", topicName, e); - } - if (readerFuture == null) { - return CompletableFuture.completedFuture(null); - } - CompletableFuture result = new CompletableFuture<>(); - CompletableFuture refreshFuture = new CompletableFuture<>(); - refreshFuture.whenComplete((v, ex) -> result.complete(policiesCache.get(topicName))); - // Must ensure the reader is reach the end of system topic - // To ensure aways get the last topic policies - readerFuture.thenAccept(reader -> refreshCacheIfNeeded(reader, refreshFuture)); - return result; + public TopicPolicies getTopicPolicies(TopicName topicName) { + return policiesCache.get(topicName); } @Override @@ -193,54 +131,103 @@ public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicN return result; } - private CompletableFuture loadSystemTopicReader(NamespaceName namespaceName) { + @Override + public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle) { + CompletableFuture result = new CompletableFuture<>(); + NamespaceName namespace = namespaceBundle.getNamespaceObject(); + ownedBundlesCountPerNamespace.putIfAbsent(namespace, new AtomicInteger(0)); + ownedBundlesCountPerNamespace.get(namespace).incrementAndGet(); createSystemTopicFactoryIfNeeded(); - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespaceName + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace , EventType.TOPIC_POLICY); - return systemTopic.newReaderAsync(); + CompletableFuture readerFuture = systemTopic.newReaderAsync(); + readerCaches.put(namespace, readerFuture); + readerFuture.whenComplete((reader, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); + } else { + initPolicesCache(reader, result); + readMorePolicies(reader); + } + }); + return result; } - private void createSystemTopicFactoryIfNeeded() { - if (namespaceEventsSystemTopicFactory == null) { - synchronized (this) { - if (namespaceEventsSystemTopicFactory == null) { - try { - namespaceEventsSystemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarService.getClient()); - } catch (PulsarServerException e) { - log.error("Create namespace event system topic factory error.", e); - } - } - } + @Override + public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle) { + NamespaceName namespace = namespaceBundle.getNamespaceObject(); + AtomicInteger bundlesCount = ownedBundlesCountPerNamespace.get(namespace); + if (bundlesCount == null || bundlesCount.decrementAndGet() <= 0) { + readerCaches.remove(namespace).thenAccept(SystemTopic.Reader::closeAsync); + ownedBundlesCountPerNamespace.remove(namespace); + policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespace)); } + return CompletableFuture.completedFuture(null); } - private void refreshCacheIfNeeded(SystemTopic.Reader reader, CompletableFuture refreshFuture) { + private void initPolicesCache(SystemTopic.Reader reader, CompletableFuture future) { reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { - refreshFuture.completeExceptionally(ex); - readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); + future.completeExceptionally(ex); + readerCaches.remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); } if (hasMore) { reader.readNextAsync().whenComplete((msg, e) -> { if (e != null) { - refreshFuture.completeExceptionally(e); - readerCache.asMap().remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); - } - if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { - TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); - policiesCache.put( - TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), - event.getPolicies() - ); + future.completeExceptionally(e); + readerCaches.remove(reader.getSystemTopic().getTopicName().getNamespaceObject()); } - refreshCacheIfNeeded(reader, refreshFuture); + refreshTopicPoliciesCache(msg); + initPolicesCache(reader, future); }); } else { - refreshFuture.complete(null); + future.complete(null); + } + }); + } + + private void readMorePolicies(SystemTopic.Reader reader) { + reader.readNextAsync().whenComplete((msg, ex) -> { + if (ex == null) { + refreshTopicPoliciesCache(msg); + readMorePolicies(reader); + } else { + if (ex instanceof PulsarClientException.AlreadyClosedException) { + log.error("Read more topic policies exception, close the read now!", ex); + NamespaceName namespace = reader.getSystemTopic().getTopicName().getNamespaceObject(); + ownedBundlesCountPerNamespace.remove(namespace); + readerCaches.remove(namespace); + } else { + readMorePolicies(reader); + } } }); } + private void refreshTopicPoliciesCache(Message msg) { + if (EventType.TOPIC_POLICY.equals(msg.getValue().getEventType())) { + TopicPoliciesEvent event = msg.getValue().getTopicPoliciesEvent(); + policiesCache.put( + TopicName.get(event.getDomain(), event.getTenant(), event.getNamespace(), event.getTopic()), + event.getPolicies() + ); + } + } + + private void createSystemTopicFactoryIfNeeded() { + if (namespaceEventsSystemTopicFactory == null) { + synchronized (this) { + if (namespaceEventsSystemTopicFactory == null) { + try { + namespaceEventsSystemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarService.getClient()); + } catch (PulsarServerException e) { + log.error("Create namespace event system topic factory error.", e); + } + } + } + } + } + private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, TopicName topicName, TopicPolicies policies, CompletableFuture future) { reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { @@ -284,12 +271,12 @@ long getPoliciesCacheSize() { @VisibleForTesting long getReaderCacheCount() { - return readerCache.size(); + return readerCaches.size(); } @VisibleForTesting boolean checkReaderIsCached(NamespaceName namespaceName) { - return readerCache.getIfPresent(namespaceName) != null; + return readerCaches.get(namespaceName) != null; } private static final Logger log = LoggerFactory.getLogger(SystemTopicBasedTopicPoliciesService.class); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 6ca7f6a28127b..a88422f34ddc5 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -18,6 +18,7 @@ */ package org.apache.pulsar.broker.service; +import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; import org.apache.pulsar.common.util.FutureUtil; @@ -43,7 +44,7 @@ public interface TopicPoliciesService { * @param topicName topic name * @return future of the topic policies */ - CompletableFuture getTopicPoliciesAsync(TopicName topicName); + TopicPolicies getTopicPolicies(TopicName topicName); /** * Get policies for a topic without cache async @@ -52,6 +53,19 @@ public interface TopicPoliciesService { */ CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName); + /** + * Add owned namespace bundle async. + * + * @param namespaceBundle namespace bundle + */ + CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle); + + /** + * Remove owned namespace bundle async. + * + * @param namespaceBundle namespace bundle + */ + CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle); class TopicPoliciesServiceDisabled implements TopicPoliciesService { @@ -61,13 +75,25 @@ public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, Top } @Override - public CompletableFuture getTopicPoliciesAsync(TopicName topicName) { - return CompletableFuture.completedFuture(null); + public TopicPolicies getTopicPolicies(TopicName topicName) { + return null; } @Override public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { return CompletableFuture.completedFuture(null); } + + @Override + public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle) { + //No-op + return CompletableFuture.completedFuture(null); + } + + @Override + public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle) { + //No-op + return CompletableFuture.completedFuture(null); + } } } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index e6d60af489861..4577284d7c2bb 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -35,7 +35,6 @@ import org.testng.annotations.Test; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; public class SystemTopicBasedTopicPoliciesServiceTest extends MockedPulsarServiceBaseTest { @@ -67,7 +66,7 @@ protected void cleanup() throws Exception { } @Test - public void testGetPolicy() throws PulsarClientException, ExecutionException, InterruptedException { + public void testGetPolicy() throws ExecutionException, InterruptedException { // Update policy for TOPIC1 TopicPolicies policies1 = TopicPolicies.builder() @@ -105,12 +104,14 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In .build(); systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC6, policies6).get(); - TopicPolicies policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); - TopicPolicies policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); - TopicPolicies policiesGet3 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC3).get(); - TopicPolicies policiesGet4 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC4).get(); - TopicPolicies policiesGet5 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC5).get(); - TopicPolicies policiesGet6 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC6).get(); + Thread.sleep(1000); + + TopicPolicies policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC1); + TopicPolicies policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC2); + TopicPolicies policiesGet3 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC3); + TopicPolicies policiesGet4 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC4); + TopicPolicies policiesGet5 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC5); + TopicPolicies policiesGet6 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC6); Assert.assertEquals(policiesGet1, policies1); Assert.assertEquals(policiesGet2, policies2); @@ -120,13 +121,13 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertEquals(policiesGet6, policies6); // Only cache 2 readers, reader for NAMESPACE1 is evicted - Assert.assertEquals(systemTopicBasedTopicPoliciesService.getReaderCacheCount(), 3 - 1); + Assert.assertEquals(systemTopicBasedTopicPoliciesService.getReaderCacheCount(), 3); // Remove reader cache will remove policies cache - Assert.assertEquals(systemTopicBasedTopicPoliciesService.getPoliciesCacheSize(), 6 - 2); + Assert.assertEquals(systemTopicBasedTopicPoliciesService.getPoliciesCacheSize(), 6); // Check reader cache is correct. - Assert.assertFalse(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); @@ -143,14 +144,16 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In policies1.setMaxProducerPerTopic(106); systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); + Thread.sleep(2000); + // reader for NAMESPACE1 will back fill the reader cache - policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC1).get(); - policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPoliciesAsync(TOPIC2).get(); + policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC1); + policiesGet2 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC2); Assert.assertEquals(policies1, policiesGet1); Assert.assertEquals(policies2, policiesGet2); // Check reader cache is correct. - Assert.assertFalse(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); + Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE2))); Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE1))); Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); @@ -159,7 +162,7 @@ public void testGetPolicy() throws PulsarClientException, ExecutionException, In Assert.assertEquals(policies1, policiesGet1); } - private void prepareData() throws PulsarAdminException { + private void prepareData() throws PulsarAdminException, PulsarClientException { admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); admin.tenants().createTenant("system-topic", new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); @@ -167,6 +170,9 @@ private void prepareData() throws PulsarAdminException { admin.namespaces().createNamespace(NAMESPACE2); admin.namespaces().createNamespace(NAMESPACE3); systemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarClient); - systemTopicBasedTopicPoliciesService = new SystemTopicBasedTopicPoliciesService(pulsar, 2, 1, TimeUnit.MINUTES); + systemTopicBasedTopicPoliciesService = (SystemTopicBasedTopicPoliciesService) pulsar.getTopicPoliciesService(); + + // Broker need to own the namespace bundle + pulsarClient.newProducer().topic(TOPIC1.toString()).create(); } } From dd88848311a878b96b55af2722171e34830a6c0f Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 11 Sep 2019 19:03:52 +0800 Subject: [PATCH 09/31] Fix dead lock. --- .../broker/namespace/NamespaceService.java | 71 +++++++++++-------- .../SystemTopicBasedTopicPoliciesService.java | 39 ++++++---- ...temTopicBasedTopicPoliciesServiceTest.java | 20 ++++-- .../TopicPoliciesServiceDisableTest.java | 60 ++++++++++++++++ 4 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceDisableTest.java diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java index b1f1febaecf5f..5e3d4198e61b7 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java @@ -343,37 +343,12 @@ private CompletableFuture> findBrokerServiceUrl(Namespace targetMap = findingBundlesNotAuthoritative; } - return targetMap.computeIfAbsent(bundle, (k) -> { - CompletableFuture> future = new CompletableFuture<>(); - - // First check if we or someone else already owns the bundle - ownershipCache.getOwnerAsync(bundle).thenAccept(nsData -> { - if (!nsData.isPresent()) { - // No one owns this bundle + if (targetMap.get(bundle) != null && !targetMap.get(bundle).isDone()) { + return findBrokerServiceUrlInternal(bundle, authoritative, readOnly); + } - if (readOnly) { - // Do not attempt to acquire ownership - future.complete(Optional.empty()); - } else { - // Now, no one owns the namespace yet. Hence, we will try to dynamically assign it - pulsar.getExecutor().execute(() -> { - searchForCandidateBroker(bundle, future, authoritative); - }); - } - } else if (nsData.get().isDisabled()) { - future.completeExceptionally( - new IllegalStateException(String.format("Namespace bundle %s is being unloaded", bundle))); - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Namespace bundle {} already owned by {} ", bundle, nsData); - } - future.complete(Optional.of(new LookupResult(nsData.get()))); - } - }).exceptionally(exception -> { - LOG.warn("Failed to check owner for bundle {}: {}", bundle, exception.getMessage(), exception); - future.completeExceptionally(exception); - return null; - }); + return targetMap.computeIfAbsent(bundle, (k) -> { + CompletableFuture> future = findBrokerServiceUrlInternal(bundle, authoritative, readOnly); future.whenComplete((r, t) -> pulsar.getExecutor().execute( () -> targetMap.remove(bundle) @@ -383,6 +358,42 @@ private CompletableFuture> findBrokerServiceUrl(Namespace }); } + private CompletableFuture> findBrokerServiceUrlInternal(NamespaceBundle bundle, boolean authoritative, + boolean readOnly) { + CompletableFuture> future = new CompletableFuture<>(); + + // First check if we or someone else already owns the bundle + ownershipCache.getOwnerAsync(bundle).thenAccept(nsData -> { + if (!nsData.isPresent()) { + // No one owns this bundle + + if (readOnly) { + // Do not attempt to acquire ownership + future.complete(Optional.empty()); + } else { + // Now, no one owns the namespace yet. Hence, we will try to dynamically assign it + pulsar.getExecutor().execute(() -> { + searchForCandidateBroker(bundle, future, authoritative); + }); + } + } else if (nsData.get().isDisabled()) { + future.completeExceptionally( + new IllegalStateException(String.format("Namespace bundle %s is being unloaded", bundle))); + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Namespace bundle {} already owned by {} ", bundle, nsData); + } + future.complete(Optional.of(new LookupResult(nsData.get()))); + } + }).exceptionally(exception -> { + LOG.warn("Failed to check owner for bundle {}: {}", bundle, exception.getMessage(), exception); + future.completeExceptionally(exception); + return null; + }); + + return future; + } + private void searchForCandidateBroker(NamespaceBundle bundle, CompletableFuture> lookupFuture, boolean authoritative) { String candidateBroker = null; diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index d3dde6dad7483..717e1ef9a2cb6 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -64,10 +64,12 @@ public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { @Override public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, TopicPolicies policies) { + CompletableFuture result = new CompletableFuture<>(); + createSystemTopicFactoryIfNeeded(); SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), EventType.TOPIC_POLICY); - CompletableFuture result = new CompletableFuture<>(); + CompletableFuture writerFuture = systemTopic.newWriterAsync(); writerFuture.whenComplete((writer, ex) -> { if (ex != null) { @@ -138,18 +140,24 @@ public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle name ownedBundlesCountPerNamespace.putIfAbsent(namespace, new AtomicInteger(0)); ownedBundlesCountPerNamespace.get(namespace).incrementAndGet(); createSystemTopicFactoryIfNeeded(); - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace - , EventType.TOPIC_POLICY); - CompletableFuture readerFuture = systemTopic.newReaderAsync(); - readerCaches.put(namespace, readerFuture); - readerFuture.whenComplete((reader, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); + synchronized (this) { + if (readerCaches.get(namespace) != null) { + result.complete(null); } else { - initPolicesCache(reader, result); - readMorePolicies(reader); + SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace + , EventType.TOPIC_POLICY); + CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); + readerCaches.put(namespace, readerCompletableFuture); + readerCompletableFuture.whenComplete((reader, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); + } else { + initPolicesCache(reader, result); + readMorePolicies(reader); + } + }); } - }); + } return result; } @@ -158,9 +166,12 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n NamespaceName namespace = namespaceBundle.getNamespaceObject(); AtomicInteger bundlesCount = ownedBundlesCountPerNamespace.get(namespace); if (bundlesCount == null || bundlesCount.decrementAndGet() <= 0) { - readerCaches.remove(namespace).thenAccept(SystemTopic.Reader::closeAsync); - ownedBundlesCountPerNamespace.remove(namespace); - policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespace)); + CompletableFuture readerCompletableFuture = readerCaches.remove(namespace); + if (readerCompletableFuture != null) { + readerCompletableFuture.thenAccept(SystemTopic.Reader::closeAsync); + ownedBundlesCountPerNamespace.remove(namespace); + policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespace)); + } } return CompletableFuture.completedFuture(null); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 4577284d7c2bb..789f8db93f312 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -66,7 +66,20 @@ protected void cleanup() throws Exception { } @Test - public void testGetPolicy() throws ExecutionException, InterruptedException { + public void testGetPolicy() throws ExecutionException, InterruptedException, PulsarClientException { + // Init topic policies + for (int i = 1; i <= 10; i++) { + TopicPolicies initPolicy = TopicPolicies.builder() + .maxConsumerPerTopic(i) + .build(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, initPolicy).get(); + } + + // Broker need to own the namespace bundle + pulsarClient.newProducer().topic(TOPIC1.toString()).create(); + + // Assert broker is cache all topic policies + Assert.assertEquals(10, systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC1).getMaxConsumerPerTopic().intValue()); // Update policy for TOPIC1 TopicPolicies policies1 = TopicPolicies.builder() @@ -162,7 +175,7 @@ public void testGetPolicy() throws ExecutionException, InterruptedException { Assert.assertEquals(policies1, policiesGet1); } - private void prepareData() throws PulsarAdminException, PulsarClientException { + private void prepareData() throws PulsarAdminException { admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); admin.tenants().createTenant("system-topic", new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); @@ -171,8 +184,5 @@ private void prepareData() throws PulsarAdminException, PulsarClientException { admin.namespaces().createNamespace(NAMESPACE3); systemTopicFactory = new NamespaceEventsSystemTopicFactory(pulsarClient); systemTopicBasedTopicPoliciesService = (SystemTopicBasedTopicPoliciesService) pulsar.getTopicPoliciesService(); - - // Broker need to own the namespace bundle - pulsarClient.newProducer().topic(TOPIC1.toString()).create(); } } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceDisableTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceDisableTest.java new file mode 100644 index 0000000000000..d6d4d3a9cbcc0 --- /dev/null +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/TopicPoliciesServiceDisableTest.java @@ -0,0 +1,60 @@ +/** + * 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.broker.service; + +import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; + +import org.apache.pulsar.common.naming.TopicName; +import org.apache.pulsar.common.policies.data.TopicPolicies; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class TopicPoliciesServiceDisableTest extends MockedPulsarServiceBaseTest { + + private TopicPoliciesService systemTopicBasedTopicPoliciesService; + + @BeforeMethod + @Override + protected void setup() throws Exception { + conf.setTopicLevelPoliciesEnabled(false); + super.internalSetup(); + prepareData(); + } + + @AfterMethod + @Override + protected void cleanup() throws Exception { + super.internalCleanup(); + } + + @Test + public void testTopicLevelPoliciesDisabled() { + try { + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TopicName.get("test"), new TopicPolicies()).get(); + } catch (Exception e) { + Assert.assertTrue(e.getCause() instanceof UnsupportedOperationException); + } + } + + private void prepareData() { + systemTopicBasedTopicPoliciesService = pulsar.getTopicPoliciesService(); + } +} From bc5452aef5a8d4f1d58c06bed4f3792dd84852f2 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 11 Sep 2019 19:14:48 +0800 Subject: [PATCH 10/31] fix style --- .../main/java/org/apache/pulsar/common/events/ActionType.java | 2 +- .../main/java/org/apache/pulsar/common/events/EventType.java | 4 ++-- .../org/apache/pulsar/common/events/EventsTopicNames.java | 2 +- .../java/org/apache/pulsar/common/events/PulsarEvent.java | 3 +++ .../org/apache/pulsar/common/events/TopicPoliciesEvent.java | 3 +++ .../java/org/apache/pulsar/common/policies/data/Policies.java | 1 + .../org/apache/pulsar/common/policies/data/TopicPolicies.java | 4 ++-- 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java index ff48bbd31b385..0b626dcbd7232 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/ActionType.java @@ -19,7 +19,7 @@ package org.apache.pulsar.common.events; /** - * Pulsar event action type + * Pulsar event action type. */ public enum ActionType { diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java index 0bbd5cd95baa3..630d8e8cc44ee 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventType.java @@ -19,12 +19,12 @@ package org.apache.pulsar.common.events; /** - * Pulsar system event type + * Pulsar system event type. */ public enum EventType { /** - * Topic policy events + * Topic policy events. */ TOPIC_POLICY } diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java index 19cd30e9ee16a..72b66bb9d5f0c 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/EventsTopicNames.java @@ -19,7 +19,7 @@ package org.apache.pulsar.common.events; /** - * System topic name for the event type + * System topic name for the event type. */ public class EventsTopicNames { diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java index f8a5498e0b271..00e98ca679b3f 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/PulsarEvent.java @@ -23,6 +23,9 @@ import lombok.Data; import lombok.NoArgsConstructor; +/** + * Pulsar base event. + */ @Data @Builder @NoArgsConstructor diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java index e6ae7d9b0d4c1..995bd77b9f139 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/TopicPoliciesEvent.java @@ -24,6 +24,9 @@ import lombok.NoArgsConstructor; import org.apache.pulsar.common.policies.data.TopicPolicies; +/** + * Topic policies event. + */ @Data @Builder @NoArgsConstructor diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java index d54e0c73506d8..cdbafd6423b22 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java @@ -213,6 +213,7 @@ public String toString() { .add("message_ttl_in_seconds", message_ttl_in_seconds) .add("subscription_expiration_time_minutes", subscription_expiration_time_minutes) .add("retention_policies", retention_policies) + .add("message_ttl_in_seconds", message_ttl_in_seconds).add("retentionPolicies", retention_policies) .add("deleted", deleted) .add("encryption_required", encryption_required) .add("delayed_delivery_policies", delayed_delivery_policies) diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java index 9b1e581230446..16557877f4ab5 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java @@ -34,7 +34,7 @@ public class TopicPolicies { private Map backLogQuotaMap = Maps.newHashMap(); private PersistencePolicies persistence = null; - private RetentionPolicies retention_policies = null; + private RetentionPolicies retentionPolicies = null; private Boolean deduplicationEnabled = null; private Integer messageTTLInSeconds = null; private Integer maxProducerPerTopic = null; @@ -50,7 +50,7 @@ public boolean isPersistentPolicySet() { } public boolean isRetentionSet() { - return retention_policies != null; + return retentionPolicies != null; } public boolean isDeduplicationSet() { From a78986611326a4d4e17a131e3a4cccc1c1d67137 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 11 Sep 2019 19:18:46 +0800 Subject: [PATCH 11/31] fix style check --- .../pulsar/common/events/package-info.java | 19 +++++++++++++++++++ .../common/policies/data/TopicPolicies.java | 7 ++++++- 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 pulsar-common/src/main/java/org/apache/pulsar/common/events/package-info.java diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/events/package-info.java b/pulsar-common/src/main/java/org/apache/pulsar/common/events/package-info.java new file mode 100644 index 0000000000000..240ba51c07bb1 --- /dev/null +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/events/package-info.java @@ -0,0 +1,19 @@ +/** + * 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.events; \ No newline at end of file diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java index 16557877f4ab5..998e0c003ee4a 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java @@ -19,13 +19,18 @@ package org.apache.pulsar.common.policies.data; import com.google.common.collect.Maps; + +import java.util.Map; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Map; +/** + * Topic policies. + */ @Data @Builder @NoArgsConstructor From 25acfba0c9e10348c4c38026c481a99ea8ce4448 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 12 Sep 2019 18:51:10 +0800 Subject: [PATCH 12/31] fix unit tests. --- .../broker/admin/impl/NamespacesBase.java | 5 +- .../pulsar/broker/service/BrokerService.java | 3 +- .../NamespaceEventsSystemTopicFactory.java | 14 ++- .../pulsar/broker/systopic/SystemTopic.java | 5 + .../pulsar/broker/admin/AdminApiTest.java | 95 ++++++++++++++++--- 5 files changed, 104 insertions(+), 18 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java index 8a04adf3c3dff..fd529eb72d48c 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java @@ -60,6 +60,7 @@ import org.apache.pulsar.broker.service.Topic; import org.apache.pulsar.broker.service.persistent.PersistentReplicator; import org.apache.pulsar.broker.service.persistent.PersistentTopic; +import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.broker.web.RestException; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.common.naming.NamespaceBundle; @@ -1990,13 +1991,13 @@ private void clearBacklog(NamespaceName nsName, String bundleRange, String subsc subscription = PersistentReplicator.getRemoteCluster(subscription); } for (Topic topic : topicList) { - if (topic instanceof PersistentTopic) { + if (topic instanceof PersistentTopic && !SystemTopic.isSystemTopic(TopicName.get(topic.getName()))) { futures.add(((PersistentTopic) topic).clearBacklog(subscription)); } } } else { for (Topic topic : topicList) { - if (topic instanceof PersistentTopic) { + if (topic instanceof PersistentTopic && !SystemTopic.isSystemTopic(TopicName.get(topic.getName()))) { futures.add(((PersistentTopic) topic).clearBacklog()); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java index eb8d6d275dc2a..bdf63c2e5481d 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java @@ -104,6 +104,7 @@ import org.apache.pulsar.broker.stats.ClusterReplicationMetrics; import org.apache.pulsar.broker.stats.prometheus.metrics.Summary; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; +import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.broker.web.PulsarWebResource; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect.EventListner; @@ -2234,6 +2235,6 @@ private AutoSubscriptionCreationOverride getAutoSubscriptionCreationOverride(fin return null; } private boolean isSystemTopic(String topic) { - return EventsTopicNames.NAMESPACE_EVENTS_LOCAL_NAME.equals(TopicName.get(topic).getLocalName()); + return SystemTopic.isSystemTopic(TopicName.get(topic)); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java index 85c95dcee7d52..8943521d68411 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java @@ -35,12 +35,20 @@ public NamespaceEventsSystemTopicFactory(PulsarClient client) { } public SystemTopic createSystemTopic(NamespaceName namespaceName, EventType eventType) { + TopicName topicName = getSystemTopicName(namespaceName, eventType); + if (topicName != null) { + log.info("Create system topic {} for {}", topicName.toString(), eventType); + return new TopicPoliciesSystemTopic(client, topicName); + } else { + return null; + } + } + + public static TopicName getSystemTopicName(NamespaceName namespaceName, EventType eventType) { switch (eventType) { case TOPIC_POLICY: - TopicName topicName = TopicName.get("persistent", namespaceName, + return TopicName.get("persistent", namespaceName, EventsTopicNames.NAMESPACE_EVENTS_LOCAL_NAME); - log.info("Create system topic {} for topic policy.", topicName.toString()); - return new TopicPoliciesSystemTopic(client, topicName); default: return null; } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java index 69cc2c59c28d9..0e5efed7f20d8 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java @@ -21,6 +21,7 @@ import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.MessageId; import org.apache.pulsar.client.api.PulsarClientException; +import org.apache.pulsar.common.events.EventsTopicNames; import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.naming.TopicName; @@ -167,4 +168,8 @@ interface Reader { SystemTopic getSystemTopic(); } + static boolean isSystemTopic(TopicName topicName) { + return EventsTopicNames.NAMESPACE_EVENTS_LOCAL_NAME.equals(topicName.getLocalName()); + } + } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java index eb4dad7e78e03..a9afc2e5bf042 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java @@ -74,6 +74,8 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.service.BrokerService; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; +import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.client.admin.LongRunningProcessStatus; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; @@ -94,6 +96,7 @@ import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.client.api.SubscriptionType; +import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.lookup.data.LookupData; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; @@ -720,6 +723,10 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc } assertTrue(i < 10); + // Delete system topic first. + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString(), true); + admin.namespaces().deleteNamespace("prop-xyz/ns1"); assertEquals(admin.namespaces().getNamespaces("prop-xyz"), Lists.newArrayList("prop-xyz/ns2")); @@ -747,8 +754,15 @@ public void persistentTopics(String topicName) throws Exception { final String persistentTopicName = "persistent://prop-xyz/ns1/" + topicName; // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/" + topicName, 0); - assertEquals(admin.topics().getList("prop-xyz/ns1"), - Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); + + List topicList = admin.topics().getList("prop-xyz/ns1"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -827,7 +841,14 @@ public void persistentTopics(String topicName) throws Exception { } catch (NotFoundException e) { } - assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList()); + topicList = admin.topics().getList("prop-xyz/ns1"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList()); } @Test(dataProvider = "topicName") @@ -896,7 +917,14 @@ public void partitionedTopics(String topicName) throws Exception { producer.send(message.getBytes()); } - assertEquals(Sets.newHashSet(admin.topics().getList("prop-xyz/ns1")), + List topicList = admin.topics().getList("prop-xyz/ns1"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(Sets.newHashSet(topicList), Sets.newHashSet(partitionedTopicName + "-partition-0", partitionedTopicName + "-partition-1", partitionedTopicName + "-partition-2", partitionedTopicName + "-partition-3")); @@ -950,7 +978,8 @@ public void partitionedTopics(String topicName) throws Exception { .create(); topics = admin.topics().getList("prop-xyz/ns1"); - assertEquals(topics.size(), 4); + // 4 partitions and 1 system topic + assertEquals(topics.size(), 4 + 1); try { admin.topics().deletePartitionedTopic(partitionedTopicName); @@ -1068,8 +1097,18 @@ public void testDeleteNamespaceBundle(Integer numBundles) throws Exception { admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds3"); admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds4"); - assertEquals(admin.namespaces().getTopics("prop-xyz/ns1-bundles"), Lists.newArrayList()); + List topicList = admin.topics().getList("prop-xyz/ns1-bundles"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1-bundles"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList()); + // Delete system topic first + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1-bundles"), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/ns1-bundles"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "test"), Lists.newArrayList()); } @@ -1086,7 +1125,15 @@ public void testNamespaceSplitBundle() throws Exception { .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); + + List topicList = admin.topics().getList(namespace); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, null); @@ -1205,7 +1252,15 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); + + List topicList = admin.topics().getList(namespace); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", false, null); @@ -1347,8 +1402,15 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1-bundles/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/ns1-bundles"), - Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); + + List topicList = admin.topics().getList("prop-xyz/ns1"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); // create consumer and subscription Consumer consumer = pulsarClient.newConsumer().topic("persistent://prop-xyz/ns1-bundles/ds2") @@ -1917,7 +1979,8 @@ public void partitionedTopicsCursorReset(String topicName) throws Exception { .acknowledgmentGroupTime(0, TimeUnit.SECONDS).subscribe(); List topics = admin.topics().getList("prop-xyz/ns1"); - assertEquals(topics.size(), 4); + // 4 partition and 1 system topic + assertEquals(topics.size(), 4 + 1); assertEquals(admin.topics().getSubscriptions(topicName), Lists.newArrayList("my-sub")); @@ -1961,7 +2024,15 @@ public void persistentTopicsInvalidCursorReset() throws Exception { String topicName = "persistent://prop-xyz/ns1/invalidcursorreset"; // Force to create a topic publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList(topicName)); + + List topicList = admin.topics().getList("prop-xyz/ns1"); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + + assertEquals(topicList, Lists.newArrayList(topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() From 33d19dbc85689779e1b1b85f200b1dfd0da0e6b3 Mon Sep 17 00:00:00 2001 From: Penghui Li Date: Sat, 14 Sep 2019 16:46:27 +0800 Subject: [PATCH 13/31] fix unit tests --- .../pulsar/broker/admin/AdminApiTest.java | 78 +++---------------- .../broker/admin/v1/V1_AdminApiTest.java | 40 ++++++---- .../auth/MockedPulsarServiceBaseTest.java | 16 ++++ 3 files changed, 55 insertions(+), 79 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java index a9afc2e5bf042..27448c0ebae5d 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java @@ -755,14 +755,8 @@ public void persistentTopics(String topicName) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/" + topicName, 0); - List topicList = admin.topics().getList("prop-xyz/ns1"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), + Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -841,14 +835,7 @@ public void persistentTopics(String topicName) throws Exception { } catch (NotFoundException e) { } - topicList = admin.topics().getList("prop-xyz/ns1"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList()); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList()); } @Test(dataProvider = "topicName") @@ -917,14 +904,7 @@ public void partitionedTopics(String topicName) throws Exception { producer.send(message.getBytes()); } - List topicList = admin.topics().getList("prop-xyz/ns1"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(Sets.newHashSet(topicList), + assertEquals(Sets.newHashSet(getTopicListAndTrimSystemTopic("prop-xyz/ns1")), Sets.newHashSet(partitionedTopicName + "-partition-0", partitionedTopicName + "-partition-1", partitionedTopicName + "-partition-2", partitionedTopicName + "-partition-3")); @@ -1097,14 +1077,7 @@ public void testDeleteNamespaceBundle(Integer numBundles) throws Exception { admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds3"); admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds4"); - List topicList = admin.topics().getList("prop-xyz/ns1-bundles"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1-bundles"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList()); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1-bundles"), Lists.newArrayList()); // Delete system topic first admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1-bundles"), @@ -1126,14 +1099,7 @@ public void testNamespaceSplitBundle() throws Exception { producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - List topicList = admin.topics().getList(namespace); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, null); @@ -1253,14 +1219,7 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - List topicList = admin.topics().getList(namespace); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", false, null); @@ -1340,7 +1299,7 @@ public void testNamespaceUnloadBundle() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/ns1"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList("persistent://prop-xyz/ns1/ds2")); // create consumer and subscription @@ -1403,14 +1362,8 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1-bundles/ds2", 0); - List topicList = admin.topics().getList("prop-xyz/ns1"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1-bundles"), + Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); // create consumer and subscription Consumer consumer = pulsarClient.newConsumer().topic("persistent://prop-xyz/ns1-bundles/ds2") @@ -2025,14 +1978,7 @@ public void persistentTopicsInvalidCursorReset() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic(topicName, 0); - List topicList = admin.topics().getList("prop-xyz/ns1"); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); - - assertEquals(topicList, Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList(topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -2109,7 +2055,7 @@ public void testPersistentTopicsExpireMessages() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/ns1"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList("persistent://prop-xyz/ns1/ds2")); // create consumer and subscription diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java index 2ddff57d54b1c..5d86a27fb09b3 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java @@ -56,6 +56,7 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.service.BrokerService; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.LongRunningProcessStatus; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; @@ -74,6 +75,7 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.client.api.SubscriptionType; +import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.lookup.data.LookupData; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; @@ -576,7 +578,9 @@ public void properties() throws PulsarAdminException { admin.tenants().updateTenant("prop-xyz", newPropertyAdmin); assertEquals(admin.tenants().getTenantInfo("prop-xyz"), newPropertyAdmin); - + // Delete system topic first. + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); admin.tenants().deleteTenant("prop-xyz"); assertEquals(admin.tenants().getTenants(), Lists.newArrayList()); @@ -677,6 +681,9 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc } assertTrue(i < 10); + // Delete system topic first. + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "use"), Lists.newArrayList("prop-xyz/use/ns2")); @@ -703,7 +710,7 @@ public void persistentTopics(String topicName) throws Exception { final String persistentTopicName = "persistent://prop-xyz/use/ns1/" + topicName; // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/" + topicName, 0); - assertEquals(admin.topics().getList("prop-xyz/use/ns1"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/" + topicName)); // create consumer and subscription @@ -772,7 +779,7 @@ public void persistentTopics(String topicName) throws Exception { } catch (NotFoundException e) { } - assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList()); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList()); } @Test(dataProvider = "topicName") @@ -835,7 +842,7 @@ public void partitionedTopics(String topicName) throws Exception { producer.send(message.getBytes()); } - assertEquals(Sets.newHashSet(admin.topics().getList("prop-xyz/use/ns1")), + assertEquals(Sets.newHashSet(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1")), Sets.newHashSet(partitionedTopicName + "-partition-0", partitionedTopicName + "-partition-1", partitionedTopicName + "-partition-2", partitionedTopicName + "-partition-3")); @@ -889,7 +896,8 @@ public void partitionedTopics(String topicName) throws Exception { .create(); topics = admin.topics().getList("prop-xyz/use/ns1"); - assertEquals(topics.size(), 4); + // 4 partitions and 1 system topic + assertEquals(topics.size(), 4 + 1); try { admin.topics().deletePartitionedTopic(partitionedTopicName); @@ -933,8 +941,11 @@ public void testDeleteNamespaceBundle(Integer numBundles) throws Exception { admin.lookups().lookupTopic("persistent://prop-xyz/use/ns1-bundles/ds3"); admin.lookups().lookupTopic("persistent://prop-xyz/use/ns1-bundles/ds4"); - assertEquals(admin.namespaces().getTopics("prop-xyz/use/ns1-bundles"), Lists.newArrayList()); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1-bundles"), Lists.newArrayList()); + // Delete system topic first. + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1-bundles"), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1-bundles"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "use"), Lists.newArrayList()); } @@ -951,7 +962,7 @@ public void testNamespaceSplitBundle() throws Exception { .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, null); @@ -981,7 +992,7 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", false, null); @@ -1089,7 +1100,7 @@ public void testNamespaceUnloadBundle() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/use/ns1"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/ds2")); // create consumer and subscription @@ -1150,7 +1161,7 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1-bundles/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/use/ns1-bundles"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1-bundles"), Lists.newArrayList("persistent://prop-xyz/use/ns1-bundles/ds2")); // create consumer and subscription @@ -1446,6 +1457,9 @@ public void testBackwardCompatiblity() throws Exception { assertEquals(result.someNewIntField, 0); assertNull(result.someNewString); + // Delete system topic first. + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); admin.tenants().deleteTenant("prop-xyz"); assertEquals(admin.tenants().getTenants(), Lists.newArrayList()); @@ -1591,7 +1605,7 @@ public void partitionedTopicsCursorReset(String topicName) throws Exception { .subscriptionType(SubscriptionType.Exclusive) .acknowledgmentGroupTime(0, TimeUnit.SECONDS).subscribe(); - List topics = admin.topics().getList("prop-xyz/use/ns1"); + List topics = getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"); assertEquals(topics.size(), 4); assertEquals(admin.topics().getSubscriptions(topicName), Lists.newArrayList("my-sub")); @@ -1636,7 +1650,7 @@ public void persistentTopicsInvalidCursorReset() throws Exception { String topicName = "persistent://prop-xyz/use/ns1/invalidcursorreset"; // Force to create a topic publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList(topicName)); + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList(topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -1713,7 +1727,7 @@ public void testPersistentTopicsExpireMessages() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/ds2", 0); - assertEquals(admin.topics().getList("prop-xyz/use/ns1"), + assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/ds2")); // create consumer and subscription diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java index 53e629be4e386..f2dd39e544d2b 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.testng.Assert.assertTrue; import com.google.common.collect.Sets; import com.google.common.util.concurrent.MoreExecutors; @@ -49,12 +50,17 @@ import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.ServiceConfiguration; import org.apache.pulsar.broker.namespace.NamespaceService; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; +import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.policies.data.ClusterData; import org.apache.pulsar.common.policies.data.TenantInfo; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.common.naming.NamespaceName; +import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.compaction.Compactor; import org.apache.pulsar.zookeeper.ZooKeeperClientFactory; import org.apache.pulsar.zookeeper.ZookeeperClientFactoryImpl; @@ -329,5 +335,15 @@ public static void setFieldValue(Class clazz, Object classObj, String fieldNa field.set(classObj, fieldValue); } + protected List getTopicListAndTrimSystemTopic(String namespace) throws PulsarAdminException { + List topicList = admin.topics().getList(namespace); + + // Check topic policy system topic and then delete them + assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString())); + topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + return topicList; + } + private static final Logger log = LoggerFactory.getLogger(MockedPulsarServiceBaseTest.class); } From 46af3acda30cfcd90c70624d472bbccb435c9952 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Mon, 16 Sep 2019 15:41:34 +0800 Subject: [PATCH 14/31] fix unit tests. --- .../SystemTopicBasedTopicPoliciesService.java | 20 +++++++----- .../pulsar/broker/admin/NamespacesTest.java | 11 +++++-- .../broker/service/BrokerServiceTest.java | 2 +- .../service/PersistentTopicE2ETest.java | 5 +++ .../broker/stats/PrometheusMetricsTest.java | 31 +++++++++++++++++-- .../proxy/ProxyPublishConsumeTest.java | 6 ++++ 6 files changed, 63 insertions(+), 12 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 717e1ef9a2cb6..879fa74f5b027 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -146,14 +146,20 @@ public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle name } else { SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace , EventType.TOPIC_POLICY); - CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); - readerCaches.put(namespace, readerCompletableFuture); - readerCompletableFuture.whenComplete((reader, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); + pulsarService.getBrokerService().getTopic(systemTopic.getTopicName().toString(), true).whenComplete((p, e) -> { + if (e == null) { + CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); + readerCaches.put(namespace, readerCompletableFuture); + readerCompletableFuture.whenComplete((reader, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); + } else { + initPolicesCache(reader, result); + readMorePolicies(reader); + } + }); } else { - initPolicesCache(reader, result); - readMorePolicies(reader); + result.completeExceptionally(e); } }); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java index 2df24bb2e4358..1a1c7c1234b88 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java @@ -68,12 +68,14 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.namespace.OwnershipCache; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.web.PulsarWebResource; import org.apache.pulsar.broker.web.RestException; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.SubscriptionType; +import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundles; import org.apache.pulsar.common.naming.NamespaceName; @@ -1038,9 +1040,12 @@ public void testDeleteNamespace() throws Exception { NamespaceBundle bundle1 = pulsar.getNamespaceService().getBundle(topic); // (2) Delete topic admin.topics().delete(topicName); - // (3) Delete ns + // (3) Delete system topic + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString(), true); + // (4) Delete ns admin.namespaces().deleteNamespace(namespace); - // (4) check bundle + // (5) check bundle NamespaceBundle bundle2 = pulsar.getNamespaceService().getBundle(topic); assertNotEquals(bundle1.getBundleRange(), bundle2.getBundleRange()); // returns full bundle if policies not present @@ -1086,6 +1091,8 @@ public void testSubscribeRate() throws Exception { assertTrue(consumer.isConnected()); pulsar.getConfiguration().setAuthorizationEnabled(true); admin.topics().deletePartitionedTopic(topicName, true); + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespace); admin.tenants().deleteTenant("my-tenants"); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java index a2f27822d0008..c24cbb0c31301 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java @@ -415,7 +415,7 @@ public void testBrokerServiceNamespaceStats() throws Exception { for (String ns : nsList) { List topics = admin.namespaces().getTopics(ns); for (String dest : topics) { - admin.topics().delete(dest); + admin.topics().delete(dest, true); } admin.namespaces().deleteNamespace(ns); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java index 38e85d81a135e..dde656237c549 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java @@ -52,6 +52,7 @@ import org.apache.pulsar.broker.service.persistent.PersistentSubscription; import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.broker.service.schema.SchemaRegistry; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.CompressionType; import org.apache.pulsar.client.api.Consumer; @@ -75,6 +76,8 @@ import org.apache.pulsar.client.impl.TypedMessageBuilderImpl; import org.apache.pulsar.client.impl.schema.JSONSchema; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.RetentionPolicies; import org.apache.pulsar.common.protocol.schema.SchemaData; @@ -903,6 +906,8 @@ public void testMessageExpiry() throws Exception { consumer.close(); admin.topics().deleteSubscription(topicName, subName); admin.topics().delete(topicName); + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespaceName), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespaceName); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java index 81ecfc90e8d3a..37f793741936f 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java @@ -32,10 +32,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; import org.apache.pulsar.broker.service.BrokerTestBase; import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsGenerator; import org.apache.pulsar.client.api.Consumer; +import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.client.api.Producer; +import org.apache.pulsar.common.naming.TopicName; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -100,14 +103,35 @@ public void testPerTopicStats() throws Exception { // There should be 2 metrics with different tags for each topic List cm = (List) metrics.get("pulsar_storage_write_latency_le_1"); - assertEquals(cm.size(), 2); + // 2 topics and 1 system topic + assertEquals(cm.size(), 2 + 1); + cm.removeIf(f -> { + String topicName = f.tags.get("topic"); + if (StringUtils.isNotBlank(topicName)) { + return SystemTopic.isSystemTopic(TopicName.get(topicName)); + } else { + return false; + } + }); assertEquals(cm.get(0).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic2"); assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); assertEquals(cm.get(1).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic1"); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); cm = (List) metrics.get("pulsar_producers_count"); - assertEquals(cm.size(), 3); + + // 3 topics and 1 system topic + assertEquals(cm.size(), 3 + 1); + cm.removeIf(f -> { + String topicName = f.tags.get("topic"); + if (StringUtils.isNotBlank(topicName)) { + return SystemTopic.isSystemTopic(TopicName.get(topicName)); + } else { + return false; + } + }); + assertEquals(cm.get(1).value, 1.0); + assertEquals(cm.get(1).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic2"); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); assertEquals(cm.get(2).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic1"); @@ -115,6 +139,9 @@ public void testPerTopicStats() throws Exception { cm = (List) metrics.get("topic_load_times_count"); assertEquals(cm.size(), 1); + + // add 1.0 for system topic + assertEquals(cm.get(0).value, 2.0 + 1.0); assertEquals(cm.get(0).tags.get("cluster"), "test"); cm = (List) metrics.get("pulsar_in_bytes_total"); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java index 009596f074628..3abbadc07c584 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java @@ -48,7 +48,11 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import org.apache.bookkeeper.test.PortManager; +import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.api.ProducerConsumerBase; +import org.apache.pulsar.common.events.EventType; +import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.policies.data.BacklogQuota; import org.apache.pulsar.common.stats.Metrics; import org.apache.pulsar.websocket.WebSocketService; @@ -344,6 +348,8 @@ public void producerBacklogQuotaExceededTest() throws Exception { admin.topics().skipAllMessages("persistent://" + topic, subscription); admin.topics().delete("persistent://" + topic); admin.namespaces().removeBacklogQuota(namespace); + admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), + EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespace); } } From 3049ffdf19ee4fc7c71f418ff5f8c639229795c3 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Mon, 16 Sep 2019 16:40:41 +0800 Subject: [PATCH 15/31] fix unit tests. --- .../SystemTopicBasedTopicPoliciesService.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 879fa74f5b027..717e1ef9a2cb6 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -146,20 +146,14 @@ public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle name } else { SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace , EventType.TOPIC_POLICY); - pulsarService.getBrokerService().getTopic(systemTopic.getTopicName().toString(), true).whenComplete((p, e) -> { - if (e == null) { - CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); - readerCaches.put(namespace, readerCompletableFuture); - readerCompletableFuture.whenComplete((reader, ex) -> { - if (ex != null) { - result.completeExceptionally(ex); - } else { - initPolicesCache(reader, result); - readMorePolicies(reader); - } - }); + CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); + readerCaches.put(namespace, readerCompletableFuture); + readerCompletableFuture.whenComplete((reader, ex) -> { + if (ex != null) { + result.completeExceptionally(ex); } else { - result.completeExceptionally(e); + initPolicesCache(reader, result); + readMorePolicies(reader); } }); } From bc950f3549615d36ad22ec57f9326664479f1f0c Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 26 Sep 2019 15:08:42 +0800 Subject: [PATCH 16/31] fix unit tests --- .../apache/pulsar/broker/namespace/NamespaceService.java | 4 ---- .../org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java index 5e3d4198e61b7..b62aa791eb2b9 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java @@ -343,10 +343,6 @@ private CompletableFuture> findBrokerServiceUrl(Namespace targetMap = findingBundlesNotAuthoritative; } - if (targetMap.get(bundle) != null && !targetMap.get(bundle).isDone()) { - return findBrokerServiceUrlInternal(bundle, authoritative, readOnly); - } - return targetMap.computeIfAbsent(bundle, (k) -> { CompletableFuture> future = findBrokerServiceUrlInternal(bundle, authoritative, readOnly); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java index 5d86a27fb09b3..8efa4e8028c50 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java @@ -578,9 +578,7 @@ public void properties() throws PulsarAdminException { admin.tenants().updateTenant("prop-xyz", newPropertyAdmin); assertEquals(admin.tenants().getTenantInfo("prop-xyz"), newPropertyAdmin); - // Delete system topic first. - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), - EventType.TOPIC_POLICY).toString(), true); + admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); admin.tenants().deleteTenant("prop-xyz"); assertEquals(admin.tenants().getTenants(), Lists.newArrayList()); @@ -1457,9 +1455,6 @@ public void testBackwardCompatiblity() throws Exception { assertEquals(result.someNewIntField, 0); assertNull(result.someNewString); - // Delete system topic first. - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); admin.tenants().deleteTenant("prop-xyz"); assertEquals(admin.tenants().getTenants(), Lists.newArrayList()); From 7bdd8aa78cf9431b6500fb55dc035c63f7aec1f8 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 8 Oct 2019 11:22:22 +0800 Subject: [PATCH 17/31] Add SystemTopic extends PersistentTopic. --- .../broker/admin/impl/NamespacesBase.java | 6 +-- .../pulsar/broker/service/BrokerService.java | 42 +++------------ .../SystemTopicBasedTopicPoliciesService.java | 28 +++++----- .../broker/service/TopicPoliciesService.java | 4 +- .../service/persistent/PersistentTopic.java | 41 +++++++++------ .../service/persistent/SystemTopic.java | 52 +++++++++++++++++++ .../NamespaceEventsSystemTopicFactory.java | 4 +- ...ystemTopic.java => SystemTopicClient.java} | 6 +-- ...icBase.java => SystemTopicClientBase.java} | 6 +-- ...va => TopicPoliciesSystemTopicClient.java} | 28 +++++----- .../pulsar/broker/admin/AdminApiTest.java | 1 - .../auth/MockedPulsarServiceBaseTest.java | 4 +- ...temTopicBasedTopicPoliciesServiceTest.java | 2 +- .../broker/stats/PrometheusMetricsTest.java | 5 +- ...NamespaceEventsSystemTopicServiceTest.java | 28 +++++----- .../pulsar/common/policies/data/Policies.java | 7 ++- .../common/policies/data/TopicPolicies.java | 2 +- 17 files changed, 152 insertions(+), 114 deletions(-) create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/SystemTopic.java rename pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/{SystemTopic.java => SystemTopicClient.java} (97%) rename pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/{SystemTopicBase.java => SystemTopicClientBase.java} (95%) rename pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/{TopicPoliciesSystemTopic.java => TopicPoliciesSystemTopicClient.java} (86%) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java index fd529eb72d48c..9b5794e4e440e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java @@ -60,7 +60,7 @@ import org.apache.pulsar.broker.service.Topic; import org.apache.pulsar.broker.service.persistent.PersistentReplicator; import org.apache.pulsar.broker.service.persistent.PersistentTopic; -import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.broker.web.RestException; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.common.naming.NamespaceBundle; @@ -1991,13 +1991,13 @@ private void clearBacklog(NamespaceName nsName, String bundleRange, String subsc subscription = PersistentReplicator.getRemoteCluster(subscription); } for (Topic topic : topicList) { - if (topic instanceof PersistentTopic && !SystemTopic.isSystemTopic(TopicName.get(topic.getName()))) { + if (topic instanceof PersistentTopic && !SystemTopicClient.isSystemTopic(TopicName.get(topic.getName()))) { futures.add(((PersistentTopic) topic).clearBacklog(subscription)); } } } else { for (Topic topic : topicList) { - if (topic instanceof PersistentTopic && !SystemTopic.isSystemTopic(TopicName.get(topic.getName()))) { + if (topic instanceof PersistentTopic && !SystemTopicClient.isSystemTopic(TopicName.get(topic.getName()))) { futures.add(((PersistentTopic) topic).clearBacklog()); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java index bdf63c2e5481d..ab4d50f258cdd 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerService.java @@ -101,10 +101,10 @@ import org.apache.pulsar.broker.service.persistent.DispatchRateLimiter; import org.apache.pulsar.broker.service.persistent.PersistentDispatcherMultipleConsumers; import org.apache.pulsar.broker.service.persistent.PersistentTopic; +import org.apache.pulsar.broker.service.persistent.SystemTopic; import org.apache.pulsar.broker.stats.ClusterReplicationMetrics; import org.apache.pulsar.broker.stats.prometheus.metrics.Summary; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.broker.web.PulsarWebResource; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect; import org.apache.pulsar.broker.zookeeper.aspectj.ClientCnxnAspect.EventListner; @@ -119,7 +119,6 @@ import org.apache.pulsar.client.impl.conf.ClientConfigurationData; import org.apache.pulsar.common.allocator.PulsarByteBufAllocator; import org.apache.pulsar.common.configuration.FieldContext; -import org.apache.pulsar.common.events.EventsTopicNames; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; import org.apache.pulsar.common.naming.NamespaceBundles; @@ -933,8 +932,9 @@ private void createPersistentTopic(final String topic, boolean createIfMissing, @Override public void openLedgerComplete(ManagedLedger ledger, Object ctx) { try { - PersistentTopic persistentTopic = new PersistentTopic( - topic, ledger, BrokerService.this, isSystemTopic(topic)); + PersistentTopic persistentTopic = isSystemTopic(topic) + ? new SystemTopic(topic, ledger, BrokerService.this) + : new PersistentTopic(topic, ledger, BrokerService.this); CompletableFuture replicationFuture = persistentTopic.checkReplication(); replicationFuture.thenCompose(v -> { // Also check dedup status @@ -1254,39 +1254,11 @@ public BacklogQuotaManager getBacklogQuotaManager() { return this.backlogQuotaManager; } - /** - * - * @param topic - * needing quota enforcement check - * @return determine if quota enforcement needs to be done for topic - */ - public boolean isBacklogExceeded(PersistentTopic topic) { - if (topic.isSystemTopic()) { - return false; - } - TopicName topicName = TopicName.get(topic.getName()); - long backlogQuotaLimitInBytes = getBacklogQuotaManager().getBacklogQuotaLimit(topicName.getNamespace()); - if (backlogQuotaLimitInBytes < 0) { - return false; - } - if (log.isDebugEnabled()) { - log.debug("[{}] - backlog quota limit = [{}]", topic.getName(), backlogQuotaLimitInBytes); - } - - // check if backlog exceeded quota - long storageSize = topic.getBacklogSize(); - if (log.isDebugEnabled()) { - log.debug("[{}] Storage size = [{}], limit [{}]", topic.getName(), storageSize, backlogQuotaLimitInBytes); - } - - return (storageSize >= backlogQuotaLimitInBytes); - } - public void monitorBacklogQuota() { forEachTopic(topic -> { if (topic instanceof PersistentTopic) { PersistentTopic persistentTopic = (PersistentTopic) topic; - if (isBacklogExceeded(persistentTopic)) { + if (persistentTopic.isBacklogExceeded()) { getBacklogQuotaManager().handleExceededBacklogQuota(persistentTopic); } else { if (log.isDebugEnabled()) { @@ -2235,6 +2207,6 @@ private AutoSubscriptionCreationOverride getAutoSubscriptionCreationOverride(fin return null; } private boolean isSystemTopic(String topic) { - return SystemTopic.isSystemTopic(TopicName.get(topic)); + return SystemTopicClient.isSystemTopic(TopicName.get(topic)); } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 717e1ef9a2cb6..67c558214fd6d 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -26,7 +26,7 @@ import org.apache.pulsar.common.events.ActionType; import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.common.events.PulsarEvent; import org.apache.pulsar.common.events.TopicPoliciesEvent; import org.apache.pulsar.common.naming.NamespaceBundle; @@ -56,7 +56,7 @@ public class SystemTopicBasedTopicPoliciesService implements TopicPoliciesServic private final Map ownedBundlesCountPerNamespace = new ConcurrentHashMap<>(); - private final Map> readerCaches = new ConcurrentHashMap<>(); + private final Map> readerCaches = new ConcurrentHashMap<>(); public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { this.pulsarService = pulsarService; @@ -67,10 +67,10 @@ public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, Top CompletableFuture result = new CompletableFuture<>(); createSystemTopicFactoryIfNeeded(); - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), + SystemTopicClient systemTopicClient = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject(), EventType.TOPIC_POLICY); - CompletableFuture writerFuture = systemTopic.newWriterAsync(); + CompletableFuture writerFuture = systemTopicClient.newWriterAsync(); writerFuture.whenComplete((writer, ex) -> { if (ex != null) { result.completeExceptionally(ex); @@ -119,16 +119,16 @@ public TopicPolicies getTopicPolicies(TopicName topicName) { } @Override - public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { + public CompletableFuture getTopicPoliciesBypassCacheAsync(TopicName topicName) { CompletableFuture result = new CompletableFuture<>(); createSystemTopicFactoryIfNeeded(); if (namespaceEventsSystemTopicFactory == null) { result.complete(null); return result; } - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject() + SystemTopicClient systemTopicClient = namespaceEventsSystemTopicFactory.createSystemTopic(topicName.getNamespaceObject() , EventType.TOPIC_POLICY); - systemTopic.newReaderAsync().thenAccept(r -> + systemTopicClient.newReaderAsync().thenAccept(r -> fetchTopicPoliciesAsyncAndCloseReader(r, topicName, null, result)); return result; } @@ -144,9 +144,9 @@ public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle name if (readerCaches.get(namespace) != null) { result.complete(null); } else { - SystemTopic systemTopic = namespaceEventsSystemTopicFactory.createSystemTopic(namespace + SystemTopicClient systemTopicClient = namespaceEventsSystemTopicFactory.createSystemTopic(namespace , EventType.TOPIC_POLICY); - CompletableFuture readerCompletableFuture = systemTopic.newReaderAsync(); + CompletableFuture readerCompletableFuture = systemTopicClient.newReaderAsync(); readerCaches.put(namespace, readerCompletableFuture); readerCompletableFuture.whenComplete((reader, ex) -> { if (ex != null) { @@ -166,9 +166,9 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n NamespaceName namespace = namespaceBundle.getNamespaceObject(); AtomicInteger bundlesCount = ownedBundlesCountPerNamespace.get(namespace); if (bundlesCount == null || bundlesCount.decrementAndGet() <= 0) { - CompletableFuture readerCompletableFuture = readerCaches.remove(namespace); + CompletableFuture readerCompletableFuture = readerCaches.remove(namespace); if (readerCompletableFuture != null) { - readerCompletableFuture.thenAccept(SystemTopic.Reader::closeAsync); + readerCompletableFuture.thenAccept(SystemTopicClient.Reader::closeAsync); ownedBundlesCountPerNamespace.remove(namespace); policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespace)); } @@ -176,7 +176,7 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n return CompletableFuture.completedFuture(null); } - private void initPolicesCache(SystemTopic.Reader reader, CompletableFuture future) { + private void initPolicesCache(SystemTopicClient.Reader reader, CompletableFuture future) { reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { future.completeExceptionally(ex); @@ -197,7 +197,7 @@ private void initPolicesCache(SystemTopic.Reader reader, CompletableFuture }); } - private void readMorePolicies(SystemTopic.Reader reader) { + private void readMorePolicies(SystemTopicClient.Reader reader) { reader.readNextAsync().whenComplete((msg, ex) -> { if (ex == null) { refreshTopicPoliciesCache(msg); @@ -239,7 +239,7 @@ private void createSystemTopicFactoryIfNeeded() { } } - private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopic.Reader reader, TopicName topicName, TopicPolicies policies, + private void fetchTopicPoliciesAsyncAndCloseReader(SystemTopicClient.Reader reader, TopicName topicName, TopicPolicies policies, CompletableFuture future) { reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index a88422f34ddc5..437974cc700f7 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -51,7 +51,7 @@ public interface TopicPoliciesService { * @param topicName topic name * @return future of the topic policies */ - CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName); + CompletableFuture getTopicPoliciesBypassCacheAsync(TopicName topicName); /** * Add owned namespace bundle async. @@ -80,7 +80,7 @@ public TopicPolicies getTopicPolicies(TopicName topicName) { } @Override - public CompletableFuture getTopicPoliciesWithoutCacheAsync(TopicName topicName) { + public CompletableFuture getTopicPoliciesBypassCacheAsync(TopicName topicName) { return CompletableFuture.completedFuture(null); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java index 23b1aa2be52e4..6e6c9e4bec541 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java @@ -167,8 +167,6 @@ public class PersistentTopic extends AbstractTopic implements Topic, AddEntryCal private CompletableFuture currentCompaction = CompletableFuture.completedFuture(COMPACTION_NEVER_RUN); private final CompactedTopic compactedTopic; - private final boolean isSystemTopic; - private CompletableFuture currentOffload = CompletableFuture.completedFuture( (MessageIdImpl)MessageId.earliest); @@ -212,11 +210,9 @@ public void reset() { } } - public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerService, - boolean isSystemTopic) throws NamingException { + public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerService) throws NamingException { super(topic, brokerService); this.ledger = ledger; - this.isSystemTopic = isSystemTopic; this.subscriptions = new ConcurrentOpenHashMap<>(16, 1); this.replicators = new ConcurrentOpenHashMap<>(16, 1); USAGE_COUNT_UPDATER.set(this, 0); @@ -281,7 +277,6 @@ public PersistentTopic(String topic, ManagedLedger ledger, BrokerService brokerS this.replicators = new ConcurrentOpenHashMap<>(16, 1); this.compactedTopic = new CompactedTopicImpl(brokerService.pulsar().getBookKeeperClient()); this.backloggedCursorThresholdEntries = brokerService.pulsar().getConfiguration().getManagedLedgerCursorBackloggedThreshold(); - this.isSystemTopic = false; } private void initializeDispatchRateLimiterIfNeeded(Optional policies) { @@ -1124,9 +1119,6 @@ public CompletableFuture checkReplication() { @Override public void checkMessageExpiry() { - if (isSystemTopic) { - return; - } TopicName name = TopicName.get(topic); Policies policies; try { @@ -1160,7 +1152,7 @@ public void checkCompaction() { .orElseThrow(() -> new KeeperException.NoNodeException()); - if (isSystemTopic || policies.compaction_threshold != 0 + if (isSystemTopic() || policies.compaction_threshold != 0 && currentCompaction.isDone()) { long backlogEstimate = 0; @@ -1640,9 +1632,6 @@ private boolean hasBacklogs() { @Override public void checkGC(int maxInactiveDurationInSec, InactiveTopicDeleteMode deleteMode) { - if (isSystemTopic) { - return; - } if (isActive(deleteMode)) { lastActive = System.nanoTime(); } else if (System.nanoTime() - lastActive < TimeUnit.SECONDS.toNanos(maxInactiveDurationInSec)) { @@ -1861,7 +1850,7 @@ public boolean isBacklogQuotaExceeded(String producerName) { if ((retentionPolicy == BacklogQuota.RetentionPolicy.producer_request_hold || retentionPolicy == BacklogQuota.RetentionPolicy.producer_exception) - && brokerService.isBacklogExceeded(this)) { + && isBacklogExceeded()) { log.info("[{}] Backlog quota exceeded. Cannot create producer [{}]", this.getName(), producerName); return true; } else { @@ -1871,6 +1860,28 @@ public boolean isBacklogQuotaExceeded(String producerName) { return false; } + /** + * @return determine if quota enforcement needs to be done for topic + */ + public boolean isBacklogExceeded() { + TopicName topicName = TopicName.get(getName()); + long backlogQuotaLimitInBytes = brokerService.getBacklogQuotaManager().getBacklogQuotaLimit(topicName.getNamespace()); + if (backlogQuotaLimitInBytes < 0) { + return false; + } + if (log.isDebugEnabled()) { + log.debug("[{}] - backlog quota limit = [{}]", getName(), backlogQuotaLimitInBytes); + } + + // check if backlog exceeded quota + long storageSize = getBacklogSize(); + if (log.isDebugEnabled()) { + log.debug("[{}] Storage size = [{}], limit [{}]", getName(), storageSize, backlogQuotaLimitInBytes); + } + + return (storageSize >= backlogQuotaLimitInBytes); + } + @Override public boolean isReplicated() { return !replicators.isEmpty(); @@ -2148,6 +2159,6 @@ public CompactedTopic getCompactedTopic() { @Override public boolean isSystemTopic() { - return isSystemTopic; + return false; } } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/SystemTopic.java new file mode 100644 index 0000000000000..6720209f25e91 --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/SystemTopic.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.pulsar.broker.service.persistent; + +import org.apache.bookkeeper.mledger.ManagedLedger; +import org.apache.pulsar.broker.service.BrokerService; +import org.apache.pulsar.broker.service.BrokerServiceException; +import org.apache.pulsar.common.policies.data.InactiveTopicDeleteMode; + +public class SystemTopic extends PersistentTopic { + + public SystemTopic(String topic, ManagedLedger ledger, BrokerService brokerService) throws BrokerServiceException.NamingException { + super(topic, ledger, brokerService); + } + + @Override + public boolean isBacklogExceeded() { + return false; + } + + @Override + public boolean isSystemTopic() { + return true; + } + + @Override + public void checkMessageExpiry() { + // do nothing for system topic + } + + @Override + public void checkGC(int maxInactiveDurationInSec, InactiveTopicDeleteMode deleteMode) { + // do nothing for system topic + } +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java index 8943521d68411..911a99726a01a 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicFactory.java @@ -34,11 +34,11 @@ public NamespaceEventsSystemTopicFactory(PulsarClient client) { this.client = client; } - public SystemTopic createSystemTopic(NamespaceName namespaceName, EventType eventType) { + public SystemTopicClient createSystemTopic(NamespaceName namespaceName, EventType eventType) { TopicName topicName = getSystemTopicName(namespaceName, eventType); if (topicName != null) { log.info("Create system topic {} for {}", topicName.toString(), eventType); - return new TopicPoliciesSystemTopic(client, topicName); + return new TopicPoliciesSystemTopicClient(client, topicName); } else { return null; } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClient.java similarity index 97% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java rename to pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClient.java index 0e5efed7f20d8..c5a33522d1997 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClient.java @@ -32,7 +32,7 @@ /** * Pulsar system topic */ -public interface SystemTopic { +public interface SystemTopicClient { /** * Get topic name of the system topic. @@ -118,7 +118,7 @@ interface Writer { * Get the system topic of the writer * @return system topic */ - SystemTopic getSystemTopic(); + SystemTopicClient getSystemTopicClient(); } @@ -165,7 +165,7 @@ interface Reader { * Get the system topic of the reader * @return system topic */ - SystemTopic getSystemTopic(); + SystemTopicClient getSystemTopic(); } static boolean isSystemTopic(TopicName topicName) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClientBase.java similarity index 95% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java rename to pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClientBase.java index aed17b9d94219..e358190da1ae8 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/SystemTopicClientBase.java @@ -30,7 +30,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -public abstract class SystemTopicBase implements SystemTopic { +public abstract class SystemTopicClientBase implements SystemTopicClient { protected final TopicName topicName; protected final PulsarClient client; @@ -38,7 +38,7 @@ public abstract class SystemTopicBase implements SystemTopic { protected final List writers; protected final List readers; - public SystemTopicBase(PulsarClient client, TopicName topicName) { + public SystemTopicClientBase(PulsarClient client, TopicName topicName) { this.client = client; this.topicName = topicName; this.writers = Collections.synchronizedList(new ArrayList<>()); @@ -113,5 +113,5 @@ public List getWriters() { return writers; } - private static final Logger log = LoggerFactory.getLogger(SystemTopicBase.class); + private static final Logger log = LoggerFactory.getLogger(SystemTopicClientBase.class); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopicClient.java similarity index 86% rename from pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java rename to pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopicClient.java index 3d4d9f604cdd2..812bd072722d4 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopic.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/systopic/TopicPoliciesSystemTopicClient.java @@ -35,9 +35,9 @@ /** * System topic for topic policy */ -public class TopicPoliciesSystemTopic extends SystemTopicBase { +public class TopicPoliciesSystemTopicClient extends SystemTopicClientBase { - public TopicPoliciesSystemTopic(PulsarClient client, TopicName topicName) { + public TopicPoliciesSystemTopicClient(PulsarClient client, TopicName topicName) { super(client, topicName); } @@ -49,7 +49,7 @@ protected CompletableFuture newWriterAsyncInternal() { if (log.isDebugEnabled()) { log.debug("[{}] A new writer is created", topicName); } - return CompletableFuture.completedFuture(new TopicPolicyWriter(producer, TopicPoliciesSystemTopic.this)); + return CompletableFuture.completedFuture(new TopicPolicyWriter(producer, TopicPoliciesSystemTopicClient.this)); }); } @@ -63,18 +63,18 @@ protected CompletableFuture newReaderAsyncInternal() { if (log.isDebugEnabled()) { log.debug("[{}] A new reader is created", topicName); } - return CompletableFuture.completedFuture(new TopicPolicyReader(reader, TopicPoliciesSystemTopic.this)); + return CompletableFuture.completedFuture(new TopicPolicyReader(reader, TopicPoliciesSystemTopicClient.this)); }); } private static class TopicPolicyWriter implements Writer { private final Producer producer; - private final SystemTopic systemTopic; + private final SystemTopicClient systemTopicClient; - private TopicPolicyWriter(Producer producer, SystemTopic systemTopic) { + private TopicPolicyWriter(Producer producer, SystemTopicClient systemTopicClient) { this.producer = producer; - this.systemTopic = systemTopic; + this.systemTopicClient = systemTopicClient; } @Override @@ -97,7 +97,7 @@ private String getEventKey(PulsarEvent event) { @Override public void close() throws IOException { this.producer.close(); - systemTopic.getWriters().remove(TopicPolicyWriter.this); + systemTopicClient.getWriters().remove(TopicPolicyWriter.this); } @Override @@ -106,18 +106,18 @@ public CompletableFuture closeAsync() { } @Override - public SystemTopic getSystemTopic() { - return systemTopic; + public SystemTopicClient getSystemTopicClient() { + return systemTopicClient; } } private static class TopicPolicyReader implements Reader { private final org.apache.pulsar.client.api.Reader reader; - private final TopicPoliciesSystemTopic systemTopic; + private final TopicPoliciesSystemTopicClient systemTopic; private TopicPolicyReader(org.apache.pulsar.client.api.Reader reader, - TopicPoliciesSystemTopic systemTopic) { + TopicPoliciesSystemTopicClient systemTopic) { this.reader = reader; this.systemTopic = systemTopic; } @@ -157,10 +157,10 @@ public CompletableFuture closeAsync() { } @Override - public SystemTopic getSystemTopic() { + public SystemTopicClient getSystemTopic() { return systemTopic; } } - private static final Logger log = LoggerFactory.getLogger(TopicPoliciesSystemTopic.class); + private static final Logger log = LoggerFactory.getLogger(TopicPoliciesSystemTopicClient.class); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java index 27448c0ebae5d..c0992c6591fca 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java @@ -75,7 +75,6 @@ import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.service.BrokerService; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.client.admin.LongRunningProcessStatus; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java index f2dd39e544d2b..08fd56734fead 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java @@ -51,7 +51,7 @@ import org.apache.pulsar.broker.ServiceConfiguration; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.PulsarClient; @@ -341,7 +341,7 @@ protected List getTopicListAndTrimSystemTopic(String namespace) throws P // Check topic policy system topic and then delete them assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopic.isSystemTopic(TopicName.get(tn))); + topicList.removeIf(tn -> SystemTopicClient.isSystemTopic(TopicName.get(tn))); return topicList; } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 789f8db93f312..80caddfda41b9 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -171,7 +171,7 @@ public void testGetPolicy() throws ExecutionException, InterruptedException, Pul Assert.assertTrue(systemTopicBasedTopicPoliciesService.checkReaderIsCached(NamespaceName.get(NAMESPACE3))); // Check get without cache - policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesWithoutCacheAsync(TOPIC1).get(); + policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPoliciesBypassCacheAsync(TOPIC1).get(); Assert.assertEquals(policies1, policiesGet1); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java index 37f793741936f..ff5b5b9a0ac4c 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java @@ -37,6 +37,7 @@ import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsGenerator; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.broker.systopic.SystemTopic; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.common.naming.TopicName; import org.testng.annotations.AfterClass; @@ -108,7 +109,7 @@ public void testPerTopicStats() throws Exception { cm.removeIf(f -> { String topicName = f.tags.get("topic"); if (StringUtils.isNotBlank(topicName)) { - return SystemTopic.isSystemTopic(TopicName.get(topicName)); + return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); } else { return false; } @@ -125,7 +126,7 @@ public void testPerTopicStats() throws Exception { cm.removeIf(f -> { String topicName = f.tags.get("topic"); if (StringUtils.isNotBlank(topicName)) { - return SystemTopic.isSystemTopic(TopicName.get(topicName)); + return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); } else { return false; } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java index 98f6dbd801d46..a6b104b22e245 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java @@ -62,7 +62,7 @@ protected void cleanup() throws Exception { @Test public void testSendAndReceiveNamespaceEvents() throws Exception { - SystemTopic systemTopicForNamespace1 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE1), EventType.TOPIC_POLICY); + SystemTopicClient systemTopicClientForNamespace1 = systemTopicFactory.createSystemTopic(NamespaceName.get(NAMESPACE1), EventType.TOPIC_POLICY); TopicPolicies policies = TopicPolicies.builder() .maxProducerPerTopic(10) .build(); @@ -77,33 +77,33 @@ public void testSendAndReceiveNamespaceEvents() throws Exception { .policies(policies) .build()) .build(); - systemTopicForNamespace1.newWriter().write(event); - SystemTopic.Reader reader = systemTopicForNamespace1.newReader(); + systemTopicClientForNamespace1.newWriter().write(event); + SystemTopicClient.Reader reader = systemTopicClientForNamespace1.newReader(); Message received = reader.readNext(); log.info("Receive pulsar event from system topic : {}", received.getValue()); // test event send and receive Assert.assertEquals(received.getValue(), event); - Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 1); - Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 1); + Assert.assertEquals(systemTopicClientForNamespace1.getWriters().size(), 1); + Assert.assertEquals(systemTopicClientForNamespace1.getReaders().size(), 1); // test new reader read - SystemTopic.Reader reader1 = systemTopicForNamespace1.newReader(); + SystemTopicClient.Reader reader1 = systemTopicClientForNamespace1.newReader(); Message received1 = reader1.readNext(); log.info("Receive pulsar event from system topic : {}", received1.getValue()); Assert.assertEquals(received1.getValue(), event); // test writers and readers - Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 2); - SystemTopic.Writer writer = systemTopicForNamespace1.newWriter(); - Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 2); + Assert.assertEquals(systemTopicClientForNamespace1.getReaders().size(), 2); + SystemTopicClient.Writer writer = systemTopicClientForNamespace1.newWriter(); + Assert.assertEquals(systemTopicClientForNamespace1.getWriters().size(), 2); writer.close(); reader.close(); - Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 1); - Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 1); - systemTopicForNamespace1.close(); - Assert.assertEquals(systemTopicForNamespace1.getWriters().size(), 0); - Assert.assertEquals(systemTopicForNamespace1.getReaders().size(), 0); + Assert.assertEquals(systemTopicClientForNamespace1.getWriters().size(), 1); + Assert.assertEquals(systemTopicClientForNamespace1.getReaders().size(), 1); + systemTopicClientForNamespace1.close(); + Assert.assertEquals(systemTopicClientForNamespace1.getWriters().size(), 0); + Assert.assertEquals(systemTopicClientForNamespace1.getReaders().size(), 0); } private void prepareData() throws PulsarAdminException { diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java index cdbafd6423b22..f1b444e5f9ddc 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java @@ -197,8 +197,10 @@ public static void setStorageQuota(Policies polices, BacklogQuota quota) { @Override public String toString() { return MoreObjects.toStringHelper(this).add("auth_policies", auth_policies) - .add("replication_clusters", replication_clusters).add("bundles", bundles) - .add("backlog_quota_map", backlog_quota_map).add("persistence", persistence) + .add("replication_clusters", replication_clusters) + .add("bundles", bundles) + .add("backlog_quota_map", backlog_quota_map) + .add("persistence", persistence) .add("deduplicationEnabled", deduplicationEnabled) .add("autoTopicCreationOverride", autoTopicCreationOverride) .add("autoSubscriptionCreationOverride", autoSubscriptionCreationOverride) @@ -214,6 +216,7 @@ public String toString() { .add("subscription_expiration_time_minutes", subscription_expiration_time_minutes) .add("retention_policies", retention_policies) .add("message_ttl_in_seconds", message_ttl_in_seconds).add("retentionPolicies", retention_policies) + .add("retention_policies", retention_policies) .add("deleted", deleted) .add("encryption_required", encryption_required) .add("delayed_delivery_policies", delayed_delivery_policies) diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java index 998e0c003ee4a..56fbf8368eed8 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/TopicPolicies.java @@ -74,7 +74,7 @@ public boolean isMaxConsumerPerTopicSet() { return maxConsumerPerTopic != null; } - public boolean isMaxConsumersPerSubscription() { + public boolean isMaxConsumersPerSubscriptionSet() { return maxConsumersPerSubscription != null; } } From 32ce0c121c3c39b643e6a9bf451a8c3181e4967b Mon Sep 17 00:00:00 2001 From: lipenghui Date: Tue, 8 Oct 2019 16:17:59 +0800 Subject: [PATCH 18/31] Add TopicPoliciesCacheNotInitException --- .../SystemTopicBasedTopicPoliciesService.java | 20 +++++++++++--- .../TopicPoliciesCacheNotInitException.java | 26 +++++++++++++++++++ .../broker/service/TopicPoliciesService.java | 4 +-- ...temTopicBasedTopicPoliciesServiceTest.java | 22 +++++++++------- 4 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 67c558214fd6d..cfbc1493f2923 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -58,6 +58,8 @@ public class SystemTopicBasedTopicPoliciesService implements TopicPoliciesServic private final Map> readerCaches = new ConcurrentHashMap<>(); + private final Map policyCacheInitMap = new ConcurrentHashMap<>(); + public SystemTopicBasedTopicPoliciesService(PulsarService pulsarService) { this.pulsarService = pulsarService; } @@ -114,7 +116,11 @@ public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, Top } @Override - public TopicPolicies getTopicPolicies(TopicName topicName) { + public TopicPolicies getTopicPolicies(TopicName topicName) throws TopicPoliciesCacheNotInitException { + if (policyCacheInitMap.containsKey(topicName.getNamespaceObject()) + && !policyCacheInitMap.get(topicName.getNamespaceObject())) { + throw new TopicPoliciesCacheNotInitException(); + } return policiesCache.get(topicName); } @@ -137,15 +143,16 @@ public CompletableFuture getTopicPoliciesBypassCacheAsync(TopicNa public CompletableFuture addOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle) { CompletableFuture result = new CompletableFuture<>(); NamespaceName namespace = namespaceBundle.getNamespaceObject(); - ownedBundlesCountPerNamespace.putIfAbsent(namespace, new AtomicInteger(0)); - ownedBundlesCountPerNamespace.get(namespace).incrementAndGet(); createSystemTopicFactoryIfNeeded(); synchronized (this) { if (readerCaches.get(namespace) != null) { + ownedBundlesCountPerNamespace.get(namespace).incrementAndGet(); result.complete(null); } else { SystemTopicClient systemTopicClient = namespaceEventsSystemTopicFactory.createSystemTopic(namespace , EventType.TOPIC_POLICY); + ownedBundlesCountPerNamespace.putIfAbsent(namespace, new AtomicInteger(1)); + policyCacheInitMap.put(namespace, false); CompletableFuture readerCompletableFuture = systemTopicClient.newReaderAsync(); readerCaches.put(namespace, readerCompletableFuture); readerCompletableFuture.whenComplete((reader, ex) -> { @@ -170,6 +177,7 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n if (readerCompletableFuture != null) { readerCompletableFuture.thenAccept(SystemTopicClient.Reader::closeAsync); ownedBundlesCountPerNamespace.remove(namespace); + policyCacheInitMap.remove(namespace); policiesCache.entrySet().removeIf(entry -> entry.getKey().getNamespaceObject().equals(namespace)); } } @@ -193,6 +201,7 @@ private void initPolicesCache(SystemTopicClient.Reader reader, CompletableFuture }); } else { future.complete(null); + policyCacheInitMap.computeIfPresent(reader.getSystemTopic().getTopicName().getNamespaceObject(), (k, v) -> true); } }); } @@ -290,5 +299,10 @@ boolean checkReaderIsCached(NamespaceName namespaceName) { return readerCaches.get(namespaceName) != null; } + @VisibleForTesting + Boolean getPoliciesCacheInit(NamespaceName namespaceName) { + return policyCacheInitMap.get(namespaceName); + } + private static final Logger log = LoggerFactory.getLogger(SystemTopicBasedTopicPoliciesService.class); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java new file mode 100644 index 0000000000000..96cc47d996d3f --- /dev/null +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.pulsar.broker.service; + +public class TopicPoliciesCacheNotInitException extends Exception { + + public TopicPoliciesCacheNotInitException() { + super("Topic policies cache have not init."); + } +} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 437974cc700f7..ee3da00ee71db 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -44,7 +44,7 @@ public interface TopicPoliciesService { * @param topicName topic name * @return future of the topic policies */ - TopicPolicies getTopicPolicies(TopicName topicName); + TopicPolicies getTopicPolicies(TopicName topicName) throws TopicPoliciesCacheNotInitException; /** * Get policies for a topic without cache async @@ -75,7 +75,7 @@ public CompletableFuture updateTopicPoliciesAsync(TopicName topicName, Top } @Override - public TopicPolicies getTopicPolicies(TopicName topicName) { + public TopicPolicies getTopicPolicies(TopicName topicName) throws TopicPoliciesCacheNotInitException { return null; } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 80caddfda41b9..94a8d8ea179c7 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -66,17 +66,19 @@ protected void cleanup() throws Exception { } @Test - public void testGetPolicy() throws ExecutionException, InterruptedException, PulsarClientException { + public void testGetPolicy() throws ExecutionException, InterruptedException, PulsarClientException, TopicPoliciesCacheNotInitException { + // Init topic policies - for (int i = 1; i <= 10; i++) { - TopicPolicies initPolicy = TopicPolicies.builder() - .maxConsumerPerTopic(i) - .build(); - systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, initPolicy).get(); - } + TopicPolicies initPolicy = TopicPolicies.builder() + .maxConsumerPerTopic(10) + .build(); + systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, initPolicy); + + Assert.assertNull(systemTopicBasedTopicPoliciesService.getPoliciesCacheInit(TOPIC1.getNamespaceObject())); - // Broker need to own the namespace bundle - pulsarClient.newProducer().topic(TOPIC1.toString()).create(); + Thread.sleep(1000); + + Assert.assertTrue(systemTopicBasedTopicPoliciesService.getPoliciesCacheInit(TOPIC1.getNamespaceObject())); // Assert broker is cache all topic policies Assert.assertEquals(10, systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC1).getMaxConsumerPerTopic().intValue()); @@ -157,7 +159,7 @@ public void testGetPolicy() throws ExecutionException, InterruptedException, Pul policies1.setMaxProducerPerTopic(106); systemTopicBasedTopicPoliciesService.updateTopicPoliciesAsync(TOPIC1, policies1); - Thread.sleep(2000); + Thread.sleep(1000); // reader for NAMESPACE1 will back fill the reader cache policiesGet1 = systemTopicBasedTopicPoliciesService.getTopicPolicies(TOPIC1); From 1df87acd63ba7d79e85b92be5650d8fd2dc50d80 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 9 Oct 2019 18:09:46 +0800 Subject: [PATCH 19/31] fix anti-affinity namespace tests --- .../broker/loadbalance/AntiAffinityNamespaceGroupTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java index 0951da4d018a8..21b6ecbdf618c 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java @@ -114,6 +114,7 @@ void setup() throws Exception { config1.setFailureDomainsEnabled(true); config1.setLoadBalancerEnabled(true); config1.setAdvertisedAddress("localhost"); + config1.setTopicLevelPoliciesEnabled(false); createCluster(bkEnsemble.getZkClient(), config1); pulsar1 = new PulsarService(config1); pulsar1.setShutdownService(new NoOpShutdownService()); @@ -131,6 +132,7 @@ void setup() throws Exception { config2.setZookeeperServers("127.0.0.1" + ":" + bkEnsemble.getZookeeperPort()); config2.setBrokerServicePort(Optional.of(0)); config2.setFailureDomainsEnabled(true); + config2.setTopicLevelPoliciesEnabled(false); pulsar2 = new PulsarService(config2); pulsar2.setShutdownService(new NoOpShutdownService()); pulsar2.start(); @@ -497,7 +499,7 @@ public void testLoadSheddingWithAntiAffinityNamespace() throws Exception { final String namespace = "my-tenant/use/my-ns"; final int totalNamespaces = 5; final String namespaceAntiAffinityGroup = "my-antiaffinity"; - final String bundle = "0x00000000_0xffffffff"; + final String bundle = "0x00000000_0x40000000"; admin1.tenants().createTenant("my-tenant", new TenantInfo(Sets.newHashSet("appid1", "appid2"), Sets.newHashSet("use"))); From c7d3e0645159e1d8e1d95c815572ec83d1c40939 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 20 Nov 2019 14:37:38 +0800 Subject: [PATCH 20/31] Use namespace bundle change listener. --- .../apache/pulsar/broker/PulsarService.java | 10 +++++++- .../SystemTopicBasedTopicPoliciesService.java | 24 +++++++++++++++++++ .../broker/service/TopicPoliciesService.java | 10 ++++++++ ...temTopicBasedTopicPoliciesServiceTest.java | 3 --- ...NamespaceEventsSystemTopicServiceTest.java | 6 +++-- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index 72aa1f0529467..a0fbd0f582879 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -419,7 +419,13 @@ public void start() throws PulsarServerException { this.defaultOffloader = createManagedLedgerOffloader( OffloadPolicies.create(this.getConfiguration().getProperties())); - brokerService.start(); + if (StringUtils.isNotBlank(config.getTransactionMetadataStoreProviderClassName())) { + transactionMetadataStoreService = new TransactionMetadataStoreService(TransactionMetadataStoreProvider + .newProvider(config.getTransactionMetadataStoreProviderClassName()), this); + } else { + transactionMetadataStoreService = new TransactionMetadataStoreService(TransactionMetadataStoreProvider + .newProvider(InMemTransactionMetadataStoreProvider.class.getName()), this); + } // Start topic level policies service if (config.isTopicLevelPoliciesEnabled() && config.isSystemTopicEnabled()) { @@ -497,6 +503,8 @@ public Boolean get() { // Initialize namespace service, after service url assigned. Should init zk and refresh self owner info. this.nsService.initialize(); + this.topicPoliciesService.start(); + // Start the leader election service startLeaderElectionService(); diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index cfbc1493f2923..4d30d790b2f5e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; +import org.apache.pulsar.broker.namespace.NamespaceBundleOwnershipListener; import org.apache.pulsar.client.api.Message; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.events.ActionType; @@ -184,6 +185,29 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n return CompletableFuture.completedFuture(null); } + @Override + public void start() { + + pulsarService.getNamespaceService().addNamespaceBundleOwnershipListener(new NamespaceBundleOwnershipListener() { + + @Override + public void onLoad(NamespaceBundle bundle) { + addOwnedNamespaceBundleAsync(bundle); + } + + @Override + public void unLoad(NamespaceBundle bundle) { + removeOwnedNamespaceBundleAsync(bundle); + } + + @Override + public boolean test(NamespaceBundle namespaceBundle) { + return true; + } + + }); + } + private void initPolicesCache(SystemTopicClient.Reader reader, CompletableFuture future) { reader.hasMoreEventsAsync().whenComplete((hasMore, ex) -> { if (ex != null) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index ee3da00ee71db..1d228e471f165 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -67,6 +67,11 @@ public interface TopicPoliciesService { */ CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle namespaceBundle); + /** + * Start the topic policy service. + */ + void start(); + class TopicPoliciesServiceDisabled implements TopicPoliciesService { @Override @@ -95,5 +100,10 @@ public CompletableFuture removeOwnedNamespaceBundleAsync(NamespaceBundle n //No-op return CompletableFuture.completedFuture(null); } + + @Override + public void start() { + //No-op + } } } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 94a8d8ea179c7..35c53c25db288 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -135,9 +135,6 @@ public void testGetPolicy() throws ExecutionException, InterruptedException, Pul Assert.assertEquals(policiesGet5, policies5); Assert.assertEquals(policiesGet6, policies6); - // Only cache 2 readers, reader for NAMESPACE1 is evicted - Assert.assertEquals(systemTopicBasedTopicPoliciesService.getReaderCacheCount(), 3); - // Remove reader cache will remove policies cache Assert.assertEquals(systemTopicBasedTopicPoliciesService.getPoliciesCacheSize(), 6); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java index a6b104b22e245..9bc18ff6ce9ff 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java @@ -33,7 +33,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; +import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -47,14 +49,14 @@ public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBa private NamespaceEventsSystemTopicFactory systemTopicFactory; - @BeforeMethod + @BeforeClass @Override protected void setup() throws Exception { super.internalSetup(); prepareData(); } - @AfterMethod + @AfterClass @Override protected void cleanup() throws Exception { super.internalCleanup(); From ec21c2c33403a1fe9ed01a4f59a3682c21ed4fe2 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Wed, 20 Nov 2019 14:57:08 +0800 Subject: [PATCH 21/31] Remove unused code. --- .../broker/namespace/NamespaceService.java | 71 ++++++++----------- .../broker/namespace/OwnershipCache.java | 4 -- .../service/BrokerServiceException.java | 6 ++ .../SystemTopicBasedTopicPoliciesService.java | 1 + .../TopicPoliciesCacheNotInitException.java | 26 ------- .../broker/service/TopicPoliciesService.java | 1 + ...temTopicBasedTopicPoliciesServiceTest.java | 5 +- 7 files changed, 40 insertions(+), 74 deletions(-) delete mode 100644 pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java index b62aa791eb2b9..74d69c4efc44e 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/NamespaceService.java @@ -344,7 +344,36 @@ private CompletableFuture> findBrokerServiceUrl(Namespace } return targetMap.computeIfAbsent(bundle, (k) -> { - CompletableFuture> future = findBrokerServiceUrlInternal(bundle, authoritative, readOnly); + CompletableFuture> future = new CompletableFuture<>(); + + // First check if we or someone else already owns the bundle + ownershipCache.getOwnerAsync(bundle).thenAccept(nsData -> { + if (!nsData.isPresent()) { + // No one owns this bundle + + if (readOnly) { + // Do not attempt to acquire ownership + future.complete(Optional.empty()); + } else { + // Now, no one owns the namespace yet. Hence, we will try to dynamically assign it + pulsar.getExecutor().execute(() -> { + searchForCandidateBroker(bundle, future, authoritative); + }); + } + } else if (nsData.get().isDisabled()) { + future.completeExceptionally( + new IllegalStateException(String.format("Namespace bundle %s is being unloaded", bundle))); + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Namespace bundle {} already owned by {} ", bundle, nsData); + } + future.complete(Optional.of(new LookupResult(nsData.get()))); + } + }).exceptionally(exception -> { + LOG.warn("Failed to check owner for bundle {}: {}", bundle, exception.getMessage(), exception); + future.completeExceptionally(exception); + return null; + }); future.whenComplete((r, t) -> pulsar.getExecutor().execute( () -> targetMap.remove(bundle) @@ -354,42 +383,6 @@ private CompletableFuture> findBrokerServiceUrl(Namespace }); } - private CompletableFuture> findBrokerServiceUrlInternal(NamespaceBundle bundle, boolean authoritative, - boolean readOnly) { - CompletableFuture> future = new CompletableFuture<>(); - - // First check if we or someone else already owns the bundle - ownershipCache.getOwnerAsync(bundle).thenAccept(nsData -> { - if (!nsData.isPresent()) { - // No one owns this bundle - - if (readOnly) { - // Do not attempt to acquire ownership - future.complete(Optional.empty()); - } else { - // Now, no one owns the namespace yet. Hence, we will try to dynamically assign it - pulsar.getExecutor().execute(() -> { - searchForCandidateBroker(bundle, future, authoritative); - }); - } - } else if (nsData.get().isDisabled()) { - future.completeExceptionally( - new IllegalStateException(String.format("Namespace bundle %s is being unloaded", bundle))); - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Namespace bundle {} already owned by {} ", bundle, nsData); - } - future.complete(Optional.of(new LookupResult(nsData.get()))); - } - }).exceptionally(exception -> { - LOG.warn("Failed to check owner for bundle {}: {}", bundle, exception.getMessage(), exception); - future.completeExceptionally(exception); - return null; - }); - - return future; - } - private void searchForCandidateBroker(NamespaceBundle bundle, CompletableFuture> lookupFuture, boolean authoritative) { String candidateBroker = null; @@ -1169,10 +1162,6 @@ public void unloadSLANamespace() throws Exception { LOG.info("Namespace {} unloaded successfully", namespaceName); } - public String getHeartbeatNamespace() { - return getHeartbeatNamespace(host, config); - } - public static String getHeartbeatNamespace(String host, ServiceConfiguration config) { Integer port = null; if (config.getWebServicePort().isPresent()) { diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java index a09bb15602da1..50e96fadf51fb 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/namespace/OwnershipCache.java @@ -150,10 +150,6 @@ public CompletableFuture asyncLoad(String namespaceBundleZNode, Exe } } - public OwnershipCache(PulsarService pulsar, NamespaceBundleFactory bundleFactory) { - this(pulsar, bundleFactory, null); - } - /** * Constructor of OwnershipCache * diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerServiceException.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerServiceException.java index b4bfed518ad3c..6d0e50fe68d7a 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerServiceException.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/BrokerServiceException.java @@ -171,6 +171,12 @@ public ConsumerAssignException(String msg) { } } + public static class TopicPoliciesCacheNotInitException extends BrokerServiceException { + public TopicPoliciesCacheNotInitException() { + super("Topic policies cache have not init."); + } + } + public static PulsarApi.ServerError getClientErrorCode(Throwable t) { return getClientErrorCode(t, true); } diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java index 4d30d790b2f5e..7c561c9725023 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesService.java @@ -19,6 +19,7 @@ package org.apache.pulsar.broker.service; import com.google.common.annotations.VisibleForTesting; +import org.apache.pulsar.broker.service.BrokerServiceException.TopicPoliciesCacheNotInitException; import org.apache.pulsar.broker.PulsarServerException; import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.namespace.NamespaceBundleOwnershipListener; diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java deleted file mode 100644 index 96cc47d996d3f..0000000000000 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesCacheNotInitException.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * 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.broker.service; - -public class TopicPoliciesCacheNotInitException extends Exception { - - public TopicPoliciesCacheNotInitException() { - super("Topic policies cache have not init."); - } -} diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java index 1d228e471f165..1d9c382741b47 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/TopicPoliciesService.java @@ -18,6 +18,7 @@ */ package org.apache.pulsar.broker.service; +import org.apache.pulsar.broker.service.BrokerServiceException.TopicPoliciesCacheNotInitException; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.TopicPolicies; diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 35c53c25db288..33e3dce527b8c 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -20,10 +20,9 @@ import com.google.common.collect.Sets; import org.apache.pulsar.broker.auth.MockedPulsarServiceBaseTest; - +import org.apache.pulsar.broker.service.BrokerServiceException.TopicPoliciesCacheNotInitException; import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.PulsarAdminException; -import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.ClusterData; @@ -66,7 +65,7 @@ protected void cleanup() throws Exception { } @Test - public void testGetPolicy() throws ExecutionException, InterruptedException, PulsarClientException, TopicPoliciesCacheNotInitException { + public void testGetPolicy() throws ExecutionException, InterruptedException, TopicPoliciesCacheNotInitException { // Init topic policies TopicPolicies initPolicy = TopicPolicies.builder() From 9685ebcfc1d2fe181298f4887e15a72c0c853138 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 21 Nov 2019 11:32:34 +0800 Subject: [PATCH 22/31] Fix unit tests. --- .../broker/admin/impl/NamespacesBase.java | 25 ++++++++++++++++--- .../NamespaceOwnershipListenerTests.java | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java index 9b5794e4e440e..b4f80006d6dcc 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java @@ -199,8 +199,10 @@ protected void internalDeleteNamespace(AsyncResponse asyncResponse, boolean auth } boolean isEmpty; + List topics; try { - isEmpty = pulsar().getNamespaceService().getListOfPersistentTopics(namespaceName).join().isEmpty() + topics = pulsar().getNamespaceService().getListOfPersistentTopics(namespaceName).join(); + isEmpty = topics.isEmpty() && getPartitionedTopicList(TopicDomain.persistent).isEmpty() && getPartitionedTopicList(TopicDomain.non_persistent).isEmpty(); } catch (Exception e) { @@ -212,8 +214,17 @@ && getPartitionedTopicList(TopicDomain.persistent).isEmpty() if (log.isDebugEnabled()) { log.debug("Found topics on namespace {}", namespaceName); } - asyncResponse.resume(new RestException(Status.CONFLICT, "Cannot delete non empty namespace")); - return; + boolean hasNonSystemTopic = false; + for (String topic : topics) { + if (!SystemTopicClient.isSystemTopic(TopicName.get(topic))) { + hasNonSystemTopic = true; + break; + } + } + if (hasNonSystemTopic) { + asyncResponse.resume(new RestException(Status.CONFLICT, "Cannot delete non empty namespace")); + return; + } } // set the policies to deleted so that somebody else cannot acquire this namespace @@ -231,6 +242,14 @@ && getPartitionedTopicList(TopicDomain.persistent).isEmpty() // remove from owned namespace map and ephemeral node from ZK final List> futures = Lists.newArrayList(); try { + // remove system topics first. + if (!topics.isEmpty()) { + for (String topic : topics) { + pulsar().getBrokerService().getTopicIfExists(topic).whenComplete((topicOptional, ex) -> { + topicOptional.ifPresent(systemTopic -> futures.add(systemTopic.deleteForcefully())); + }); + } + } NamespaceBundles bundles = pulsar().getNamespaceService().getNamespaceBundleFactory() .getBundles(namespaceName); for (NamespaceBundle bundle : bundles.getBundles()) { diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java index 551e45cb1c23e..ee4b493d59170 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java @@ -20,6 +20,7 @@ import com.google.common.collect.Sets; import org.apache.pulsar.broker.service.BrokerTestBase; +import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.PulsarClientException; From 27fe2ad26772f77211f2848c25fbc5646e6dfeb6 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 28 Nov 2019 18:44:41 +0800 Subject: [PATCH 23/31] Fix unit test --- .../apache/pulsar/broker/admin/impl/NamespacesBase.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java index b4f80006d6dcc..39bfbfc40f1b8 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java @@ -202,9 +202,10 @@ protected void internalDeleteNamespace(AsyncResponse asyncResponse, boolean auth List topics; try { topics = pulsar().getNamespaceService().getListOfPersistentTopics(namespaceName).join(); - isEmpty = topics.isEmpty() - && getPartitionedTopicList(TopicDomain.persistent).isEmpty() - && getPartitionedTopicList(TopicDomain.non_persistent).isEmpty(); + topics.addAll(getPartitionedTopicList(TopicDomain.persistent)); + topics.addAll(getPartitionedTopicList(TopicDomain.non_persistent)); + isEmpty = topics.isEmpty(); + } catch (Exception e) { asyncResponse.resume(new RestException(e)); return; From 1bccfa6e0c783d4485e24764287d0c8fb56319b1 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Mon, 2 Dec 2019 12:00:43 +0800 Subject: [PATCH 24/31] Fix unit test --- .../broker/service/BrokerServiceTest.java | 3 +- .../broker/stats/PrometheusMetricsTest.java | 44 ++++++++++++++----- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java index c24cbb0c31301..666615e06f79b 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java @@ -389,7 +389,8 @@ public void testBrokerServiceNamespaceStats() throws Exception { rolloverPerIntervalStats(); JsonObject topicStats = brokerStatsClient.getTopics(); - assertEquals(topicStats.size(), 2, topicStats.toString()); + // original topics and system topic for namespace event change + assertEquals(topicStats.size(), 3, topicStats.toString()); for (String ns : nsList) { JsonObject nsObject = topicStats.getAsJsonObject(ns); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java index ff5b5b9a0ac4c..798f507c0fd3d 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java @@ -104,8 +104,6 @@ public void testPerTopicStats() throws Exception { // There should be 2 metrics with different tags for each topic List cm = (List) metrics.get("pulsar_storage_write_latency_le_1"); - // 2 topics and 1 system topic - assertEquals(cm.size(), 2 + 1); cm.removeIf(f -> { String topicName = f.tags.get("topic"); if (StringUtils.isNotBlank(topicName)) { @@ -113,16 +111,26 @@ public void testPerTopicStats() throws Exception { } else { return false; } - }); + }); // 2 topics and 1 system topic + assertEquals(cm.size(), 2); + assertEquals(cm.get(0).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic2"); assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); assertEquals(cm.get(1).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic1"); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); cm = (List) metrics.get("pulsar_producers_count"); + cm.removeIf(f -> { + String topicName = f.tags.get("topic"); + if (StringUtils.isNotBlank(topicName)) { + return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); + } else { + return false; + } + }); // 3 topics and 1 system topic - assertEquals(cm.size(), 3 + 1); + assertEquals(cm.size(), 3); cm.removeIf(f -> { String topicName = f.tags.get("topic"); if (StringUtils.isNotBlank(topicName)) { @@ -141,8 +149,8 @@ public void testPerTopicStats() throws Exception { cm = (List) metrics.get("topic_load_times_count"); assertEquals(cm.size(), 1); - // add 1.0 for system topic - assertEquals(cm.get(0).value, 2.0 + 1.0); + // add 2.0 for system topic + assertEquals(cm.get(0).value, 4.0); assertEquals(cm.get(0).tags.get("cluster"), "test"); cm = (List) metrics.get("pulsar_in_bytes_total"); @@ -223,15 +231,31 @@ public void testPerNamespaceStats() throws Exception { // There should be 1 metric aggregated per namespace List cm = (List) metrics.get("pulsar_storage_write_latency_le_1"); - assertEquals(cm.size(), 1); - assertNull(cm.get(0).tags.get("topic")); - assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); - cm = (List) metrics.get("pulsar_producers_count"); assertEquals(cm.size(), 2); assertNull(cm.get(1).tags.get("topic")); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); + for (Metric metric : cm) { + assertNull(metric.tags.get("topic")); + assertTrue(metric.tags.get("namespace").equals("my-property/use/my-ns") + || metric.tags.get("namespace").startsWith("pulsar/test")); + } + cm = (List) metrics.get("pulsar_producers_count"); + assertEquals(cm.size(), 3); + for (Metric metric : cm) { + if (metric.tags.get("namespaces") != null) { + if (metric.tags.get("namespace").equals("my-property/use/my-ns")) { + assertEquals(metric.value, 2.0); + } else { + assertEquals(metric.value, 0.0); + } + assertTrue(metric.tags.get("namespace").equals("my-property/use/my-ns") + || metric.tags.get("namespace").startsWith("pulsar/test")); + } + assertNull(metric.tags.get("topic")); + } + cm = (List) metrics.get("pulsar_in_bytes_total"); assertEquals(cm.size(), 1); assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); From f213868d1dba43b2b50662b2bfd278ce0750bb2a Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 9 Jan 2020 10:32:19 +0800 Subject: [PATCH 25/31] Fix unit test --- .../service/SystemTopicBasedTopicPoliciesServiceTest.java | 2 +- .../systopic/NamespaceEventsSystemTopicServiceTest.java | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 33e3dce527b8c..37725ad0d6465 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -174,7 +174,7 @@ public void testGetPolicy() throws ExecutionException, InterruptedException, Top } private void prepareData() throws PulsarAdminException { - admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); + admin.clusters().createCluster("test", new ClusterData(pulsar.getBrokerServiceUrl())); admin.tenants().createTenant("system-topic", new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); admin.namespaces().createNamespace(NAMESPACE1); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java index 9bc18ff6ce9ff..15aa63f6158d1 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/systopic/NamespaceEventsSystemTopicServiceTest.java @@ -34,9 +34,7 @@ import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class NamespaceEventsSystemTopicServiceTest extends MockedPulsarServiceBaseTest { @@ -109,7 +107,7 @@ public void testSendAndReceiveNamespaceEvents() throws Exception { } private void prepareData() throws PulsarAdminException { - admin.clusters().createCluster("test", new ClusterData("http://127.0.0.1:" + BROKER_WEBSERVICE_PORT)); + admin.clusters().createCluster("test", new ClusterData(pulsar.getBrokerServiceUrl())); admin.tenants().createTenant("system-topic", new TenantInfo(Sets.newHashSet(), Sets.newHashSet("test"))); admin.namespaces().createNamespace(NAMESPACE1); From 1f5a174dcc1d877be8424b2a3196a1841d94a754 Mon Sep 17 00:00:00 2001 From: lipenghui Date: Thu, 9 Jan 2020 14:10:38 +0800 Subject: [PATCH 26/31] remove unused code --- .../apache/pulsar/broker/PulsarService.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java index a0fbd0f582879..f665f856a5d92 100644 --- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java +++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java @@ -419,19 +419,6 @@ public void start() throws PulsarServerException { this.defaultOffloader = createManagedLedgerOffloader( OffloadPolicies.create(this.getConfiguration().getProperties())); - if (StringUtils.isNotBlank(config.getTransactionMetadataStoreProviderClassName())) { - transactionMetadataStoreService = new TransactionMetadataStoreService(TransactionMetadataStoreProvider - .newProvider(config.getTransactionMetadataStoreProviderClassName()), this); - } else { - transactionMetadataStoreService = new TransactionMetadataStoreService(TransactionMetadataStoreProvider - .newProvider(InMemTransactionMetadataStoreProvider.class.getName()), this); - } - - // Start topic level policies service - if (config.isTopicLevelPoliciesEnabled() && config.isSystemTopicEnabled()) { - this.topicPoliciesService = new SystemTopicBasedTopicPoliciesService(this); - } - brokerService.start(); this.webService = new WebService(this); @@ -503,6 +490,11 @@ public Boolean get() { // Initialize namespace service, after service url assigned. Should init zk and refresh self owner info. this.nsService.initialize(); + // Start topic level policies service + if (config.isTopicLevelPoliciesEnabled() && config.isSystemTopicEnabled()) { + this.topicPoliciesService = new SystemTopicBasedTopicPoliciesService(this); + } + this.topicPoliciesService.start(); // Start the leader election service From ec95761906d7dc9cd96f3e03909d633e1a36ff85 Mon Sep 17 00:00:00 2001 From: penghui Date: Tue, 19 May 2020 15:08:53 +0800 Subject: [PATCH 27/31] Fix conflicts --- conf/broker.conf | 1 - conf/standalone.conf | 1 - .../broker/stats/PrometheusMetricsTest.java | 1 - .../pulsar/client/impl/KeySharedConsumer.java | 35 ------------------- .../client/impl/KeySharedConsumer1.java | 35 ------------------- .../client/impl/KeySharedConsumer2.java | 35 ------------------- .../pulsar/client/impl/KeySharedProducer.java | 33 ----------------- 7 files changed, 141 deletions(-) delete mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java delete mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java delete mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java delete mode 100644 pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java diff --git a/conf/broker.conf b/conf/broker.conf index b02d6a0a5d726..426a63a12755a 100644 --- a/conf/broker.conf +++ b/conf/broker.conf @@ -337,7 +337,6 @@ replicatedSubscriptionsSnapshotTimeoutSeconds=30 # Max number of snapshot to be cached per subscription. replicatedSubscriptionsSnapshotMaxCachedPerSubscription=10 -<<<<<<< HEAD # Max memory size for broker handling messages sending from producers. # If the processing message size exceed this value, broker will stop read data # from the connection. The processing messages means messages are sends to broker diff --git a/conf/standalone.conf b/conf/standalone.conf index b215246b1066d..b12e2eda0c405 100644 --- a/conf/standalone.conf +++ b/conf/standalone.conf @@ -221,7 +221,6 @@ maxConsumersPerTopic=0 # Using a value of 0, is disabling maxConsumersPerSubscription-limit check. maxConsumersPerSubscription=0 -<<<<<<< HEAD # Max number of partitions per partitioned topic # Use 0 or negative number to disable the check maxNumPartitionsPerPartitionedTopic=0 diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java index 798f507c0fd3d..fcd768099ea09 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java @@ -36,7 +36,6 @@ import org.apache.pulsar.broker.service.BrokerTestBase; import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsGenerator; import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.broker.systopic.SystemTopic; import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.common.naming.TopicName; diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java deleted file mode 100644 index 5129f71db8b77..0000000000000 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.apache.pulsar.client.impl; - -import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.client.api.Schema; -import org.apache.pulsar.client.api.SubscriptionType; - -import java.util.concurrent.TimeUnit; - -public class KeySharedConsumer { - - public static void main(String[] args) throws PulsarClientException { - PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); - - for (int i = 0; i < 3000; i++) { - new Thread(() -> { - try { - Consumer consumer = client.newConsumer(Schema.STRING) - .topic("key_shared_latency-1") - .subscriptionType(SubscriptionType.Key_Shared) - .receiverQueueSize(1000) - .subscriptionName("test") - .subscribe(); - while (true) { - consumer.acknowledge(consumer.receive()); - } - } catch (PulsarClientException e) { - e.printStackTrace(); - } - }).start(); - } - - } -} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java deleted file mode 100644 index f965a971fa7d6..0000000000000 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer1.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.apache.pulsar.client.impl; - -import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.client.api.Schema; -import org.apache.pulsar.client.api.SubscriptionType; - -import java.util.concurrent.TimeUnit; - -public class KeySharedConsumer1 { - - public static void main(String[] args) throws PulsarClientException { - PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); - - for (int i = 0; i < 2000; i++) { - new Thread(() -> { - try { - Consumer consumer = client.newConsumer(Schema.STRING) - .topic("key_shared_latency-1") - .subscriptionType(SubscriptionType.Key_Shared) - .receiverQueueSize(1000) - .subscriptionName("test") - .subscribe(); - while (true) { - consumer.acknowledge(consumer.receive()); - } - } catch (PulsarClientException e) { - e.printStackTrace(); - } - }).start(); - } - - } -} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java deleted file mode 100644 index edb6c63c812d8..0000000000000 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedConsumer2.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.apache.pulsar.client.impl; - -import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.client.api.Schema; -import org.apache.pulsar.client.api.SubscriptionType; - -import java.util.concurrent.TimeUnit; - -public class KeySharedConsumer2 { - - public static void main(String[] args) throws PulsarClientException { - PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); - - for (int i = 0; i < 2000; i++) { - new Thread(() -> { - try { - Consumer consumer = client.newConsumer(Schema.STRING) - .topic("key_shared_latency-1") - .subscriptionType(SubscriptionType.Key_Shared) - .receiverQueueSize(1000) - .subscriptionName("test") - .subscribe(); - while (true) { - consumer.acknowledge(consumer.receive()); - } - } catch (PulsarClientException e) { - e.printStackTrace(); - } - }).start(); - } - - } -} diff --git a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java b/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java deleted file mode 100644 index 7f737f9391f46..0000000000000 --- a/pulsar-client/src/test/java/org/apache/pulsar/client/impl/KeySharedProducer.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.apache.pulsar.client.impl; - -import org.apache.pulsar.client.api.BatcherBuilder; -import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.client.api.Producer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.apache.pulsar.client.api.Schema; -import org.apache.pulsar.client.api.SubscriptionType; - -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -public class KeySharedProducer { - - public static void main(String[] args) throws PulsarClientException, InterruptedException { - PulsarClient client = PulsarClient.builder().serviceUrl("pulsar://127.0.0.1:6650").statsInterval(5, TimeUnit.SECONDS).build(); - Producer producer = client.newProducer(Schema.STRING) - .topic("key_shared_latency-1") - .enableBatching(false) - .batcherBuilder(BatcherBuilder.KEY_BASED) - .maxPendingMessages(5000) - .create(); - - int i = 0; - while (true) { - producer.newMessage().key(UUID.randomUUID().toString()).value("test").sendAsync(); - if (++i % 20 == 0) { -// Thread.sleep(1); - } - } - } -} From b95d36dc0619fe614f95321d2ba51f88f9578b60 Mon Sep 17 00:00:00 2001 From: penghui Date: Tue, 19 May 2020 15:15:12 +0800 Subject: [PATCH 28/31] Fix conflicts --- .../java/org/apache/pulsar/common/policies/data/Policies.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java index f1b444e5f9ddc..2946157410988 100644 --- a/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java +++ b/pulsar-common/src/main/java/org/apache/pulsar/common/policies/data/Policies.java @@ -215,8 +215,6 @@ public String toString() { .add("message_ttl_in_seconds", message_ttl_in_seconds) .add("subscription_expiration_time_minutes", subscription_expiration_time_minutes) .add("retention_policies", retention_policies) - .add("message_ttl_in_seconds", message_ttl_in_seconds).add("retentionPolicies", retention_policies) - .add("retention_policies", retention_policies) .add("deleted", deleted) .add("encryption_required", encryption_required) .add("delayed_delivery_policies", delayed_delivery_policies) From fc1906174ad9be18e3771662452f09c739825d7e Mon Sep 17 00:00:00 2001 From: penghui Date: Tue, 26 May 2020 21:59:08 +0800 Subject: [PATCH 29/31] Disable the topic level policy service and system topic by default. --- conf/broker.conf | 4 ++-- conf/standalone.conf | 4 ++-- .../java/org/apache/pulsar/broker/ServiceConfiguration.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/conf/broker.conf b/conf/broker.conf index 426a63a12755a..c785bd43fdb1c 100644 --- a/conf/broker.conf +++ b/conf/broker.conf @@ -358,11 +358,11 @@ retentionCheckIntervalInSeconds=120 maxNumPartitionsPerPartitionedTopic=0 # Enable or disable system topic -systemTopicEnabled=true +systemTopicEnabled=false # Enable or disable topic level policies, topic level policies depends on the system topic # Please enable the system topic first. -topicLevelPoliciesEnabled=true +topicLevelPoliciesEnabled=false ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with diff --git a/conf/standalone.conf b/conf/standalone.conf index b12e2eda0c405..426ba5c948476 100644 --- a/conf/standalone.conf +++ b/conf/standalone.conf @@ -322,11 +322,11 @@ brokerClientTlsCiphers= brokerClientTlsProtocols= # Enable or disable system topic -systemTopicEnabled=true +systemTopicEnabled=false # Enable or disable topic level policies, topic level policies depends on the system topic # Please enable the system topic first. -topicLevelPoliciesEnabled=true +topicLevelPoliciesEnabled=false ### --- Authentication --- ### # Role names that are treated as "proxy roles". If the broker sees a request with diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java index 41c935a72fb20..7c9ebe95e7000 100644 --- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java +++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java @@ -677,13 +677,13 @@ public class ServiceConfiguration implements PulsarConfiguration { @FieldContext( category = CATEGORY_SERVER, doc = "Enable or disable system topic.") - private boolean systemTopicEnabled = true; + private boolean systemTopicEnabled = false; @FieldContext( category = CATEGORY_SERVER, doc = "Enable or disable topic level policies, topic level policies depends on the system topic, " + "please enable the system topic first.") - private boolean topicLevelPoliciesEnabled = true; + private boolean topicLevelPoliciesEnabled = false; /***** --- TLS --- ****/ @FieldContext( From f505108099b146eaa21bc6d9c115034aa65bbf33 Mon Sep 17 00:00:00 2001 From: penghui Date: Wed, 27 May 2020 15:04:03 +0800 Subject: [PATCH 30/31] Fix tests issue --- .../pulsar/broker/admin/AdminApiTest.java | 200 +++++++-------- .../pulsar/broker/admin/NamespacesTest.java | 13 +- .../broker/admin/v1/V1_AdminApiTest.java | 237 +++++++++--------- .../auth/MockedPulsarServiceBaseTest.java | 28 +-- .../AntiAffinityNamespaceGroupTest.java | 6 +- .../NamespaceOwnershipListenerTests.java | 3 +- .../broker/service/BrokerServiceTest.java | 11 +- .../service/PersistentTopicE2ETest.java | 187 +++++++------- ...temTopicBasedTopicPoliciesServiceTest.java | 2 + .../broker/stats/PrometheusMetricsTest.java | 61 +---- .../proxy/ProxyPublishConsumeTest.java | 8 +- 11 files changed, 322 insertions(+), 434 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java index c0992c6591fca..ccd0e27bddbba 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java @@ -74,7 +74,6 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.service.BrokerService; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.LongRunningProcessStatus; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; @@ -95,7 +94,6 @@ import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.client.api.SubscriptionType; -import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.lookup.data.LookupData; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; @@ -663,7 +661,7 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc // test with url style role. admin.namespaces().grantPermissionOnNamespace("prop-xyz/ns1", - "spiffe://developer/passport-role", EnumSet.allOf(AuthAction.class)); + "spiffe://developer/passport-role", EnumSet.allOf(AuthAction.class)); admin.namespaces().grantPermissionOnNamespace("prop-xyz/ns1", "my-role", EnumSet.allOf(AuthAction.class)); Policies policies = new Policies(); @@ -697,10 +695,10 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc // Force topic creation and namespace being loaded Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/my-topic") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1/my-topic") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.close(); admin.topics().delete("persistent://prop-xyz/ns1/my-topic"); @@ -722,10 +720,6 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc } assertTrue(i < 10); - // Delete system topic first. - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1"), - EventType.TOPIC_POLICY).toString(), true); - admin.namespaces().deleteNamespace("prop-xyz/ns1"); assertEquals(admin.namespaces().getNamespaces("prop-xyz"), Lists.newArrayList("prop-xyz/ns2")); @@ -753,9 +747,8 @@ public void persistentTopics(String topicName) throws Exception { final String persistentTopicName = "persistent://prop-xyz/ns1/" + topicName; // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/" + topicName, 0); - - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), - Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); + assertEquals(admin.topics().getList("prop-xyz/ns1"), + Lists.newArrayList("persistent://prop-xyz/ns1/" + topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -834,7 +827,7 @@ public void persistentTopics(String topicName) throws Exception { } catch (NotFoundException e) { } - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList()); + assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList()); } @Test(dataProvider = "topicName") @@ -893,17 +886,17 @@ public void partitionedTopics(String topicName) throws Exception { assertEquals(admin.topics().getSubscriptions(partitionedTopicName), Lists.newArrayList("my-sub")); Producer producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); } - assertEquals(Sets.newHashSet(getTopicListAndTrimSystemTopic("prop-xyz/ns1")), + assertEquals(Sets.newHashSet(admin.topics().getList("prop-xyz/ns1")), Sets.newHashSet(partitionedTopicName + "-partition-0", partitionedTopicName + "-partition-1", partitionedTopicName + "-partition-2", partitionedTopicName + "-partition-3")); @@ -951,14 +944,13 @@ public void partitionedTopics(String topicName) throws Exception { } producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); topics = admin.topics().getList("prop-xyz/ns1"); - // 4 partitions and 1 system topic - assertEquals(topics.size(), 4 + 1); + assertEquals(topics.size(), 4); try { admin.topics().deletePartitionedTopic(partitionedTopicName); @@ -1012,9 +1004,9 @@ public void testGetPartitionedInternalInfo() throws Exception { PartitionedManagedLedgerInfo partitionedManagedLedgerInfo = new PartitionedManagedLedgerInfo(); partitionedManagedLedgerInfo.version = 0L; partitionedManagedLedgerInfo.partitions.put(partitionTopic0, - ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic0Info), ManagedLedgerInfo.class)); + ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic0Info), ManagedLedgerInfo.class)); partitionedManagedLedgerInfo.partitions.put(partitionTopic1, - ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic1Info), ManagedLedgerInfo.class)); + ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic1Info), ManagedLedgerInfo.class)); String expectedResult = ObjectMapperFactory.getThreadLocal().writeValueAsString(partitionedManagedLedgerInfo); @@ -1076,11 +1068,8 @@ public void testDeleteNamespaceBundle(Integer numBundles) throws Exception { admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds3"); admin.lookups().lookupTopic("persistent://prop-xyz/ns1-bundles/ds4"); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1-bundles"), Lists.newArrayList()); + assertEquals(admin.namespaces().getTopics("prop-xyz/ns1-bundles"), Lists.newArrayList()); - // Delete system topic first - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/ns1-bundles"), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/ns1-bundles"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "test"), Lists.newArrayList()); } @@ -1091,14 +1080,13 @@ public void testNamespaceSplitBundle() throws Exception { final String namespace = "prop-xyz/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - - assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, null); @@ -1121,16 +1109,16 @@ public void testNamespaceSplitBundleWithTopicCountEquallyDivideAlgorithm() throw // Force to create a topic final String namespace = "prop-xyz/ns1"; List topicNames = Lists.newArrayList( - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); List> producers = new ArrayList<>(2); for (String topicName : topicNames) { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producers.add(producer); producer.send("message".getBytes()); } @@ -1139,7 +1127,7 @@ public void testNamespaceSplitBundleWithTopicCountEquallyDivideAlgorithm() throw try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, - NamespaceBundleSplitAlgorithm.topicCountEquallyDivideName); + NamespaceBundleSplitAlgorithm.topicCountEquallyDivideName); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } @@ -1160,7 +1148,7 @@ public void testNamespaceSplitBundleWithInvalidAlgorithm() throws Exception { final String namespace = "prop-xyz/ns1"; try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, - "invalid_test"); + "invalid_test"); fail("unsupported namespace bundle split algorithm"); } catch (PulsarAdminException ignored) { } @@ -1172,16 +1160,16 @@ public void testNamespaceSplitBundleWithDefaultTopicCountEquallyDivideAlgorithm( // Force to create a topic final String namespace = "prop-xyz/ns1"; List topicNames = Lists.newArrayList( - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); List> producers = new ArrayList<>(2); for (String topicName : topicNames) { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producers.add(producer); producer.send("message".getBytes()); } @@ -1211,14 +1199,13 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { final String namespace = "prop-xyz/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - - assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", false, null); @@ -1298,7 +1285,7 @@ public void testNamespaceUnloadBundle() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/ds2", 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), + assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList("persistent://prop-xyz/ns1/ds2")); // create consumer and subscription @@ -1309,10 +1296,10 @@ public void testNamespaceUnloadBundle() throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1360,9 +1347,8 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1-bundles/ds2", 0); - - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1-bundles"), - Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); + assertEquals(admin.topics().getList("prop-xyz/ns1-bundles"), + Lists.newArrayList("persistent://prop-xyz/ns1-bundles/ds2")); // create consumer and subscription Consumer consumer = pulsarClient.newConsumer().topic("persistent://prop-xyz/ns1-bundles/ds2") @@ -1372,10 +1358,10 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1421,7 +1407,7 @@ public void testDeleteSubscription() throws Exception { // create a topic and produce some messages publishMessagesOnPersistentTopic(persistentTopicName, 5); assertEquals(admin.topics().getList("prop-xyz/ns1"), - Lists.newArrayList(persistentTopicName)); + Lists.newArrayList(persistentTopicName)); // create the subscription by PulsarAdmin admin.topics().createSubscription(persistentTopicName, subName, MessageId.earliest); @@ -1430,11 +1416,11 @@ public void testDeleteSubscription() throws Exception { // create consumer and subscription PulsarClient client = PulsarClient.builder() - .serviceUrl(pulsar.getWebServiceAddress()) - .statsInterval(0, TimeUnit.SECONDS) - .build(); + .serviceUrl(pulsar.getWebServiceAddress()) + .statsInterval(0, TimeUnit.SECONDS) + .build(); Consumer consumer = client.newConsumer().topic(persistentTopicName).subscriptionName(subName) - .subscriptionType(SubscriptionType.Exclusive).subscribe(); + .subscriptionType(SubscriptionType.Exclusive).subscribe(); // try to delete the subscription with a connected consumer try { @@ -1478,10 +1464,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1491,10 +1477,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer1 = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer1.send(message.getBytes()); @@ -1594,10 +1580,10 @@ private void publishNullValueMessageOnPersistentTopic(String topicName, int mess private void publishMessagesOnPersistentTopic(String topicName, int messages, int startIdx, boolean nullValue) throws Exception { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = startIdx; i < (messages + startIdx); i++) { if (nullValue) { @@ -1648,10 +1634,10 @@ public void statsOnNonExistingTopics() throws Exception { public void testDeleteFailedReturnCode() throws Exception { String topicName = "persistent://prop-xyz/ns1/my-topic"; Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { admin.topics().delete(topicName); @@ -1931,8 +1917,7 @@ public void partitionedTopicsCursorReset(String topicName) throws Exception { .acknowledgmentGroupTime(0, TimeUnit.SECONDS).subscribe(); List topics = admin.topics().getList("prop-xyz/ns1"); - // 4 partition and 1 system topic - assertEquals(topics.size(), 4 + 1); + assertEquals(topics.size(), 4); assertEquals(admin.topics().getSubscriptions(topicName), Lists.newArrayList("my-sub")); @@ -1976,8 +1961,7 @@ public void persistentTopicsInvalidCursorReset() throws Exception { String topicName = "persistent://prop-xyz/ns1/invalidcursorreset"; // Force to create a topic publishMessagesOnPersistentTopic(topicName, 0); - - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList(topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -2054,7 +2038,7 @@ public void testPersistentTopicsExpireMessages() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/ns1/ds2", 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/ns1"), + assertEquals(admin.topics().getList("prop-xyz/ns1"), Lists.newArrayList("persistent://prop-xyz/ns1/ds2")); // create consumer and subscription @@ -2119,10 +2103,10 @@ public void testPersistentTopicExpireMessageOnParitionTopic() throws Exception { .subscriptionName("my-sub").subscribe(); Producer producer = client.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic("persistent://prop-xyz/ns1/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -2420,7 +2404,7 @@ public void testCompactionStatus() throws Exception { assertNotNull(pulsar.getBrokerService().getTopicReference(topicName)); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.NOT_RUN); + LongRunningProcessStatus.Status.NOT_RUN); // mock actual compaction, we don't need to really run it CompletableFuture promise = new CompletableFuture(); @@ -2429,12 +2413,12 @@ public void testCompactionStatus() throws Exception { admin.topics().triggerCompaction(topicName); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.RUNNING); + LongRunningProcessStatus.Status.RUNNING); promise.complete(1L); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.SUCCESS); + LongRunningProcessStatus.Status.SUCCESS); CompletableFuture errorPromise = new CompletableFuture(); doReturn(errorPromise).when(compactor).compact(topicName); @@ -2442,7 +2426,7 @@ public void testCompactionStatus() throws Exception { errorPromise.completeExceptionally(new Exception("Failed at something")); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.ERROR); + LongRunningProcessStatus.Status.ERROR); assertTrue(admin.topics().compactionStatus(topicName).lastError.contains("Failed at something")); } @@ -2451,9 +2435,9 @@ public void testTopicStatsLastExpireTimestampForSubscription() throws PulsarAdmi admin.namespaces().setNamespaceMessageTTL("prop-xyz/ns1", 60); final String topic = "persistent://prop-xyz/ns1/testTopicStatsLastExpireTimestampForSubscription"; Consumer producer = pulsarClient.newConsumer() - .topic(topic) - .subscriptionName("sub-1") - .subscribe(); + .topic(topic) + .subscriptionName("sub-1") + .subscribe(); Assert.assertEquals(admin.topics().getStats(topic).subscriptions.size(), 1); Assert.assertEquals(admin.topics().getStats(topic).subscriptions.values().iterator().next().lastExpireTimestamp, 0L); @@ -2546,4 +2530,4 @@ public void testGetTtlDurationDefaultInSeconds() throws Exception { int seconds = admin.namespaces().getPolicies("prop-xyz/ns1").message_ttl_in_seconds; assertEquals(seconds, 3600); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java index 1a1c7c1234b88..c3586d5b428e6 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/NamespacesTest.java @@ -68,14 +68,12 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.namespace.OwnershipCache; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.broker.web.PulsarWebResource; import org.apache.pulsar.broker.web.RestException; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Consumer; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.SubscriptionType; -import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundles; import org.apache.pulsar.common.naming.NamespaceName; @@ -1040,12 +1038,9 @@ public void testDeleteNamespace() throws Exception { NamespaceBundle bundle1 = pulsar.getNamespaceService().getBundle(topic); // (2) Delete topic admin.topics().delete(topicName); - // (3) Delete system topic - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString(), true); - // (4) Delete ns + // (3) Delete ns admin.namespaces().deleteNamespace(namespace); - // (5) check bundle + // (4) check bundle NamespaceBundle bundle2 = pulsar.getNamespaceService().getBundle(topic); assertNotEquals(bundle1.getBundleRange(), bundle2.getBundleRange()); // returns full bundle if policies not present @@ -1091,8 +1086,6 @@ public void testSubscribeRate() throws Exception { assertTrue(consumer.isConnected()); pulsar.getConfiguration().setAuthorizationEnabled(true); admin.topics().deletePartitionedTopic(topicName, true); - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespace); admin.tenants().deleteTenant("my-tenants"); } @@ -1241,4 +1234,4 @@ private void mockWebUrl(URL localWebServiceUrl, NamespaceName namespace) throws doReturn(true).when(nsSvc) .isServiceUnitOwned(Mockito.argThat(bundle -> bundle.getNamespaceObject().equals(namespace))); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java index 8efa4e8028c50..424e82fbc8eef 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java @@ -56,7 +56,6 @@ import org.apache.pulsar.broker.namespace.NamespaceEphemeralData; import org.apache.pulsar.broker.namespace.NamespaceService; import org.apache.pulsar.broker.service.BrokerService; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.LongRunningProcessStatus; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; @@ -75,7 +74,6 @@ import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.Schema; import org.apache.pulsar.client.api.SubscriptionType; -import org.apache.pulsar.common.events.EventType; import org.apache.pulsar.common.lookup.data.LookupData; import org.apache.pulsar.common.naming.NamespaceBundle; import org.apache.pulsar.common.naming.NamespaceBundleFactory; @@ -679,9 +677,6 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc } assertTrue(i < 10); - // Delete system topic first. - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1"), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "use"), Lists.newArrayList("prop-xyz/use/ns2")); @@ -708,7 +703,7 @@ public void persistentTopics(String topicName) throws Exception { final String persistentTopicName = "persistent://prop-xyz/use/ns1/" + topicName; // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/" + topicName, 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), + assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/" + topicName)); // create consumer and subscription @@ -777,7 +772,7 @@ public void persistentTopics(String topicName) throws Exception { } catch (NotFoundException e) { } - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList()); + assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList()); } @Test(dataProvider = "topicName") @@ -830,17 +825,17 @@ public void partitionedTopics(String topicName) throws Exception { assertEquals(admin.topics().getSubscriptions(partitionedTopicName), Lists.newArrayList("my-sub")); Producer producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); } - assertEquals(Sets.newHashSet(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1")), + assertEquals(Sets.newHashSet(admin.topics().getList("prop-xyz/use/ns1")), Sets.newHashSet(partitionedTopicName + "-partition-0", partitionedTopicName + "-partition-1", partitionedTopicName + "-partition-2", partitionedTopicName + "-partition-3")); @@ -888,14 +883,13 @@ public void partitionedTopics(String topicName) throws Exception { } producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); topics = admin.topics().getList("prop-xyz/use/ns1"); - // 4 partitions and 1 system topic - assertEquals(topics.size(), 4 + 1); + assertEquals(topics.size(), 4); try { admin.topics().deletePartitionedTopic(partitionedTopicName); @@ -939,11 +933,8 @@ public void testDeleteNamespaceBundle(Integer numBundles) throws Exception { admin.lookups().lookupTopic("persistent://prop-xyz/use/ns1-bundles/ds3"); admin.lookups().lookupTopic("persistent://prop-xyz/use/ns1-bundles/ds4"); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1-bundles"), Lists.newArrayList()); + assertEquals(admin.namespaces().getTopics("prop-xyz/use/ns1-bundles"), Lists.newArrayList()); - // Delete system topic first. - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get("prop-xyz/use/ns1-bundles"), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace("prop-xyz/use/ns1-bundles"); assertEquals(admin.namespaces().getNamespaces("prop-xyz", "use"), Lists.newArrayList()); } @@ -954,13 +945,13 @@ public void testNamespaceSplitBundle() throws Exception { final String namespace = "prop-xyz/use/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, null); @@ -984,13 +975,13 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { final String namespace = "prop-xyz/use/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(getTopicListAndTrimSystemTopic(namespace), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", false, null); @@ -1010,30 +1001,30 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { try { executorService.invokeAll( - Arrays.asList( - () -> - { - log.info("split 2 bundles at the same time. spilt: 0x00000000_0x7fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x7fffffff", false, null); - return null; - }, - () -> - { - log.info("split 2 bundles at the same time. spilt: 0x7fffffff_0xffffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xffffffff", false, null); - return null; - } - ) + Arrays.asList( + () -> + { + log.info("split 2 bundles at the same time. spilt: 0x00000000_0x7fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x7fffffff", false, null); + return null; + }, + () -> + { + log.info("split 2 bundles at the same time. spilt: 0x7fffffff_0xffffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xffffffff", false, null); + return null; + } + ) ); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } String[] splitRange4 = { - namespace + "/0x00000000_0x3fffffff", - namespace + "/0x3fffffff_0x7fffffff", - namespace + "/0x7fffffff_0xbfffffff", - namespace + "/0xbfffffff_0xffffffff"}; + namespace + "/0x00000000_0x3fffffff", + namespace + "/0x3fffffff_0x7fffffff", + namespace + "/0x7fffffff_0xbfffffff", + namespace + "/0xbfffffff_0xffffffff"}; bundles = bundleFactory.getBundles(NamespaceName.get(namespace)); assertEquals(bundles.getBundles().size(), 4); for (int i = 0; i < bundles.getBundles().size(); i++) { @@ -1042,46 +1033,46 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { try { executorService.invokeAll( - Arrays.asList( - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x00000000_0x3fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x3fffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x3fffffff_0x7fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x3fffffff_0x7fffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x7fffffff_0xbfffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xbfffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0xbfffffff_0xffffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0xbfffffff_0xffffffff", false, null); - return null; - } - ) + Arrays.asList( + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x00000000_0x3fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x3fffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x3fffffff_0x7fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x3fffffff_0x7fffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x7fffffff_0xbfffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xbfffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0xbfffffff_0xffffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0xbfffffff_0xffffffff", false, null); + return null; + } + ) ); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } String[] splitRange8 = { - namespace + "/0x00000000_0x1fffffff", - namespace + "/0x1fffffff_0x3fffffff", - namespace + "/0x3fffffff_0x5fffffff", - namespace + "/0x5fffffff_0x7fffffff", - namespace + "/0x7fffffff_0x9fffffff", - namespace + "/0x9fffffff_0xbfffffff", - namespace + "/0xbfffffff_0xdfffffff", - namespace + "/0xdfffffff_0xffffffff"}; + namespace + "/0x00000000_0x1fffffff", + namespace + "/0x1fffffff_0x3fffffff", + namespace + "/0x3fffffff_0x5fffffff", + namespace + "/0x5fffffff_0x7fffffff", + namespace + "/0x7fffffff_0x9fffffff", + namespace + "/0x9fffffff_0xbfffffff", + namespace + "/0xbfffffff_0xdfffffff", + namespace + "/0xdfffffff_0xffffffff"}; bundles = bundleFactory.getBundles(NamespaceName.get(namespace)); assertEquals(bundles.getBundles().size(), 8); for (int i = 0; i < bundles.getBundles().size(); i++) { @@ -1098,7 +1089,7 @@ public void testNamespaceUnloadBundle() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/ds2", 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), + assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/ds2")); // create consumer and subscription @@ -1109,10 +1100,10 @@ public void testNamespaceUnloadBundle() throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1159,7 +1150,7 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1-bundles/ds2", 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1-bundles"), + assertEquals(admin.topics().getList("prop-xyz/use/ns1-bundles"), Lists.newArrayList("persistent://prop-xyz/use/ns1-bundles/ds2")); // create consumer and subscription @@ -1170,10 +1161,10 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1226,10 +1217,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1239,10 +1230,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer1 = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer1.send(message.getBytes()); @@ -1336,10 +1327,10 @@ private void publishMessagesOnPersistentTopic(String topicName, int messages) th private void publishMessagesOnPersistentTopic(String topicName, int messages, int startIdx) throws Exception { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = startIdx; i < (messages + startIdx); i++) { String message = "message-" + i; @@ -1386,10 +1377,10 @@ public void statsOnNonExistingTopics() throws Exception { public void testDeleteFailedReturnCode() throws Exception { String topicName = "persistent://prop-xyz/use/ns1/my-topic"; Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { admin.topics().delete(topicName); @@ -1600,7 +1591,7 @@ public void partitionedTopicsCursorReset(String topicName) throws Exception { .subscriptionType(SubscriptionType.Exclusive) .acknowledgmentGroupTime(0, TimeUnit.SECONDS).subscribe(); - List topics = getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"); + List topics = admin.topics().getList("prop-xyz/use/ns1"); assertEquals(topics.size(), 4); assertEquals(admin.topics().getSubscriptions(topicName), Lists.newArrayList("my-sub")); @@ -1645,7 +1636,7 @@ public void persistentTopicsInvalidCursorReset() throws Exception { String topicName = "persistent://prop-xyz/use/ns1/invalidcursorreset"; // Force to create a topic publishMessagesOnPersistentTopic(topicName, 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), Lists.newArrayList(topicName)); + assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList(topicName)); // create consumer and subscription PulsarClient client = PulsarClient.builder() @@ -1722,7 +1713,7 @@ public void testPersistentTopicsExpireMessages() throws Exception { // Force to create a topic publishMessagesOnPersistentTopic("persistent://prop-xyz/use/ns1/ds2", 0); - assertEquals(getTopicListAndTrimSystemTopic("prop-xyz/use/ns1"), + assertEquals(admin.topics().getList("prop-xyz/use/ns1"), Lists.newArrayList("persistent://prop-xyz/use/ns1/ds2")); // create consumer and subscription @@ -1788,10 +1779,10 @@ public void testPersistentTopicExpireMessageOnParitionTopic() throws Exception { .subscriptionName("my-sub").subscribe(); Producer producer = client.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic("persistent://prop-xyz/use/ns1/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -2016,7 +2007,7 @@ public void testCompactionStatus() throws Exception { assertNotNull(pulsar.getBrokerService().getTopicReference(topicName)); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.NOT_RUN); + LongRunningProcessStatus.Status.NOT_RUN); // mock actual compaction, we don't need to really run it CompletableFuture promise = new CompletableFuture(); @@ -2025,12 +2016,12 @@ public void testCompactionStatus() throws Exception { admin.topics().triggerCompaction(topicName); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.RUNNING); + LongRunningProcessStatus.Status.RUNNING); promise.complete(1L); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.SUCCESS); + LongRunningProcessStatus.Status.SUCCESS); CompletableFuture errorPromise = new CompletableFuture(); doReturn(errorPromise).when(compactor).compact(topicName); @@ -2038,8 +2029,8 @@ public void testCompactionStatus() throws Exception { errorPromise.completeExceptionally(new Exception("Failed at something")); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.ERROR); + LongRunningProcessStatus.Status.ERROR); assertTrue(admin.topics().compactionStatus(topicName) - .lastError.contains("Failed at something")); + .lastError.contains("Failed at something")); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java index 08fd56734fead..d80ea79fa711c 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; -import static org.testng.Assert.assertTrue; import com.google.common.collect.Sets; import com.google.common.util.concurrent.MoreExecutors; @@ -50,17 +49,12 @@ import org.apache.pulsar.broker.PulsarService; import org.apache.pulsar.broker.ServiceConfiguration; import org.apache.pulsar.broker.namespace.NamespaceService; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; -import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.admin.PulsarAdmin; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.PulsarClient; import org.apache.pulsar.client.api.PulsarClientException; import org.apache.pulsar.common.policies.data.ClusterData; import org.apache.pulsar.common.policies.data.TenantInfo; -import org.apache.pulsar.common.events.EventType; -import org.apache.pulsar.common.naming.NamespaceName; -import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.compaction.Compactor; import org.apache.pulsar.zookeeper.ZooKeeperClientFactory; import org.apache.pulsar.zookeeper.ZookeeperClientFactoryImpl; @@ -146,8 +140,8 @@ protected final void init() throws Exception { sameThreadOrderedSafeExecutor = new SameThreadOrderedSafeExecutor(); bkExecutor = Executors.newSingleThreadExecutor( new ThreadFactoryBuilder().setNameFormat("mock-pulsar-bk") - .setUncaughtExceptionHandler((thread, ex) -> log.info("Uncaught exception", ex)) - .build()); + .setUncaughtExceptionHandler((thread, ex) -> log.info("Uncaught exception", ex)) + .build()); mockZooKeeper = createMockZooKeeper(); mockBookKeeper = createMockBookKeeper(mockZooKeeper, bkExecutor); @@ -296,7 +290,7 @@ public void reallyShutdown() { @Override public CompletableFuture create(String serverList, SessionType sessionType, - int zkSessionTimeoutMillis) { + int zkSessionTimeoutMillis) { // Always return the same instance (so that we don't loose the mock ZK content on broker restart return CompletableFuture.completedFuture(mockZooKeeper); } @@ -306,8 +300,8 @@ public CompletableFuture create(String serverList, SessionType sessio @Override public BookKeeper create(ServiceConfiguration conf, ZooKeeper zkClient, - Optional> ensemblePlacementPolicyClass, - Map properties) { + Optional> ensemblePlacementPolicyClass, + Map properties) { // Always return the same instance (so that we don't loose the mock BK content on broker restart return mockBookKeeper; } @@ -335,15 +329,5 @@ public static void setFieldValue(Class clazz, Object classObj, String fieldNa field.set(classObj, fieldValue); } - protected List getTopicListAndTrimSystemTopic(String namespace) throws PulsarAdminException { - List topicList = admin.topics().getList(namespace); - - // Check topic policy system topic and then delete them - assertTrue(topicList.contains(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString())); - topicList.removeIf(tn -> SystemTopicClient.isSystemTopic(TopicName.get(tn))); - return topicList; - } - private static final Logger log = LoggerFactory.getLogger(MockedPulsarServiceBaseTest.class); -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java index 21b6ecbdf618c..65d917bd473a6 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/loadbalance/AntiAffinityNamespaceGroupTest.java @@ -114,7 +114,6 @@ void setup() throws Exception { config1.setFailureDomainsEnabled(true); config1.setLoadBalancerEnabled(true); config1.setAdvertisedAddress("localhost"); - config1.setTopicLevelPoliciesEnabled(false); createCluster(bkEnsemble.getZkClient(), config1); pulsar1 = new PulsarService(config1); pulsar1.setShutdownService(new NoOpShutdownService()); @@ -132,7 +131,6 @@ void setup() throws Exception { config2.setZookeeperServers("127.0.0.1" + ":" + bkEnsemble.getZookeeperPort()); config2.setBrokerServicePort(Optional.of(0)); config2.setFailureDomainsEnabled(true); - config2.setTopicLevelPoliciesEnabled(false); pulsar2 = new PulsarService(config2); pulsar2.setShutdownService(new NoOpShutdownService()); pulsar2.start(); @@ -499,7 +497,7 @@ public void testLoadSheddingWithAntiAffinityNamespace() throws Exception { final String namespace = "my-tenant/use/my-ns"; final int totalNamespaces = 5; final String namespaceAntiAffinityGroup = "my-antiaffinity"; - final String bundle = "0x00000000_0x40000000"; + final String bundle = "0x00000000_0xffffffff"; admin1.tenants().createTenant("my-tenant", new TenantInfo(Sets.newHashSet("appid1", "appid2"), Sets.newHashSet("use"))); @@ -538,4 +536,4 @@ private NamespaceBundle makeBundle(final String property, final String cluster, BoundType.CLOSED)); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java index ee4b493d59170..f2fe3f5ec8c13 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/namespace/NamespaceOwnershipListenerTests.java @@ -20,7 +20,6 @@ import com.google.common.collect.Sets; import org.apache.pulsar.broker.service.BrokerTestBase; -import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.Producer; import org.apache.pulsar.client.api.PulsarClientException; @@ -127,4 +126,4 @@ public void testGetAllPartitions() throws PulsarAdminException, ExecutionExcepti admin.namespaces().deleteNamespace(namespace); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java index 666615e06f79b..c354165993593 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java @@ -389,8 +389,7 @@ public void testBrokerServiceNamespaceStats() throws Exception { rolloverPerIntervalStats(); JsonObject topicStats = brokerStatsClient.getTopics(); - // original topics and system topic for namespace event change - assertEquals(topicStats.size(), 3, topicStats.toString()); + assertEquals(topicStats.size(), 2, topicStats.toString()); for (String ns : nsList) { JsonObject nsObject = topicStats.getAsJsonObject(ns); @@ -416,7 +415,7 @@ public void testBrokerServiceNamespaceStats() throws Exception { for (String ns : nsList) { List topics = admin.namespaces().getTopics(ns); for (String dest : topics) { - admin.topics().delete(dest, true); + admin.topics().delete(dest); } admin.namespaces().deleteNamespace(ns); } @@ -760,7 +759,7 @@ public void testLookupThrottlingForClientByClient() throws Exception { fail("It should fail as throttling should only receive 2 requests"); } catch (Exception e) { if (!(e.getCause() instanceof - org.apache.pulsar.client.api.PulsarClientException.TooManyRequestsException)) { + org.apache.pulsar.client.api.PulsarClientException.TooManyRequestsException)) { fail("Subscribe should fail with TooManyRequestsException"); } } @@ -920,7 +919,7 @@ public void testCreateNamespacePolicy() throws Exception { /** * It verifies that unloading bundle gracefully closes managed-ledger before removing ownership to avoid bad-zk * version. - * + * * @throws Exception */ @Test @@ -962,4 +961,4 @@ public void testStuckTopicUnloading() throws Exception { } assertNull(ledgers.get(topicMlName)); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java index dde656237c549..db6ddac3bbeb9 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java @@ -52,7 +52,6 @@ import org.apache.pulsar.broker.service.persistent.PersistentSubscription; import org.apache.pulsar.broker.service.persistent.PersistentTopic; import org.apache.pulsar.broker.service.schema.SchemaRegistry; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.admin.PulsarAdminException; import org.apache.pulsar.client.api.CompressionType; import org.apache.pulsar.client.api.Consumer; @@ -76,8 +75,6 @@ import org.apache.pulsar.client.impl.TypedMessageBuilderImpl; import org.apache.pulsar.client.impl.schema.JSONSchema; import org.apache.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType; -import org.apache.pulsar.common.events.EventType; -import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.naming.TopicName; import org.apache.pulsar.common.policies.data.RetentionPolicies; import org.apache.pulsar.common.protocol.schema.SchemaData; @@ -113,10 +110,10 @@ public void testSimpleProducerEvents() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -158,10 +155,10 @@ public void testSimpleConsumerEvents() throws Exception { assertEquals(getAvailablePermits(subRef), 1000 /* default */); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs * 2; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -236,10 +233,10 @@ public void testConsumerFlowControl() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .receiverQueueSize(recvQueueSize).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -284,10 +281,10 @@ public void testActiveSubscriptionWithCache() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .receiverQueueSize(recvQueueSize).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // (2) Produce Messages for (int i = 0; i < recvQueueSize / 2; i++) { @@ -357,10 +354,10 @@ public Void call() throws Exception { } Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < recvQueueSize * numConsumersThreads; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -388,10 +385,10 @@ public void testGracefulClose() throws Exception { final String subName = "sub4"; Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); Thread.sleep(ASYNC_EVENT_COMPLETION_WAIT); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); @@ -455,10 +452,10 @@ public void testSimpleCloseTopic() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -487,10 +484,10 @@ public void testSingleClientMultipleSubscriptions() throws Exception { pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); fail("Should have thrown an exception since one consumer is already connected"); @@ -883,10 +880,10 @@ public void testMessageExpiry() throws Exception { assertFalse(subRef.getDispatcher().isConsumerConnected()); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -906,8 +903,6 @@ public void testMessageExpiry() throws Exception { consumer.close(); admin.topics().deleteSubscription(topicName, subName); admin.topics().delete(topicName); - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespaceName), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespaceName); } @@ -932,10 +927,10 @@ public void testMessageExpiryWithFewExpiredBacklog() throws Exception { assertTrue(subRef.getDispatcher().isConsumerConnected()); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -1043,10 +1038,10 @@ public void testReceiveWithTimeout() throws Exception { ConsumerImpl consumer = (ConsumerImpl) pulsarClient.newConsumer().topic(topicName) .subscriptionName(subName).receiverQueueSize(1000).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); assertEquals(consumer.getAvailablePermits(), 0); @@ -1074,10 +1069,10 @@ public void testProducerReturnedMessageId() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -1126,13 +1121,13 @@ public void testProducerQueueFullBlocking() throws Exception { // 1. Producer connect ProducerImpl producer = (ProducerImpl) client.newProducer() - .topic(topicName) - .maxPendingMessages(messages) - .blockIfQueueFull(true) - .sendTimeout(1, TimeUnit.SECONDS) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .maxPendingMessages(messages) + .blockIfQueueFull(true) + .sendTimeout(1, TimeUnit.SECONDS) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 2. Stop broker super.internalCleanup(); @@ -1173,13 +1168,13 @@ public void testProducerQueueFullNonBlocking() throws Exception { // 1. Producer connect PulsarClient client = PulsarClient.builder().serviceUrl(brokerUrl.toString()).build(); ProducerImpl producer = (ProducerImpl) client.newProducer() - .topic(topicName) - .maxPendingMessages(messages) - .blockIfQueueFull(false) - .sendTimeout(1, TimeUnit.SECONDS) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .maxPendingMessages(messages) + .blockIfQueueFull(false) + .sendTimeout(1, TimeUnit.SECONDS) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 2. Stop broker super.internalCleanup(); @@ -1222,15 +1217,15 @@ public void testDeleteTopics() throws Exception { // 1. producers connect Producer producer1 = pulsarClient.newProducer() - .topic("persistent://prop/ns-abc/topic-1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop/ns-abc/topic-1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); /* Producer producer2 = */ pulsarClient.newProducer() - .topic("persistent://prop/ns-abc/topic-2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop/ns-abc/topic-2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); brokerService.updateRates(); @@ -1270,11 +1265,11 @@ public void testCompression(CompressionType compressionType) throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .compressionType(compressionType) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .compressionType(compressionType) + .create(); Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName("my-sub").subscribe(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); @@ -1310,10 +1305,10 @@ public void testBrokerTopicStats() throws Exception { final String namespace = "prop/ns-abc"; Producer producer = pulsarClient.newProducer() - .topic("persistent://" + namespace + "/topic0") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://" + namespace + "/topic0") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 1. producer publish messages for (int i = 0; i < 10; i++) { String message = "my-message-" + i; @@ -1343,9 +1338,9 @@ public void testPayloadCorruptionDetection() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer().topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName("my-sub").subscribe(); CompletableFuture future1 = producer.newMessage().value("message-1".getBytes()).sendAsync(); @@ -1470,10 +1465,10 @@ public void testMessageReplay() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .subscriptionType(SubscriptionType.Shared).receiverQueueSize(1).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -1536,10 +1531,10 @@ public void testCreateProducerWithSameName() throws Exception { String topic = "persistent://prop/ns-abc/testCreateProducerWithSameName"; ProducerBuilder producerBuilder = pulsarClient.newProducer() - .topic(topic) - .producerName("test-producer-a") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition); + .topic(topic) + .producerName("test-producer-a") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition); Producer p1 = producerBuilder.create(); try { @@ -1595,4 +1590,4 @@ public void testWithEventTime() throws Exception { assertEquals(msg.getValue(), "test"); assertEquals(msg.getEventTime(), 5); } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java index 37725ad0d6465..132d8b17557be 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/SystemTopicBasedTopicPoliciesServiceTest.java @@ -54,6 +54,8 @@ public class SystemTopicBasedTopicPoliciesServiceTest extends MockedPulsarServic @BeforeMethod @Override protected void setup() throws Exception { + conf.setSystemTopicEnabled(true); + conf.setTopicLevelPoliciesEnabled(true); super.internalSetup(); prepareData(); } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java index fcd768099ea09..948bdbd31bcde 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/stats/PrometheusMetricsTest.java @@ -32,13 +32,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.StringUtils; import org.apache.pulsar.broker.service.BrokerTestBase; import org.apache.pulsar.broker.stats.prometheus.PrometheusMetricsGenerator; import org.apache.pulsar.client.api.Consumer; -import org.apache.pulsar.broker.systopic.SystemTopicClient; import org.apache.pulsar.client.api.Producer; -import org.apache.pulsar.common.naming.TopicName; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -103,43 +100,14 @@ public void testPerTopicStats() throws Exception { // There should be 2 metrics with different tags for each topic List cm = (List) metrics.get("pulsar_storage_write_latency_le_1"); - cm.removeIf(f -> { - String topicName = f.tags.get("topic"); - if (StringUtils.isNotBlank(topicName)) { - return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); - } else { - return false; - } - }); // 2 topics and 1 system topic assertEquals(cm.size(), 2); - assertEquals(cm.get(0).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic2"); assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); assertEquals(cm.get(1).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic1"); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); cm = (List) metrics.get("pulsar_producers_count"); - cm.removeIf(f -> { - String topicName = f.tags.get("topic"); - if (StringUtils.isNotBlank(topicName)) { - return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); - } else { - return false; - } - }); - - // 3 topics and 1 system topic assertEquals(cm.size(), 3); - cm.removeIf(f -> { - String topicName = f.tags.get("topic"); - if (StringUtils.isNotBlank(topicName)) { - return SystemTopicClient.isSystemTopic(TopicName.get(topicName)); - } else { - return false; - } - }); - assertEquals(cm.get(1).value, 1.0); - assertEquals(cm.get(1).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic2"); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); assertEquals(cm.get(2).tags.get("topic"), "persistent://my-property/use/my-ns/my-topic1"); @@ -147,9 +115,6 @@ public void testPerTopicStats() throws Exception { cm = (List) metrics.get("topic_load_times_count"); assertEquals(cm.size(), 1); - - // add 2.0 for system topic - assertEquals(cm.get(0).value, 4.0); assertEquals(cm.get(0).tags.get("cluster"), "test"); cm = (List) metrics.get("pulsar_in_bytes_total"); @@ -230,31 +195,15 @@ public void testPerNamespaceStats() throws Exception { // There should be 1 metric aggregated per namespace List cm = (List) metrics.get("pulsar_storage_write_latency_le_1"); + assertEquals(cm.size(), 1); + assertNull(cm.get(0).tags.get("topic")); + assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); + cm = (List) metrics.get("pulsar_producers_count"); assertEquals(cm.size(), 2); assertNull(cm.get(1).tags.get("topic")); assertEquals(cm.get(1).tags.get("namespace"), "my-property/use/my-ns"); - for (Metric metric : cm) { - assertNull(metric.tags.get("topic")); - assertTrue(metric.tags.get("namespace").equals("my-property/use/my-ns") - || metric.tags.get("namespace").startsWith("pulsar/test")); - } - cm = (List) metrics.get("pulsar_producers_count"); - assertEquals(cm.size(), 3); - for (Metric metric : cm) { - if (metric.tags.get("namespaces") != null) { - if (metric.tags.get("namespace").equals("my-property/use/my-ns")) { - assertEquals(metric.value, 2.0); - } else { - assertEquals(metric.value, 0.0); - } - assertTrue(metric.tags.get("namespace").equals("my-property/use/my-ns") - || metric.tags.get("namespace").startsWith("pulsar/test")); - } - assertNull(metric.tags.get("topic")); - } - cm = (List) metrics.get("pulsar_in_bytes_total"); assertEquals(cm.size(), 1); assertEquals(cm.get(0).tags.get("namespace"), "my-property/use/my-ns"); @@ -572,4 +521,4 @@ public String toString() { } } -} +} \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java index 3abbadc07c584..26b12b86d6f8b 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTest.java @@ -48,11 +48,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.apache.bookkeeper.test.PortManager; -import org.apache.pulsar.broker.systopic.NamespaceEventsSystemTopicFactory; import org.apache.pulsar.client.api.ProducerConsumerBase; -import org.apache.pulsar.common.events.EventType; -import org.apache.pulsar.common.naming.NamespaceName; import org.apache.pulsar.common.policies.data.BacklogQuota; import org.apache.pulsar.common.stats.Metrics; import org.apache.pulsar.websocket.WebSocketService; @@ -348,8 +344,6 @@ public void producerBacklogQuotaExceededTest() throws Exception { admin.topics().skipAllMessages("persistent://" + topic, subscription); admin.topics().delete("persistent://" + topic); admin.namespaces().removeBacklogQuota(namespace); - admin.topics().delete(NamespaceEventsSystemTopicFactory.getSystemTopicName(NamespaceName.get(namespace), - EventType.TOPIC_POLICY).toString(), true); admin.namespaces().deleteNamespace(namespace); } } @@ -618,4 +612,4 @@ private void stopWebSocketClient(WebSocketClient... clients) { } private static final Logger log = LoggerFactory.getLogger(ProxyPublishConsumeTest.class); -} +} \ No newline at end of file From 35b4e7056aacaa9e6afc04b34c0ed58a93d705bd Mon Sep 17 00:00:00 2001 From: penghui Date: Wed, 27 May 2020 15:31:36 +0800 Subject: [PATCH 31/31] Fix test format --- .../pulsar/broker/admin/AdminApiTest.java | 154 ++++++------- .../broker/admin/v1/V1_AdminApiTest.java | 202 +++++++++--------- .../auth/MockedPulsarServiceBaseTest.java | 10 +- .../broker/service/BrokerServiceTest.java | 2 +- .../service/PersistentTopicE2ETest.java | 180 ++++++++-------- 5 files changed, 274 insertions(+), 274 deletions(-) diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java index ccd0e27bddbba..a2cb3031f1246 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/AdminApiTest.java @@ -661,7 +661,7 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc // test with url style role. admin.namespaces().grantPermissionOnNamespace("prop-xyz/ns1", - "spiffe://developer/passport-role", EnumSet.allOf(AuthAction.class)); + "spiffe://developer/passport-role", EnumSet.allOf(AuthAction.class)); admin.namespaces().grantPermissionOnNamespace("prop-xyz/ns1", "my-role", EnumSet.allOf(AuthAction.class)); Policies policies = new Policies(); @@ -695,10 +695,10 @@ public void namespaces() throws PulsarAdminException, PulsarServerException, Exc // Force topic creation and namespace being loaded Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/my-topic") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1/my-topic") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.close(); admin.topics().delete("persistent://prop-xyz/ns1/my-topic"); @@ -886,10 +886,10 @@ public void partitionedTopics(String topicName) throws Exception { assertEquals(admin.topics().getSubscriptions(partitionedTopicName), Lists.newArrayList("my-sub")); Producer producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; @@ -944,10 +944,10 @@ public void partitionedTopics(String topicName) throws Exception { } producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); topics = admin.topics().getList("prop-xyz/ns1"); assertEquals(topics.size(), 4); @@ -1004,9 +1004,9 @@ public void testGetPartitionedInternalInfo() throws Exception { PartitionedManagedLedgerInfo partitionedManagedLedgerInfo = new PartitionedManagedLedgerInfo(); partitionedManagedLedgerInfo.version = 0L; partitionedManagedLedgerInfo.partitions.put(partitionTopic0, - ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic0Info), ManagedLedgerInfo.class)); + ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic0Info), ManagedLedgerInfo.class)); partitionedManagedLedgerInfo.partitions.put(partitionTopic1, - ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic1Info), ManagedLedgerInfo.class)); + ObjectMapperFactory.getThreadLocal().readValue(gson.toJson(partitionTopic1Info), ManagedLedgerInfo.class)); String expectedResult = ObjectMapperFactory.getThreadLocal().writeValueAsString(partitionedManagedLedgerInfo); @@ -1080,10 +1080,10 @@ public void testNamespaceSplitBundle() throws Exception { final String namespace = "prop-xyz/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); @@ -1109,16 +1109,16 @@ public void testNamespaceSplitBundleWithTopicCountEquallyDivideAlgorithm() throw // Force to create a topic final String namespace = "prop-xyz/ns1"; List topicNames = Lists.newArrayList( - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); List> producers = new ArrayList<>(2); for (String topicName : topicNames) { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producers.add(producer); producer.send("message".getBytes()); } @@ -1127,7 +1127,7 @@ public void testNamespaceSplitBundleWithTopicCountEquallyDivideAlgorithm() throw try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, - NamespaceBundleSplitAlgorithm.topicCountEquallyDivideName); + NamespaceBundleSplitAlgorithm.topicCountEquallyDivideName); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } @@ -1148,7 +1148,7 @@ public void testNamespaceSplitBundleWithInvalidAlgorithm() throws Exception { final String namespace = "prop-xyz/ns1"; try { admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0xffffffff", true, - "invalid_test"); + "invalid_test"); fail("unsupported namespace bundle split algorithm"); } catch (PulsarAdminException ignored) { } @@ -1160,16 +1160,16 @@ public void testNamespaceSplitBundleWithDefaultTopicCountEquallyDivideAlgorithm( // Force to create a topic final String namespace = "prop-xyz/ns1"; List topicNames = Lists.newArrayList( - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), - (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-1").toString(), + (new StringBuilder("persistent://")).append(namespace).append("/topicCountEquallyDivideAlgorithum-2").toString()); List> producers = new ArrayList<>(2); for (String topicName : topicNames) { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producers.add(producer); producer.send("message".getBytes()); } @@ -1199,10 +1199,10 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { final String namespace = "prop-xyz/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); @@ -1296,10 +1296,10 @@ public void testNamespaceUnloadBundle() throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1358,10 +1358,10 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1407,7 +1407,7 @@ public void testDeleteSubscription() throws Exception { // create a topic and produce some messages publishMessagesOnPersistentTopic(persistentTopicName, 5); assertEquals(admin.topics().getList("prop-xyz/ns1"), - Lists.newArrayList(persistentTopicName)); + Lists.newArrayList(persistentTopicName)); // create the subscription by PulsarAdmin admin.topics().createSubscription(persistentTopicName, subName, MessageId.earliest); @@ -1416,11 +1416,11 @@ public void testDeleteSubscription() throws Exception { // create consumer and subscription PulsarClient client = PulsarClient.builder() - .serviceUrl(pulsar.getWebServiceAddress()) - .statsInterval(0, TimeUnit.SECONDS) - .build(); + .serviceUrl(pulsar.getWebServiceAddress()) + .statsInterval(0, TimeUnit.SECONDS) + .build(); Consumer consumer = client.newConsumer().topic(persistentTopicName).subscriptionName(subName) - .subscriptionType(SubscriptionType.Exclusive).subscribe(); + .subscriptionType(SubscriptionType.Exclusive).subscribe(); // try to delete the subscription with a connected consumer try { @@ -1464,10 +1464,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1477,10 +1477,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer1 = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1-bundles/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/ns1-bundles/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer1.send(message.getBytes()); @@ -1580,10 +1580,10 @@ private void publishNullValueMessageOnPersistentTopic(String topicName, int mess private void publishMessagesOnPersistentTopic(String topicName, int messages, int startIdx, boolean nullValue) throws Exception { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = startIdx; i < (messages + startIdx); i++) { if (nullValue) { @@ -1634,10 +1634,10 @@ public void statsOnNonExistingTopics() throws Exception { public void testDeleteFailedReturnCode() throws Exception { String topicName = "persistent://prop-xyz/ns1/my-topic"; Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { admin.topics().delete(topicName); @@ -2103,10 +2103,10 @@ public void testPersistentTopicExpireMessageOnParitionTopic() throws Exception { .subscriptionName("my-sub").subscribe(); Producer producer = client.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/ns1/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic("persistent://prop-xyz/ns1/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -2404,7 +2404,7 @@ public void testCompactionStatus() throws Exception { assertNotNull(pulsar.getBrokerService().getTopicReference(topicName)); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.NOT_RUN); + LongRunningProcessStatus.Status.NOT_RUN); // mock actual compaction, we don't need to really run it CompletableFuture promise = new CompletableFuture(); @@ -2413,12 +2413,12 @@ public void testCompactionStatus() throws Exception { admin.topics().triggerCompaction(topicName); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.RUNNING); + LongRunningProcessStatus.Status.RUNNING); promise.complete(1L); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.SUCCESS); + LongRunningProcessStatus.Status.SUCCESS); CompletableFuture errorPromise = new CompletableFuture(); doReturn(errorPromise).when(compactor).compact(topicName); @@ -2426,7 +2426,7 @@ public void testCompactionStatus() throws Exception { errorPromise.completeExceptionally(new Exception("Failed at something")); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.ERROR); + LongRunningProcessStatus.Status.ERROR); assertTrue(admin.topics().compactionStatus(topicName).lastError.contains("Failed at something")); } @@ -2435,9 +2435,9 @@ public void testTopicStatsLastExpireTimestampForSubscription() throws PulsarAdmi admin.namespaces().setNamespaceMessageTTL("prop-xyz/ns1", 60); final String topic = "persistent://prop-xyz/ns1/testTopicStatsLastExpireTimestampForSubscription"; Consumer producer = pulsarClient.newConsumer() - .topic(topic) - .subscriptionName("sub-1") - .subscribe(); + .topic(topic) + .subscriptionName("sub-1") + .subscribe(); Assert.assertEquals(admin.topics().getStats(topic).subscriptions.size(), 1); Assert.assertEquals(admin.topics().getStats(topic).subscriptions.values().iterator().next().lastExpireTimestamp, 0L); diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java index 424e82fbc8eef..7b42a487c908a 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/admin/v1/V1_AdminApiTest.java @@ -825,10 +825,10 @@ public void partitionedTopics(String topicName) throws Exception { assertEquals(admin.topics().getSubscriptions(partitionedTopicName), Lists.newArrayList("my-sub")); Producer producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; @@ -883,10 +883,10 @@ public void partitionedTopics(String topicName) throws Exception { } producer = client.newProducer(Schema.BYTES) - .topic(partitionedTopicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(partitionedTopicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); topics = admin.topics().getList("prop-xyz/use/ns1"); assertEquals(topics.size(), 4); @@ -945,10 +945,10 @@ public void testNamespaceSplitBundle() throws Exception { final String namespace = "prop-xyz/use/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); @@ -975,10 +975,10 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { final String namespace = "prop-xyz/use/ns1"; final String topicName = (new StringBuilder("persistent://")).append(namespace).append("/ds2").toString(); Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); producer.send("message".getBytes()); publishMessagesOnPersistentTopic(topicName, 0); assertEquals(admin.topics().getList(namespace), Lists.newArrayList(topicName)); @@ -1001,30 +1001,30 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { try { executorService.invokeAll( - Arrays.asList( - () -> - { - log.info("split 2 bundles at the same time. spilt: 0x00000000_0x7fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x7fffffff", false, null); - return null; - }, - () -> - { - log.info("split 2 bundles at the same time. spilt: 0x7fffffff_0xffffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xffffffff", false, null); - return null; - } - ) + Arrays.asList( + () -> + { + log.info("split 2 bundles at the same time. spilt: 0x00000000_0x7fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x7fffffff", false, null); + return null; + }, + () -> + { + log.info("split 2 bundles at the same time. spilt: 0x7fffffff_0xffffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xffffffff", false, null); + return null; + } + ) ); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } String[] splitRange4 = { - namespace + "/0x00000000_0x3fffffff", - namespace + "/0x3fffffff_0x7fffffff", - namespace + "/0x7fffffff_0xbfffffff", - namespace + "/0xbfffffff_0xffffffff"}; + namespace + "/0x00000000_0x3fffffff", + namespace + "/0x3fffffff_0x7fffffff", + namespace + "/0x7fffffff_0xbfffffff", + namespace + "/0xbfffffff_0xffffffff"}; bundles = bundleFactory.getBundles(NamespaceName.get(namespace)); assertEquals(bundles.getBundles().size(), 4); for (int i = 0; i < bundles.getBundles().size(); i++) { @@ -1033,46 +1033,46 @@ public void testNamespaceSplitBundleConcurrent() throws Exception { try { executorService.invokeAll( - Arrays.asList( - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x00000000_0x3fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x3fffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x3fffffff_0x7fffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x3fffffff_0x7fffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0x7fffffff_0xbfffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xbfffffff", false, null); - return null; - }, - () -> - { - log.info("split 4 bundles at the same time. spilt: 0xbfffffff_0xffffffff "); - admin.namespaces().splitNamespaceBundle(namespace, "0xbfffffff_0xffffffff", false, null); - return null; - } - ) + Arrays.asList( + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x00000000_0x3fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x00000000_0x3fffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x3fffffff_0x7fffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x3fffffff_0x7fffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0x7fffffff_0xbfffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0x7fffffff_0xbfffffff", false, null); + return null; + }, + () -> + { + log.info("split 4 bundles at the same time. spilt: 0xbfffffff_0xffffffff "); + admin.namespaces().splitNamespaceBundle(namespace, "0xbfffffff_0xffffffff", false, null); + return null; + } + ) ); } catch (Exception e) { fail("split bundle shouldn't have thrown exception"); } String[] splitRange8 = { - namespace + "/0x00000000_0x1fffffff", - namespace + "/0x1fffffff_0x3fffffff", - namespace + "/0x3fffffff_0x5fffffff", - namespace + "/0x5fffffff_0x7fffffff", - namespace + "/0x7fffffff_0x9fffffff", - namespace + "/0x9fffffff_0xbfffffff", - namespace + "/0xbfffffff_0xdfffffff", - namespace + "/0xdfffffff_0xffffffff"}; + namespace + "/0x00000000_0x1fffffff", + namespace + "/0x1fffffff_0x3fffffff", + namespace + "/0x3fffffff_0x5fffffff", + namespace + "/0x5fffffff_0x7fffffff", + namespace + "/0x7fffffff_0x9fffffff", + namespace + "/0x9fffffff_0xbfffffff", + namespace + "/0xbfffffff_0xdfffffff", + namespace + "/0xdfffffff_0xffffffff"}; bundles = bundleFactory.getBundles(NamespaceName.get(namespace)); assertEquals(bundles.getBundles().size(), 8); for (int i = 0; i < bundles.getBundles().size(); i++) { @@ -1100,10 +1100,10 @@ public void testNamespaceUnloadBundle() throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1161,10 +1161,10 @@ public void testNamespaceBundleUnload(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1217,10 +1217,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -1230,10 +1230,10 @@ public void testClearBacklogOnNamespace(Integer numBundles) throws Exception { // Create producer Producer producer1 = pulsarClient.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1-bundles/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop-xyz/use/ns1-bundles/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer1.send(message.getBytes()); @@ -1327,10 +1327,10 @@ private void publishMessagesOnPersistentTopic(String topicName, int messages) th private void publishMessagesOnPersistentTopic(String topicName, int messages, int startIdx) throws Exception { Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = startIdx; i < (messages + startIdx); i++) { String message = "message-" + i; @@ -1377,10 +1377,10 @@ public void statsOnNonExistingTopics() throws Exception { public void testDeleteFailedReturnCode() throws Exception { String topicName = "persistent://prop-xyz/use/ns1/my-topic"; Producer producer = pulsarClient.newProducer(Schema.BYTES) - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { admin.topics().delete(topicName); @@ -1779,10 +1779,10 @@ public void testPersistentTopicExpireMessageOnParitionTopic() throws Exception { .subscriptionName("my-sub").subscribe(); Producer producer = client.newProducer(Schema.BYTES) - .topic("persistent://prop-xyz/use/ns1/ds1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) - .create(); + .topic("persistent://prop-xyz/use/ns1/ds1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.RoundRobinPartition) + .create(); for (int i = 0; i < 10; i++) { String message = "message-" + i; producer.send(message.getBytes()); @@ -2007,7 +2007,7 @@ public void testCompactionStatus() throws Exception { assertNotNull(pulsar.getBrokerService().getTopicReference(topicName)); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.NOT_RUN); + LongRunningProcessStatus.Status.NOT_RUN); // mock actual compaction, we don't need to really run it CompletableFuture promise = new CompletableFuture(); @@ -2016,12 +2016,12 @@ public void testCompactionStatus() throws Exception { admin.topics().triggerCompaction(topicName); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.RUNNING); + LongRunningProcessStatus.Status.RUNNING); promise.complete(1L); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.SUCCESS); + LongRunningProcessStatus.Status.SUCCESS); CompletableFuture errorPromise = new CompletableFuture(); doReturn(errorPromise).when(compactor).compact(topicName); @@ -2029,8 +2029,8 @@ public void testCompactionStatus() throws Exception { errorPromise.completeExceptionally(new Exception("Failed at something")); assertEquals(admin.topics().compactionStatus(topicName).status, - LongRunningProcessStatus.Status.ERROR); + LongRunningProcessStatus.Status.ERROR); assertTrue(admin.topics().compactionStatus(topicName) - .lastError.contains("Failed at something")); + .lastError.contains("Failed at something")); } } \ No newline at end of file diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java index d80ea79fa711c..6a162296ca0b2 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/auth/MockedPulsarServiceBaseTest.java @@ -140,8 +140,8 @@ protected final void init() throws Exception { sameThreadOrderedSafeExecutor = new SameThreadOrderedSafeExecutor(); bkExecutor = Executors.newSingleThreadExecutor( new ThreadFactoryBuilder().setNameFormat("mock-pulsar-bk") - .setUncaughtExceptionHandler((thread, ex) -> log.info("Uncaught exception", ex)) - .build()); + .setUncaughtExceptionHandler((thread, ex) -> log.info("Uncaught exception", ex)) + .build()); mockZooKeeper = createMockZooKeeper(); mockBookKeeper = createMockBookKeeper(mockZooKeeper, bkExecutor); @@ -290,7 +290,7 @@ public void reallyShutdown() { @Override public CompletableFuture create(String serverList, SessionType sessionType, - int zkSessionTimeoutMillis) { + int zkSessionTimeoutMillis) { // Always return the same instance (so that we don't loose the mock ZK content on broker restart return CompletableFuture.completedFuture(mockZooKeeper); } @@ -300,8 +300,8 @@ public CompletableFuture create(String serverList, SessionType sessio @Override public BookKeeper create(ServiceConfiguration conf, ZooKeeper zkClient, - Optional> ensemblePlacementPolicyClass, - Map properties) { + Optional> ensemblePlacementPolicyClass, + Map properties) { // Always return the same instance (so that we don't loose the mock BK content on broker restart return mockBookKeeper; } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java index c354165993593..282f8acf9347e 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/BrokerServiceTest.java @@ -759,7 +759,7 @@ public void testLookupThrottlingForClientByClient() throws Exception { fail("It should fail as throttling should only receive 2 requests"); } catch (Exception e) { if (!(e.getCause() instanceof - org.apache.pulsar.client.api.PulsarClientException.TooManyRequestsException)) { + org.apache.pulsar.client.api.PulsarClientException.TooManyRequestsException)) { fail("Subscribe should fail with TooManyRequestsException"); } } diff --git a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java index db6ddac3bbeb9..c8fef5509c317 100644 --- a/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java +++ b/pulsar-broker/src/test/java/org/apache/pulsar/broker/service/PersistentTopicE2ETest.java @@ -110,10 +110,10 @@ public void testSimpleProducerEvents() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -155,10 +155,10 @@ public void testSimpleConsumerEvents() throws Exception { assertEquals(getAvailablePermits(subRef), 1000 /* default */); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs * 2; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -233,10 +233,10 @@ public void testConsumerFlowControl() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .receiverQueueSize(recvQueueSize).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -281,10 +281,10 @@ public void testActiveSubscriptionWithCache() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .receiverQueueSize(recvQueueSize).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // (2) Produce Messages for (int i = 0; i < recvQueueSize / 2; i++) { @@ -354,10 +354,10 @@ public Void call() throws Exception { } Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < recvQueueSize * numConsumersThreads; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -385,10 +385,10 @@ public void testGracefulClose() throws Exception { final String subName = "sub4"; Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); Thread.sleep(ASYNC_EVENT_COMPLETION_WAIT); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); @@ -452,10 +452,10 @@ public void testSimpleCloseTopic() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -484,10 +484,10 @@ public void testSingleClientMultipleSubscriptions() throws Exception { pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); try { pulsarClient.newConsumer().topic(topicName).subscriptionName(subName).subscribe(); fail("Should have thrown an exception since one consumer is already connected"); @@ -880,10 +880,10 @@ public void testMessageExpiry() throws Exception { assertFalse(subRef.getDispatcher().isConsumerConnected()); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -927,10 +927,10 @@ public void testMessageExpiryWithFewExpiredBacklog() throws Exception { assertTrue(subRef.getDispatcher().isConsumerConnected()); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); for (int i = 0; i < numMsgs; i++) { String message = "my-message-" + i; producer.send(message.getBytes()); @@ -1038,10 +1038,10 @@ public void testReceiveWithTimeout() throws Exception { ConsumerImpl consumer = (ConsumerImpl) pulsarClient.newConsumer().topic(topicName) .subscriptionName(subName).receiverQueueSize(1000).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); assertEquals(consumer.getAvailablePermits(), 0); @@ -1069,10 +1069,10 @@ public void testProducerReturnedMessageId() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -1121,13 +1121,13 @@ public void testProducerQueueFullBlocking() throws Exception { // 1. Producer connect ProducerImpl producer = (ProducerImpl) client.newProducer() - .topic(topicName) - .maxPendingMessages(messages) - .blockIfQueueFull(true) - .sendTimeout(1, TimeUnit.SECONDS) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .maxPendingMessages(messages) + .blockIfQueueFull(true) + .sendTimeout(1, TimeUnit.SECONDS) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 2. Stop broker super.internalCleanup(); @@ -1168,13 +1168,13 @@ public void testProducerQueueFullNonBlocking() throws Exception { // 1. Producer connect PulsarClient client = PulsarClient.builder().serviceUrl(brokerUrl.toString()).build(); ProducerImpl producer = (ProducerImpl) client.newProducer() - .topic(topicName) - .maxPendingMessages(messages) - .blockIfQueueFull(false) - .sendTimeout(1, TimeUnit.SECONDS) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .maxPendingMessages(messages) + .blockIfQueueFull(false) + .sendTimeout(1, TimeUnit.SECONDS) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 2. Stop broker super.internalCleanup(); @@ -1217,15 +1217,15 @@ public void testDeleteTopics() throws Exception { // 1. producers connect Producer producer1 = pulsarClient.newProducer() - .topic("persistent://prop/ns-abc/topic-1") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop/ns-abc/topic-1") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); /* Producer producer2 = */ pulsarClient.newProducer() - .topic("persistent://prop/ns-abc/topic-2") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://prop/ns-abc/topic-2") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); brokerService.updateRates(); @@ -1265,11 +1265,11 @@ public void testCompression(CompressionType compressionType) throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .compressionType(compressionType) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .compressionType(compressionType) + .create(); Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName("my-sub").subscribe(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); @@ -1305,10 +1305,10 @@ public void testBrokerTopicStats() throws Exception { final String namespace = "prop/ns-abc"; Producer producer = pulsarClient.newProducer() - .topic("persistent://" + namespace + "/topic0") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic("persistent://" + namespace + "/topic0") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); // 1. producer publish messages for (int i = 0; i < 10; i++) { String message = "my-message-" + i; @@ -1338,9 +1338,9 @@ public void testPayloadCorruptionDetection() throws Exception { // 1. producer connect Producer producer = pulsarClient.newProducer().topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName("my-sub").subscribe(); CompletableFuture future1 = producer.newMessage().value("message-1".getBytes()).sendAsync(); @@ -1465,10 +1465,10 @@ public void testMessageReplay() throws Exception { Consumer consumer = pulsarClient.newConsumer().topic(topicName).subscriptionName(subName) .subscriptionType(SubscriptionType.Shared).receiverQueueSize(1).subscribe(); Producer producer = pulsarClient.newProducer() - .topic(topicName) - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition) - .create(); + .topic(topicName) + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition) + .create(); PersistentTopic topicRef = (PersistentTopic) pulsar.getBrokerService().getTopicReference(topicName).get(); assertNotNull(topicRef); @@ -1531,10 +1531,10 @@ public void testCreateProducerWithSameName() throws Exception { String topic = "persistent://prop/ns-abc/testCreateProducerWithSameName"; ProducerBuilder producerBuilder = pulsarClient.newProducer() - .topic(topic) - .producerName("test-producer-a") - .enableBatching(false) - .messageRoutingMode(MessageRoutingMode.SinglePartition); + .topic(topic) + .producerName("test-producer-a") + .enableBatching(false) + .messageRoutingMode(MessageRoutingMode.SinglePartition); Producer p1 = producerBuilder.create(); try {