Example usage for java.util.concurrent CompletableFuture completeExceptionally

List of usage examples for java.util.concurrent CompletableFuture completeExceptionally

Introduction

In this page you can find the example usage for java.util.concurrent CompletableFuture completeExceptionally.

Prototype

public boolean completeExceptionally(Throwable ex) 

Source Link

Document

If not already completed, causes invocations of #get() and related methods to throw the given exception.

Usage

From source file:org.apache.pulsar.broker.namespace.NamespaceService.java

protected CompletableFuture<LookupResult> createLookupResult(String candidateBroker) throws Exception {

    CompletableFuture<LookupResult> lookupFuture = new CompletableFuture<>();
    try {//from w w  w .  j  a  v a  2 s.c om
        checkArgument(StringUtils.isNotBlank(candidateBroker),
                "Lookup broker can't be null " + candidateBroker);
        URI uri = new URI(candidateBroker);
        String path = String.format("%s/%s:%s", LoadManager.LOADBALANCE_BROKERS_ROOT, uri.getHost(),
                uri.getPort());
        pulsar.getLocalZkCache().getDataAsync(path, pulsar.getLoadManager().get().getLoadReportDeserializer())
                .thenAccept(reportData -> {
                    if (reportData.isPresent()) {
                        ServiceLookupData lookupData = reportData.get();
                        lookupFuture.complete(new LookupResult(lookupData.getWebServiceUrl(),
                                lookupData.getWebServiceUrlTls(), lookupData.getPulsarServiceUrl(),
                                lookupData.getPulsarServiceUrlTls()));
                    } else {
                        lookupFuture.completeExceptionally(new KeeperException.NoNodeException(path));
                    }
                }).exceptionally(ex -> {
                    lookupFuture.completeExceptionally(ex);
                    return null;
                });
    } catch (Exception e) {
        lookupFuture.completeExceptionally(e);
    }
    return lookupFuture;
}

From source file:org.apache.pulsar.broker.namespace.NamespaceService.java

/**
 * 1. split the given bundle into two bundles 2. assign ownership of both the bundles to current broker 3. update
 * policies with newly created bundles into LocalZK 4. disable original bundle and refresh the cache
 *
 * @param bundle/*from  w  ww .  j  ava 2s  . c  o m*/
 * @return
 * @throws Exception
 */
public CompletableFuture<Void> splitAndOwnBundle(NamespaceBundle bundle) throws Exception {

    final CompletableFuture<Void> future = new CompletableFuture<>();

    Pair<NamespaceBundles, List<NamespaceBundle>> splittedBundles = bundleFactory.splitBundles(bundle,
            2 /* by default split into 2 */);
    if (splittedBundles != null) {
        checkNotNull(splittedBundles.getLeft());
        checkNotNull(splittedBundles.getRight());
        checkArgument(splittedBundles.getRight().size() == 2, "bundle has to be split in two bundles");
        NamespaceName nsname = bundle.getNamespaceObject();
        try {
            // take ownership of newly split bundles
            for (NamespaceBundle sBundle : splittedBundles.getRight()) {
                checkNotNull(ownershipCache.tryAcquiringOwnership(sBundle));
            }
            updateNamespaceBundles(nsname, splittedBundles.getLeft(),
                    (rc, path, zkCtx, stat) -> pulsar.getOrderedExecutor().submit(safeRun(() -> {
                        if (rc == KeeperException.Code.OK.intValue()) {
                            // disable old bundle
                            try {
                                ownershipCache.disableOwnership(bundle);
                                // invalidate cache as zookeeper has new split
                                // namespace bundle
                                bundleFactory.invalidateBundleCache(nsname);
                                // update bundled_topic cache for load-report-generation
                                pulsar.getBrokerService().refreshTopicToStatsMaps(bundle);
                                loadManager.get().setLoadReportForceUpdateFlag();
                                future.complete(null);
                            } catch (Exception e) {
                                String msg1 = format(
                                        "failed to disable bundle %s under namespace [%s] with error %s",
                                        nsname.toString(), bundle.toString(), e.getMessage());
                                LOG.warn(msg1, e);
                                future.completeExceptionally(new ServiceUnitNotReadyException(msg1));
                            }
                        } else {
                            String msg2 = format("failed to update namespace [%s] policies due to %s",
                                    nsname.toString(),
                                    KeeperException.create(KeeperException.Code.get(rc)).getMessage());
                            LOG.warn(msg2);
                            future.completeExceptionally(new ServiceUnitNotReadyException(msg2));
                        }
                    })));
        } catch (Exception e) {
            String msg = format("failed to aquire ownership of split bundle for namespace [%s], %s",
                    nsname.toString(), e.getMessage());
            LOG.warn(msg, e);
            future.completeExceptionally(new ServiceUnitNotReadyException(msg));
        }

    } else {
        String msg = format("bundle %s not found under namespace", bundle.toString());
        future.completeExceptionally(new ServiceUnitNotReadyException(msg));
    }
    return future;
}

From source file:org.apache.pulsar.broker.service.BrokerService.java

private void createPersistentTopic(final String topic, CompletableFuture<Topic> topicFuture) {

    final long topicCreateTimeMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
    DestinationName destinationName = DestinationName.get(topic);
    if (!pulsar.getNamespaceService().isServiceUnitActive(destinationName)) {
        // namespace is being unloaded
        String msg = String.format("Namespace is being unloaded, cannot add topic %s", topic);
        log.warn(msg);/*w  w  w .j a v  a  2s.c o m*/
        pulsar.getExecutor().submit(() -> topics.remove(topic, topicFuture));
        topicFuture.completeExceptionally(new ServiceUnitNotReadyException(msg));
        return;
    }

    getManagedLedgerConfig(destinationName).thenAccept(config -> {
        // Once we have the configuration, we can proceed with the async open operation

        managedLedgerFactory.asyncOpen(destinationName.getPersistenceNamingEncoding(), config,
                new OpenLedgerCallback() {
                    @Override
                    public void openLedgerComplete(ManagedLedger ledger, Object ctx) {
                        PersistentTopic persistentTopic = new PersistentTopic(topic, ledger,
                                BrokerService.this);

                        CompletableFuture<Void> replicationFuture = persistentTopic.checkReplication();
                        replicationFuture.thenRun(() -> {
                            log.info("Created topic {}", topic);
                            long topicLoadLatencyMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime())
                                    - topicCreateTimeMs;
                            pulsarStats.recordTopicLoadTimeValue(topic, topicLoadLatencyMs);
                            addTopicToStatsMaps(destinationName, persistentTopic);
                            topicFuture.complete(persistentTopic);
                        });
                        replicationFuture.exceptionally((ex) -> {
                            log.warn("Replication check failed. Removing topic from topics list {}, {}", topic,
                                    ex);
                            persistentTopic.stopReplProducers().whenComplete((v, exception) -> {
                                topics.remove(topic, topicFuture);
                                topicFuture.completeExceptionally(ex);
                            });

                            return null;
                        });
                    }

                    @Override
                    public void openLedgerFailed(ManagedLedgerException exception, Object ctx) {
                        log.warn("Failed to create topic {}", topic, exception);
                        topics.remove(topic, topicFuture);
                        topicFuture.completeExceptionally(new PersistenceException(exception));
                    }
                }, null);

    }).exceptionally((exception) -> {
        log.warn("[{}] Failed to get topic configuration: {}", topic, exception.getMessage(), exception);
        // remove topic from topics-map in different thread to avoid possible deadlock if
        // createPersistentTopic-thread only tries to handle this future-result
        pulsar.getExecutor().submit(() -> topics.remove(topic, topicFuture));
        topicFuture.completeExceptionally(exception);
        return null;
    });
}

From source file:org.apache.pulsar.broker.service.BrokerService.java

public CompletableFuture<ManagedLedgerConfig> getManagedLedgerConfig(DestinationName topicName) {
    CompletableFuture<ManagedLedgerConfig> future = new CompletableFuture<>();
    // Execute in background thread, since getting the policies might block if the z-node wasn't already cached
    pulsar.getOrderedExecutor().submitOrdered(topicName, safeRun(() -> {
        NamespaceName namespace = topicName.getNamespaceObject();
        ServiceConfiguration serviceConfig = pulsar.getConfiguration();

        // Get persistence policy for this destination
        Policies policies;/* ww  w .j a v a 2s . c  om*/
        try {
            policies = pulsar
                    .getConfigurationCache().policiesCache().get(AdminResource.path("policies",
                            namespace.getProperty(), namespace.getCluster(), namespace.getLocalName()))
                    .orElse(null);
        } catch (Throwable t) {
            // Ignoring since if we don't have policies, we fallback on the default
            log.warn("Got exception when reading persistence policy for {}: {}", topicName, t.getMessage(), t);
            future.completeExceptionally(t);
            return;
        }

        PersistencePolicies persistencePolicies = policies != null ? policies.persistence : null;
        RetentionPolicies retentionPolicies = policies != null ? policies.retention_policies : null;

        if (persistencePolicies == null) {
            // Apply default values
            persistencePolicies = new PersistencePolicies(serviceConfig.getManagedLedgerDefaultEnsembleSize(),
                    serviceConfig.getManagedLedgerDefaultWriteQuorum(),
                    serviceConfig.getManagedLedgerDefaultAckQuorum(),
                    serviceConfig.getManagedLedgerDefaultMarkDeleteRateLimit());
        }

        if (retentionPolicies == null) {
            retentionPolicies = new RetentionPolicies(serviceConfig.getDefaultRetentionTimeInMinutes(),
                    serviceConfig.getDefaultRetentionSizeInMB());
        }

        ManagedLedgerConfig config = new ManagedLedgerConfig();
        config.setEnsembleSize(persistencePolicies.getBookkeeperEnsemble());
        config.setWriteQuorumSize(persistencePolicies.getBookkeeperWriteQuorum());
        config.setAckQuorumSize(persistencePolicies.getBookkeeperAckQuorum());
        config.setThrottleMarkDelete(persistencePolicies.getManagedLedgerMaxMarkDeleteRate());
        config.setDigestType(DigestType.CRC32);

        config.setMaxUnackedRangesToPersist(serviceConfig.getManagedLedgerMaxUnackedRangesToPersist());
        config.setMaxEntriesPerLedger(serviceConfig.getManagedLedgerMaxEntriesPerLedger());
        config.setMinimumRolloverTime(serviceConfig.getManagedLedgerMinLedgerRolloverTimeMinutes(),
                TimeUnit.MINUTES);
        config.setMaximumRolloverTime(serviceConfig.getManagedLedgerMaxLedgerRolloverTimeMinutes(),
                TimeUnit.MINUTES);
        config.setMaxSizePerLedgerMb(2048);

        config.setMetadataEnsembleSize(serviceConfig.getManagedLedgerDefaultEnsembleSize());
        config.setMetadataWriteQuorumSize(serviceConfig.getManagedLedgerDefaultWriteQuorum());
        config.setMetadataAckQuorumSize(serviceConfig.getManagedLedgerDefaultAckQuorum());
        config.setMetadataMaxEntriesPerLedger(serviceConfig.getManagedLedgerCursorMaxEntriesPerLedger());

        config.setLedgerRolloverTimeout(serviceConfig.getManagedLedgerCursorRolloverTimeInSeconds());
        config.setRetentionTime(retentionPolicies.getRetentionTimeInMinutes(), TimeUnit.MINUTES);
        config.setRetentionSizeInMB(retentionPolicies.getRetentionSizeInMB());

        future.complete(config);
    }, (exception) -> future.completeExceptionally(exception)));

    return future;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

@Override
public CompletableFuture<Consumer> subscribe(final ServerCnx cnx, String subscriptionName, long consumerId,
        SubType subType, int priorityLevel, String consumerName, boolean isDurable, MessageId startMessageId,
        Map<String, String> metadata, boolean readCompacted, InitialPosition initialPosition) {

    final CompletableFuture<Consumer> future = new CompletableFuture<>();

    try {/*from  ww  w .j a  v a2s . c o m*/
        brokerService.checkTopicNsOwnership(getName());
    } catch (Exception e) {
        future.completeExceptionally(e);
        return future;
    }

    if (readCompacted && !(subType == SubType.Failover || subType == SubType.Exclusive)) {
        future.completeExceptionally(
                new NotAllowedException("readCompacted only allowed on failover or exclusive subscriptions"));
        return future;
    }
    if (isBlank(subscriptionName)) {
        if (log.isDebugEnabled()) {
            log.debug("[{}] Empty subscription name", topic);
        }
        future.completeExceptionally(new NamingException("Empty subscription name"));
        return future;
    }

    if (hasBatchMessagePublished && !cnx.isBatchMessageCompatibleVersion()) {
        if (log.isDebugEnabled()) {
            log.debug("[{}] Consumer doesn't support batch-message {}", topic, subscriptionName);
        }
        future.completeExceptionally(new UnsupportedVersionException("Consumer doesn't support batch-message"));
        return future;
    }

    if (subscriptionName.startsWith(replicatorPrefix) || subscriptionName.equals(DEDUPLICATION_CURSOR_NAME)) {
        log.warn("[{}] Failed to create subscription for {}", topic, subscriptionName);
        future.completeExceptionally(
                new NamingException("Subscription with reserved subscription name attempted"));
        return future;
    }

    if (cnx.getRemoteAddress() != null && cnx.getRemoteAddress().toString().contains(":")) {
        SubscribeRateLimiter.ConsumerIdentifier consumer = new SubscribeRateLimiter.ConsumerIdentifier(
                cnx.getRemoteAddress().toString().split(":")[0], consumerName, consumerId);
        if (subscribeRateLimiter.isPresent() && !subscribeRateLimiter.get().subscribeAvailable(consumer)
                || !subscribeRateLimiter.get().tryAcquire(consumer)) {
            log.warn("[{}] Failed to create subscription for {} {} limited by {}, available {}", topic,
                    subscriptionName, consumer, subscribeRateLimiter.get().getSubscribeRate(),
                    subscribeRateLimiter.get().getAvailableSubscribeRateLimit(consumer));
            future.completeExceptionally(
                    new NotAllowedException("Subscribe limited by subscribe rate limit per consumer."));
            return future;
        }
    }

    lock.readLock().lock();
    try {
        if (isFenced) {
            log.warn("[{}] Attempting to subscribe to a fenced topic", topic);
            future.completeExceptionally(new TopicFencedException("Topic is temporarily unavailable"));
            return future;
        }
        USAGE_COUNT_UPDATER.incrementAndGet(this);
        if (log.isDebugEnabled()) {
            log.debug("[{}] [{}] [{}] Added consumer -- count: {}", topic, subscriptionName, consumerName,
                    USAGE_COUNT_UPDATER.get(this));
        }
    } finally {
        lock.readLock().unlock();
    }

    CompletableFuture<? extends Subscription> subscriptionFuture = isDurable ? //
            getDurableSubscription(subscriptionName, initialPosition) //
            : getNonDurableSubscription(subscriptionName, startMessageId);

    int maxUnackedMessages = isDurable
            ? brokerService.pulsar().getConfiguration().getMaxUnackedMessagesPerConsumer()
            : 0;

    subscriptionFuture.thenAccept(subscription -> {
        try {
            Consumer consumer = new Consumer(subscription, subType, topic, consumerId, priorityLevel,
                    consumerName, maxUnackedMessages, cnx, cnx.getRole(), metadata, readCompacted,
                    initialPosition);
            subscription.addConsumer(consumer);
            if (!cnx.isActive()) {
                consumer.close();
                if (log.isDebugEnabled()) {
                    log.debug("[{}] [{}] [{}] Subscribe failed -- count: {}", topic, subscriptionName,
                            consumer.consumerName(), USAGE_COUNT_UPDATER.get(PersistentTopic.this));
                }
                future.completeExceptionally(
                        new BrokerServiceException("Connection was closed while the opening the cursor "));
            } else {
                log.info("[{}][{}] Created new subscription for {}", topic, subscriptionName, consumerId);
                future.complete(consumer);
            }
        } catch (BrokerServiceException e) {
            if (e instanceof ConsumerBusyException) {
                log.warn("[{}][{}] Consumer {} {} already connected", topic, subscriptionName, consumerId,
                        consumerName);
            } else if (e instanceof SubscriptionBusyException) {
                log.warn("[{}][{}] {}", topic, subscriptionName, e.getMessage());
            }

            USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this);
            future.completeExceptionally(e);
        }
    }).exceptionally(ex -> {
        log.warn("[{}] Failed to create subscription for {}: ", topic, subscriptionName, ex.getMessage());
        USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this);
        future.completeExceptionally(new PersistenceException(ex));
        return null;
    });

    return future;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

private CompletableFuture<Subscription> getDurableSubscription(String subscriptionName,
        InitialPosition initialPosition) {
    CompletableFuture<Subscription> subscriptionFuture = new CompletableFuture<>();
    ledger.asyncOpenCursor(Codec.encode(subscriptionName), initialPosition, new OpenCursorCallback() {
        @Override//  ww w  . j  av a  2 s  . c  om
        public void openCursorComplete(ManagedCursor cursor, Object ctx) {
            if (log.isDebugEnabled()) {
                log.debug("[{}][{}] Opened cursor", topic, subscriptionName);
            }

            subscriptionFuture.complete(subscriptions.computeIfAbsent(subscriptionName,
                    name -> createPersistentSubscription(subscriptionName, cursor)));
        }

        @Override
        public void openCursorFailed(ManagedLedgerException exception, Object ctx) {
            log.warn("[{}] Failed to create subscription for {}: {}", topic, subscriptionName,
                    exception.getMessage());
            USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this);
            subscriptionFuture.completeExceptionally(new PersistenceException(exception));
            if (exception instanceof ManagedLedgerFencedException) {
                // If the managed ledger has been fenced, we cannot continue using it. We need to close and reopen
                close();
            }
        }
    }, null);
    return subscriptionFuture;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

private CompletableFuture<? extends Subscription> getNonDurableSubscription(String subscriptionName,
        MessageId startMessageId) {/*www .j a  v  a 2  s .  c om*/
    CompletableFuture<Subscription> subscriptionFuture = new CompletableFuture<>();
    log.info("[{}][{}] Creating non-durable subscription at msg id {}", topic, subscriptionName,
            startMessageId);

    // Create a new non-durable cursor only for the first consumer that connects
    Subscription subscription = subscriptions.computeIfAbsent(subscriptionName, name -> {
        MessageIdImpl msgId = startMessageId != null ? (MessageIdImpl) startMessageId
                : (MessageIdImpl) MessageId.latest;

        long ledgerId = msgId.getLedgerId();
        long entryId = msgId.getEntryId();
        if (msgId instanceof BatchMessageIdImpl) {
            // When the start message is relative to a batch, we need to take one step back on the previous message,
            // because the "batch" might not have been consumed in its entirety.
            // The client will then be able to discard the first messages in the batch.
            if (((BatchMessageIdImpl) msgId).getBatchIndex() >= 0) {
                entryId = msgId.getEntryId() - 1;
            }
        }
        Position startPosition = new PositionImpl(ledgerId, entryId);
        ManagedCursor cursor = null;
        try {
            cursor = ledger.newNonDurableCursor(startPosition);
        } catch (ManagedLedgerException e) {
            subscriptionFuture.completeExceptionally(e);
        }

        return new PersistentSubscription(this, subscriptionName, cursor);
    });

    if (!subscriptionFuture.isDone()) {
        subscriptionFuture.complete(subscription);
    } else {
        // failed to initialize managed-cursor: clean up created subscription
        subscriptions.remove(subscriptionName);
    }

    return subscriptionFuture;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

/**
 * Delete the cursor ledger for a given subscription
 *
 * @param subscriptionName/*  w w  w .  ja  v a  2 s .c o m*/
 *            Subscription for which the cursor ledger is to be deleted
 * @return Completable future indicating completion of unsubscribe operation Completed exceptionally with:
 *         ManagedLedgerException if cursor ledger delete fails
 */
@Override
public CompletableFuture<Void> unsubscribe(String subscriptionName) {
    CompletableFuture<Void> unsubscribeFuture = new CompletableFuture<>();

    ledger.asyncDeleteCursor(Codec.encode(subscriptionName), new DeleteCursorCallback() {
        @Override
        public void deleteCursorComplete(Object ctx) {
            if (log.isDebugEnabled()) {
                log.debug("[{}][{}] Cursor deleted successfully", topic, subscriptionName);
            }
            subscriptions.remove(subscriptionName);
            unsubscribeFuture.complete(null);
            lastActive = System.nanoTime();
        }

        @Override
        public void deleteCursorFailed(ManagedLedgerException exception, Object ctx) {
            if (log.isDebugEnabled()) {
                log.debug("[{}][{}] Error deleting cursor for subscription", topic, subscriptionName,
                        exception);
            }
            unsubscribeFuture.completeExceptionally(new PersistenceException(exception));
        }
    }, null);

    return unsubscribeFuture;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

/**
 * Delete the managed ledger associated with this topic
 *
 * @param failIfHasSubscriptions//from w  w  w.j a  va2 s  . c om
 *            Flag indicating whether delete should succeed if topic still has unconnected subscriptions. Set to
 *            false when called from admin API (it will delete the subs too), and set to true when called from GC
 *            thread
 * @param closeIfClientsConnected
 *            Flag indicate whether explicitly close connected producers/consumers/replicators before trying to delete topic. If
 *            any client is connected to a topic and if this flag is disable then this operation fails.
 *
 * @return Completable future indicating completion of delete operation Completed exceptionally with:
 *         IllegalStateException if topic is still active ManagedLedgerException if ledger delete operation fails
 */
private CompletableFuture<Void> delete(boolean failIfHasSubscriptions, boolean closeIfClientsConnected) {
    CompletableFuture<Void> deleteFuture = new CompletableFuture<>();

    lock.writeLock().lock();
    try {
        if (isFenced) {
            log.warn("[{}] Topic is already being closed or deleted", topic);
            deleteFuture.completeExceptionally(new TopicFencedException("Topic is already fenced"));
            return deleteFuture;
        }

        CompletableFuture<Void> closeClientFuture = new CompletableFuture<>();
        if (closeIfClientsConnected) {
            List<CompletableFuture<Void>> futures = Lists.newArrayList();
            replicators.forEach((cluster, replicator) -> futures.add(replicator.disconnect()));
            producers.forEach(producer -> futures.add(producer.disconnect()));
            subscriptions.forEach((s, sub) -> futures.add(sub.disconnect()));
            FutureUtil.waitForAll(futures).thenRun(() -> {
                closeClientFuture.complete(null);
            }).exceptionally(ex -> {
                log.error("[{}] Error closing clients", topic, ex);
                isFenced = false;
                closeClientFuture.completeExceptionally(ex);
                return null;
            });
        } else {
            closeClientFuture.complete(null);
        }

        closeClientFuture.thenAccept(delete -> {
            if (USAGE_COUNT_UPDATER.get(this) == 0) {
                isFenced = true;

                List<CompletableFuture<Void>> futures = Lists.newArrayList();

                if (failIfHasSubscriptions) {
                    if (!subscriptions.isEmpty()) {
                        isFenced = false;
                        deleteFuture.completeExceptionally(new TopicBusyException("Topic has subscriptions"));
                        return;
                    }
                } else {
                    subscriptions.forEach((s, sub) -> futures.add(sub.delete()));
                }

                FutureUtil.waitForAll(futures).whenComplete((v, ex) -> {
                    if (ex != null) {
                        log.error("[{}] Error deleting topic", topic, ex);
                        isFenced = false;
                        deleteFuture.completeExceptionally(ex);
                    } else {
                        ledger.asyncDelete(new AsyncCallbacks.DeleteLedgerCallback() {
                            @Override
                            public void deleteLedgerComplete(Object ctx) {
                                brokerService.removeTopicFromCache(topic);
                                log.info("[{}] Topic deleted", topic);
                                deleteFuture.complete(null);
                            }

                            @Override
                            public void deleteLedgerFailed(ManagedLedgerException exception, Object ctx) {
                                isFenced = false;
                                log.error("[{}] Error deleting topic", topic, exception);
                                deleteFuture.completeExceptionally(new PersistenceException(exception));
                            }
                        }, null);
                    }
                });
            } else {
                deleteFuture.completeExceptionally(new TopicBusyException(
                        "Topic has " + USAGE_COUNT_UPDATER.get(this) + " connected producers/consumers"));
            }
        }).exceptionally(ex -> {
            deleteFuture.completeExceptionally(
                    new TopicBusyException("Failed to close clients before deleting topic."));
            return null;
        });
    } finally {
        lock.writeLock().unlock();
    }

    return deleteFuture;
}

From source file:org.apache.pulsar.broker.service.persistent.PersistentTopic.java

/**
 * Close this topic - close all producers and subscriptions associated with this topic
 *
 * @return Completable future indicating completion of close operation
 *///  ww w. j  a v a  2  s  .  c  o m
@Override
public CompletableFuture<Void> close() {
    CompletableFuture<Void> closeFuture = new CompletableFuture<>();

    lock.writeLock().lock();
    try {
        if (!isFenced) {
            isFenced = true;
        } else {
            log.warn("[{}] Topic is already being closed or deleted", topic);
            closeFuture.completeExceptionally(new TopicFencedException("Topic is already fenced"));
            return closeFuture;
        }
    } finally {
        lock.writeLock().unlock();
    }

    List<CompletableFuture<Void>> futures = Lists.newArrayList();

    replicators.forEach((cluster, replicator) -> futures.add(replicator.disconnect()));
    producers.forEach(producer -> futures.add(producer.disconnect()));
    subscriptions.forEach((s, sub) -> futures.add(sub.disconnect()));

    FutureUtil.waitForAll(futures).thenRun(() -> {
        // After having disconnected all producers/consumers, close the managed ledger
        ledger.asyncClose(new CloseCallback() {
            @Override
            public void closeComplete(Object ctx) {
                // Everything is now closed, remove the topic from map
                brokerService.removeTopicFromCache(topic);

                log.info("[{}] Topic closed", topic);
                closeFuture.complete(null);
            }

            @Override
            public void closeFailed(ManagedLedgerException exception, Object ctx) {
                log.error("[{}] Failed to close managed ledger, proceeding anyway.", topic, exception);
                brokerService.removeTopicFromCache(topic);
                closeFuture.complete(null);
            }
        }, null);

        if (dispatchRateLimiter.isPresent()) {
            dispatchRateLimiter.get().close();
        }
        if (subscribeRateLimiter.isPresent()) {
            subscribeRateLimiter.get().close();
        }

    }).exceptionally(exception -> {
        log.error("[{}] Error closing topic", topic, exception);
        isFenced = false;
        closeFuture.completeExceptionally(exception);
        return null;
    });

    return closeFuture;
}