Search in sources :

Example 11 with Consumer

use of com.yahoo.pulsar.broker.service.Consumer in project pulsar by yahoo.

the class PersistentTopicConcurrentTest method testConcurrentTopicAndSubscriptionDelete.

// @Test
public void testConcurrentTopicAndSubscriptionDelete() throws Exception {
    // create topic
    final PersistentTopic topic = (PersistentTopic) brokerService.getTopic(successTopicName).get();
    PulsarApi.CommandSubscribe cmd = PulsarApi.CommandSubscribe.newBuilder().setConsumerId(1).setTopic(successTopicName).setSubscription(successSubName).setRequestId(1).setSubType(PulsarApi.CommandSubscribe.SubType.Exclusive).build();
    Future<Consumer> f1 = topic.subscribe(serverCnx, cmd.getSubscription(), cmd.getConsumerId(), cmd.getSubType(), 0, cmd.getConsumerName());
    f1.get();
    final CyclicBarrier barrier = new CyclicBarrier(2);
    final CountDownLatch counter = new CountDownLatch(2);
    final AtomicBoolean gotException = new AtomicBoolean(false);
    Thread deleter = new Thread() {

        public void run() {
            try {
                barrier.await();
                // assertTrue(topic.unsubscribe(successSubName).isDone());
                Thread.sleep(5, 0);
                log.info("deleter outcome is {}", topic.delete().get());
            } catch (Exception e) {
                e.printStackTrace();
                gotException.set(true);
            } finally {
                counter.countDown();
            }
        }
    };
    Thread unsubscriber = new Thread() {

        public void run() {
            try {
                barrier.await();
                // do subscription delete
                ConcurrentOpenHashMap<String, PersistentSubscription> subscriptions = topic.getSubscriptions();
                PersistentSubscription ps = subscriptions.get(successSubName);
                // Thread.sleep(2,0);
                log.info("unsubscriber outcome is {}", ps.doUnsubscribe(ps.getConsumers().get(0)).get());
            // assertFalse(ps.delete().isCompletedExceptionally());
            } catch (Exception e) {
                e.printStackTrace();
                gotException.set(true);
            } finally {
                counter.countDown();
            }
        }
    };
    deleter.start();
    unsubscriber.start();
    counter.await();
    assertEquals(gotException.get(), false);
}
Also used : PulsarApi(com.yahoo.pulsar.common.api.proto.PulsarApi) CountDownLatch(java.util.concurrent.CountDownLatch) PersistentSubscription(com.yahoo.pulsar.broker.service.persistent.PersistentSubscription) CyclicBarrier(java.util.concurrent.CyclicBarrier) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Consumer(com.yahoo.pulsar.broker.service.Consumer) PersistentTopic(com.yahoo.pulsar.broker.service.persistent.PersistentTopic)

Example 12 with Consumer

use of com.yahoo.pulsar.broker.service.Consumer in project pulsar by yahoo.

the class PersistentTopic method updateRates.

public void updateRates(NamespaceStats nsStats, NamespaceBundleStats bundleStats, StatsOutputStream destStatsStream, ClusterReplicationMetrics replStats, String namespace) {
    TopicStats topicStats = threadLocalTopicStats.get();
    topicStats.reset();
    replicators.forEach((region, replicator) -> replicator.updateRates());
    nsStats.producerCount += producers.size();
    bundleStats.producerCount += producers.size();
    destStatsStream.startObject(topic);
    producers.forEach(producer -> {
        producer.updateRates();
        PublisherStats publisherStats = producer.getStats();
        topicStats.aggMsgRateIn += publisherStats.msgRateIn;
        topicStats.aggMsgThroughputIn += publisherStats.msgThroughputIn;
        if (producer.isRemote()) {
            topicStats.remotePublishersStats.put(producer.getRemoteCluster(), publisherStats);
        }
    });
    // Creating publishers object for backward compatibility
    destStatsStream.startList("publishers");
    destStatsStream.endList();
    // Start replicator stats
    destStatsStream.startObject("replication");
    nsStats.replicatorCount += topicStats.remotePublishersStats.size();
    replicators.forEach((cluster, replicator) -> {
        // Update replicator cursor state
        replicator.updateCursorState();
        // Update replicator stats
        ReplicatorStats rStat = replicator.getStats();
        // Add incoming msg rates
        PublisherStats pubStats = topicStats.remotePublishersStats.get(replicator.getRemoteCluster());
        if (pubStats != null) {
            rStat.msgRateIn = pubStats.msgRateIn;
            rStat.msgThroughputIn = pubStats.msgThroughputIn;
            rStat.inboundConnection = pubStats.address;
            rStat.inboundConnectedSince = pubStats.connectedSince;
        }
        topicStats.aggMsgRateOut += rStat.msgRateOut;
        topicStats.aggMsgThroughputOut += rStat.msgThroughputOut;
        // Populate replicator specific stats here
        destStatsStream.startObject(cluster);
        destStatsStream.writePair("connected", rStat.connected);
        destStatsStream.writePair("msgRateExpired", rStat.msgRateExpired);
        destStatsStream.writePair("msgRateIn", rStat.msgRateIn);
        destStatsStream.writePair("msgRateOut", rStat.msgRateOut);
        destStatsStream.writePair("msgThroughputIn", rStat.msgThroughputIn);
        destStatsStream.writePair("msgThroughputOut", rStat.msgThroughputOut);
        destStatsStream.writePair("replicationBacklog", rStat.replicationBacklog);
        destStatsStream.writePair("replicationDelayInSeconds", rStat.replicationDelayInSeconds);
        destStatsStream.writePair("inboundConnection", rStat.inboundConnection);
        destStatsStream.writePair("inboundConnectedSince", rStat.inboundConnectedSince);
        destStatsStream.writePair("outboundConnection", rStat.outboundConnection);
        destStatsStream.writePair("outboundConnectedSince", rStat.outboundConnectedSince);
        destStatsStream.endObject();
        nsStats.msgReplBacklog += rStat.replicationBacklog;
        if (replStats.isMetricsEnabled()) {
            String namespaceClusterKey = replStats.getKeyName(namespace, cluster);
            ReplicationMetrics replicationMetrics = replStats.get(namespaceClusterKey);
            boolean update = false;
            if (replicationMetrics == null) {
                replicationMetrics = ReplicationMetrics.get();
                update = true;
            }
            replicationMetrics.connected += rStat.connected ? 1 : 0;
            replicationMetrics.msgRateOut += rStat.msgRateOut;
            replicationMetrics.msgThroughputOut += rStat.msgThroughputOut;
            replicationMetrics.msgReplBacklog += rStat.replicationBacklog;
            if (update) {
                replStats.put(namespaceClusterKey, replicationMetrics);
            }
        }
    });
    // Close replication
    destStatsStream.endObject();
    // Start subscription stats
    destStatsStream.startObject("subscriptions");
    nsStats.subsCount += subscriptions.size();
    subscriptions.forEach((subscriptionName, subscription) -> {
        double subMsgRateOut = 0;
        double subMsgThroughputOut = 0;
        double subMsgRateRedeliver = 0;
        long subUnackedMessages = 0;
        // Start subscription name & consumers
        try {
            destStatsStream.startObject(subscriptionName);
            Object[] consumers = subscription.getConsumers().array();
            nsStats.consumerCount += consumers.length;
            bundleStats.consumerCount += consumers.length;
            destStatsStream.startList("consumers");
            for (Object consumerObj : consumers) {
                Consumer consumer = (Consumer) consumerObj;
                consumer.updateRates();
                ConsumerStats consumerStats = consumer.getStats();
                subMsgRateOut += consumerStats.msgRateOut;
                subMsgThroughputOut += consumerStats.msgThroughputOut;
                subMsgRateRedeliver += consumerStats.msgRateRedeliver;
                subUnackedMessages += consumerStats.unackedMessages;
                // Populate consumer specific stats here
                destStatsStream.startObject();
                destStatsStream.writePair("address", consumerStats.address);
                destStatsStream.writePair("consumerName", consumerStats.consumerName);
                destStatsStream.writePair("availablePermits", consumerStats.availablePermits);
                destStatsStream.writePair("unackedMessages", consumerStats.unackedMessages);
                destStatsStream.writePair("blockedConsumerOnUnackedMsgs", consumerStats.blockedConsumerOnUnackedMsgs);
                destStatsStream.writePair("connectedSince", consumerStats.connectedSince);
                destStatsStream.writePair("msgRateOut", consumerStats.msgRateOut);
                destStatsStream.writePair("msgThroughputOut", consumerStats.msgThroughputOut);
                destStatsStream.writePair("msgRateRedeliver", consumerStats.msgRateRedeliver);
                destStatsStream.endObject();
            }
            // Close Consumer stats
            destStatsStream.endList();
            // Populate subscription specific stats here
            destStatsStream.writePair("msgBacklog", subscription.getNumberOfEntriesInBacklog());
            destStatsStream.writePair("msgRateExpired", subscription.getExpiredMessageRate());
            destStatsStream.writePair("msgRateOut", subMsgRateOut);
            destStatsStream.writePair("msgThroughputOut", subMsgThroughputOut);
            destStatsStream.writePair("msgRateRedeliver", subMsgRateRedeliver);
            destStatsStream.writePair("unackedMessages", subUnackedMessages);
            destStatsStream.writePair("type", subscription.getTypeString());
            // Close consumers
            destStatsStream.endObject();
            topicStats.aggMsgRateOut += subMsgRateOut;
            topicStats.aggMsgThroughputOut += subMsgThroughputOut;
            nsStats.msgBacklog += subscription.getNumberOfEntriesInBacklog();
        } catch (Exception e) {
            log.error("Got exception when creating consumer stats for subscription {}: {}", subscriptionName, e.getMessage(), e);
        }
    });
    // Close subscription
    destStatsStream.endObject();
    // Remaining dest stats.
    topicStats.averageMsgSize = topicStats.aggMsgRateIn == 0.0 ? 0.0 : (topicStats.aggMsgThroughputIn / topicStats.aggMsgRateIn);
    destStatsStream.writePair("producerCount", producers.size());
    destStatsStream.writePair("averageMsgSize", topicStats.averageMsgSize);
    destStatsStream.writePair("msgRateIn", topicStats.aggMsgRateIn);
    destStatsStream.writePair("msgRateOut", topicStats.aggMsgRateOut);
    destStatsStream.writePair("msgThroughputIn", topicStats.aggMsgThroughputIn);
    destStatsStream.writePair("msgThroughputOut", topicStats.aggMsgThroughputOut);
    destStatsStream.writePair("storageSize", ledger.getEstimatedBacklogSize());
    destStatsStream.writePair("pendingAddEntriesCount", ((ManagedLedgerImpl) ledger).getPendingAddEntriesCount());
    nsStats.msgRateIn += topicStats.aggMsgRateIn;
    nsStats.msgRateOut += topicStats.aggMsgRateOut;
    nsStats.msgThroughputIn += topicStats.aggMsgThroughputIn;
    nsStats.msgThroughputOut += topicStats.aggMsgThroughputOut;
    nsStats.storageSize += ledger.getEstimatedBacklogSize();
    bundleStats.msgRateIn += topicStats.aggMsgRateIn;
    bundleStats.msgRateOut += topicStats.aggMsgRateOut;
    bundleStats.msgThroughputIn += topicStats.aggMsgThroughputIn;
    bundleStats.msgThroughputOut += topicStats.aggMsgThroughputOut;
    bundleStats.cacheSize += ((ManagedLedgerImpl) ledger).getCacheSize();
    // Close topic object
    destStatsStream.endObject();
}
Also used : ReplicationMetrics(com.yahoo.pulsar.broker.stats.ReplicationMetrics) ClusterReplicationMetrics(com.yahoo.pulsar.broker.stats.ClusterReplicationMetrics) PublisherStats(com.yahoo.pulsar.common.policies.data.PublisherStats) ConsumerStats(com.yahoo.pulsar.common.policies.data.ConsumerStats) NamingException(com.yahoo.pulsar.broker.service.BrokerServiceException.NamingException) TopicBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.TopicBusyException) PersistenceException(com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException) TopicFencedException(com.yahoo.pulsar.broker.service.BrokerServiceException.TopicFencedException) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) ManagedLedgerFencedException(org.apache.bookkeeper.mledger.ManagedLedgerException.ManagedLedgerFencedException) UnsupportedVersionException(com.yahoo.pulsar.broker.service.BrokerServiceException.UnsupportedVersionException) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException) ConsumerBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) KeeperException(org.apache.zookeeper.KeeperException) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) ServerMetadataException(com.yahoo.pulsar.broker.service.BrokerServiceException.ServerMetadataException) Consumer(com.yahoo.pulsar.broker.service.Consumer) ReplicatorStats(com.yahoo.pulsar.common.policies.data.ReplicatorStats) PersistentTopicStats(com.yahoo.pulsar.common.policies.data.PersistentTopicStats)

Example 13 with Consumer

use of com.yahoo.pulsar.broker.service.Consumer in project pulsar by yahoo.

the class PersistentTopic method subscribe.

@Override
public CompletableFuture<Consumer> subscribe(final ServerCnx cnx, String subscriptionName, long consumerId, SubType subType, int priorityLevel, String consumerName) {
    final CompletableFuture<Consumer> future = new CompletableFuture<>();
    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)) {
        log.warn("[{}] Failed to create subscription for {}", topic, subscriptionName);
        future.completeExceptionally(new NamingException("Subscription with reserved subscription name attempted"));
        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();
    }
    ledger.asyncOpenCursor(Codec.encode(subscriptionName), new OpenCursorCallback() {

        @Override
        public void openCursorComplete(ManagedCursor cursor, Object ctx) {
            if (log.isDebugEnabled()) {
                log.debug("[{}][{}] Opened cursor for {} {}", topic, subscriptionName, consumerId, consumerName);
            }
            try {
                PersistentSubscription subscription = subscriptions.computeIfAbsent(subscriptionName, name -> new PersistentSubscription(PersistentTopic.this, cursor));
                Consumer consumer = new Consumer(subscription, subType, consumerId, priorityLevel, consumerName, brokerService.pulsar().getConfiguration().getMaxUnackedMessagesPerConsumer(), cnx, cnx.getRole());
                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);
            }
        }

        @Override
        public void openCursorFailed(ManagedLedgerException exception, Object ctx) {
            log.warn("[{}] Failed to create subscription for {}", topic, subscriptionName);
            USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this);
            future.completeExceptionally(new PersistenceException(exception));
        }
    }, null);
    return future;
}
Also used : ReplicationMetrics(com.yahoo.pulsar.broker.stats.ReplicationMetrics) SubType(com.yahoo.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType) PersistentSubscriptionStats(com.yahoo.pulsar.common.policies.data.PersistentSubscriptionStats) LedgerInfo(com.yahoo.pulsar.common.policies.data.PersistentTopicInternalStats.LedgerInfo) NamingException(com.yahoo.pulsar.broker.service.BrokerServiceException.NamingException) ConsumerStats(com.yahoo.pulsar.common.policies.data.ConsumerStats) CloseCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.CloseCallback) PersistentTopicInternalStats(com.yahoo.pulsar.common.policies.data.PersistentTopicInternalStats) LoggerFactory(org.slf4j.LoggerFactory) ObjectObjectHashMap(com.carrotsearch.hppc.ObjectObjectHashMap) NamespaceBundleStats(com.yahoo.pulsar.common.policies.data.loadbalancer.NamespaceBundleStats) Policies(com.yahoo.pulsar.common.policies.data.Policies) BacklogQuota(com.yahoo.pulsar.common.policies.data.BacklogQuota) Preconditions.checkArgument(com.google.common.base.Preconditions.checkArgument) OpenCursorCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.OpenCursorCallback) ManagedCursor(org.apache.bookkeeper.mledger.ManagedCursor) TopicBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.TopicBusyException) ManagedLedger(org.apache.bookkeeper.mledger.ManagedLedger) ReplicatorStats(com.yahoo.pulsar.common.policies.data.ReplicatorStats) DeleteCursorCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.DeleteCursorCallback) FutureUtil(com.yahoo.pulsar.client.util.FutureUtil) Objects(com.google.common.base.Objects) PositionImpl(org.apache.bookkeeper.mledger.impl.PositionImpl) DestinationName(com.yahoo.pulsar.common.naming.DestinationName) PersistenceException(com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException) CursorStats(com.yahoo.pulsar.common.policies.data.PersistentTopicInternalStats.CursorStats) Set(java.util.Set) Position(org.apache.bookkeeper.mledger.Position) Instant(java.time.Instant) IndividualDeletedEntries(org.apache.bookkeeper.mledger.ManagedCursor.IndividualDeletedEntries) TopicFencedException(com.yahoo.pulsar.broker.service.BrokerServiceException.TopicFencedException) Lists(com.beust.jcommander.internal.Lists) ZoneId(java.time.ZoneId) Sets(com.google.common.collect.Sets) AddEntryCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.AddEntryCallback) BrokerService(com.yahoo.pulsar.broker.service.BrokerService) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) Topic(com.yahoo.pulsar.broker.service.Topic) ManagedCursorImpl(org.apache.bookkeeper.mledger.impl.ManagedCursorImpl) Consumer(com.yahoo.pulsar.broker.service.Consumer) List(java.util.List) ManagedLedgerFencedException(org.apache.bookkeeper.mledger.ManagedLedgerException.ManagedLedgerFencedException) AdminResource(com.yahoo.pulsar.broker.admin.AdminResource) AsyncCallbacks(org.apache.bookkeeper.mledger.AsyncCallbacks) StatsOutputStream(com.yahoo.pulsar.utils.StatsOutputStream) Entry(org.apache.bookkeeper.mledger.Entry) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) UnsupportedVersionException(com.yahoo.pulsar.broker.service.BrokerServiceException.UnsupportedVersionException) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException) MessageImpl(com.yahoo.pulsar.client.impl.MessageImpl) PersistentTopicStats(com.yahoo.pulsar.common.policies.data.PersistentTopicStats) ServerCnx(com.yahoo.pulsar.broker.service.ServerCnx) ByteBuf(io.netty.buffer.ByteBuf) FastThreadLocal(io.netty.util.concurrent.FastThreadLocal) ConcurrentOpenHashSet(com.yahoo.pulsar.common.util.collections.ConcurrentOpenHashSet) ConsumerBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ConcurrentOpenHashMap(com.yahoo.pulsar.common.util.collections.ConcurrentOpenHashMap) Codec(com.yahoo.pulsar.common.util.Codec) ManagedLedgerImpl(org.apache.bookkeeper.mledger.impl.ManagedLedgerImpl) ClusterReplicationMetrics(com.yahoo.pulsar.broker.stats.ClusterReplicationMetrics) Logger(org.slf4j.Logger) KeeperException(org.apache.zookeeper.KeeperException) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) PublisherStats(com.yahoo.pulsar.common.policies.data.PublisherStats) Producer(com.yahoo.pulsar.broker.service.Producer) ServerMetadataException(com.yahoo.pulsar.broker.service.BrokerServiceException.ServerMetadataException) AtomicLongFieldUpdater(java.util.concurrent.atomic.AtomicLongFieldUpdater) NamespaceStats(com.yahoo.pulsar.broker.stats.NamespaceStats) Maps(com.google.common.collect.Maps) TimeUnit(java.util.concurrent.TimeUnit) DateTimeFormatter(java.time.format.DateTimeFormatter) Collections(java.util.Collections) TopicFencedException(com.yahoo.pulsar.broker.service.BrokerServiceException.TopicFencedException) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) ManagedCursor(org.apache.bookkeeper.mledger.ManagedCursor) CompletableFuture(java.util.concurrent.CompletableFuture) OpenCursorCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.OpenCursorCallback) ConsumerBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) Consumer(com.yahoo.pulsar.broker.service.Consumer) PersistenceException(com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException) NamingException(com.yahoo.pulsar.broker.service.BrokerServiceException.NamingException) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException) UnsupportedVersionException(com.yahoo.pulsar.broker.service.BrokerServiceException.UnsupportedVersionException)

Example 14 with Consumer

use of com.yahoo.pulsar.broker.service.Consumer in project pulsar by yahoo.

the class PersistentDispatcherMultipleConsumers method getNextConsumer.

/**
     * <pre>
     * Broker gives more priority while dispatching messages. Here, broker follows descending priorities. (eg:
     * 0=max-priority, 1, 2,..)
     * <p>
     * Broker will first dispatch messages to max priority-level consumers if they
     * have permits, else broker will consider next priority level consumers. 
     * Also on the same priority-level, it selects consumer in round-robin manner. 
     * <p> 
     * If subscription has consumer-A with  priorityLevel 1 and Consumer-B with priorityLevel 2 then broker will dispatch 
     * messages to only consumer-A until it runs out permit and then broker starts dispatching messages to Consumer-B.
     * <p>
     * Consumer PriorityLevel Permits
     * C1       0             2
     * C2       0             1
     * C3       0             1
     * C4       1             2
     * C5       1             1
     * Result of getNextConsumer(): C1, C2, C3, C1, C4, C5, C4
     * </pre>
     * 
     * <pre>
     * <b>Algorithm:</b>
     * 1. sorted-list: consumers stored in sorted-list: max-priority stored first 
     * 2. currentConsumerRoundRobinIndex: it always stores last served consumer-index
     * 3. resultingAvailableConsumerIndex: traversal index. we always start searching availableConsumer from the  
     *    beginning of sorted-list and update resultingAvailableConsumerIndex according searching-traversal
     *    
     * Each time getNextConsumer() is called:<p>
     * 1. It always starts to traverse from the max-priority consumer (first element) from sorted-list
     * 2. Consumers on same priority-level will be treated equally and it tries to pick one of them in round-robin manner
     * 3. If consumer is not available on given priority-level then it will go to the next lower priority-level consumers
     * 4. Optimization: <p>
     *    A. Consumers on same priority-level must be treated equally => dispatch message round-robin to them: 
     *       [if Consumer of resultingAvailableConsumerIndex(current-traversal-index) has the same 
     *       priority-level as consumer of currentConsumerRoundRobinIndex(last-Served-Consumer-Index)] 
     *       <b>Dispatching in Round-Robin:</b> then it means we should do round-robin and skip all the consumers before 
     *          currentConsumerRoundRobinIndex (as they are already served previously)
     *               a. if found: if we found availableConsumer on the same priority-level after currentConsumerRoundRobinIndex 
     *                            then return that consumer and update currentConsumerRoundRobinIndex with that consumer-index
     *               b. else not_found: if we don't find any consumer on that same-priority level after currentConsumerRoundRobinIndex
     *                      - a. check skipped consumers: check skipped consumer (4.A.a) which are on index before than currentConsumerRoundRobinIndex
     *                      - b. next priority-level: if not found in previous step: then it means no consumer available in prior level. So, move to 
     *                           next lower priority level and try to find next-available consumer as per 4.A
     * 
     * </pre>
     * 
     * @return nextAvailableConsumer
     */
public Consumer getNextConsumer() {
    if (consumerList.isEmpty() || IS_CLOSED_UPDATER.get(this) == TRUE) {
        // abort read if no consumers are connected or if disconnect is initiated
        return null;
    }
    if (currentConsumerRoundRobinIndex >= consumerList.size()) {
        currentConsumerRoundRobinIndex = 0;
    }
    // index of resulting consumer which will be returned
    int resultingAvailableConsumerIndex = 0;
    boolean scanFromBeginningIfCurrentConsumerNotAvailable = true;
    int firstConsumerIndexOfCurrentPriorityLevel = -1;
    do {
        int priorityLevel = consumerList.get(currentConsumerRoundRobinIndex).getPriorityLevel() - consumerList.get(resultingAvailableConsumerIndex).getPriorityLevel();
        boolean isSamePriorityLevel = priorityLevel == 0;
        // store first-consumer index with same-priority as currentConsumerRoundRobinIndex
        if (isSamePriorityLevel && firstConsumerIndexOfCurrentPriorityLevel == -1) {
            firstConsumerIndexOfCurrentPriorityLevel = resultingAvailableConsumerIndex;
        }
        // skip already served same-priority-consumer to select consumer in round-robin manner
        resultingAvailableConsumerIndex = (isSamePriorityLevel && currentConsumerRoundRobinIndex > resultingAvailableConsumerIndex) ? currentConsumerRoundRobinIndex : resultingAvailableConsumerIndex;
        // if resultingAvailableConsumerIndex moved ahead of currentConsumerRoundRobinIndex: then we should
        // check skipped consumer which had same priority as currentConsumerRoundRobinIndex consumer
        boolean isLastConsumerBlocked = (currentConsumerRoundRobinIndex == (consumerList.size() - 1) && !isConsumerAvailable(consumerList.get(currentConsumerRoundRobinIndex)));
        boolean shouldScanCurrentLevel = priorityLevel < 0 || /* means moved to next lower-priority-level */
        isLastConsumerBlocked;
        if (shouldScanCurrentLevel && scanFromBeginningIfCurrentConsumerNotAvailable) {
            for (int i = firstConsumerIndexOfCurrentPriorityLevel; i < currentConsumerRoundRobinIndex; i++) {
                Consumer nextConsumer = consumerList.get(i);
                if (isConsumerAvailable(nextConsumer)) {
                    currentConsumerRoundRobinIndex = i + 1;
                    return nextConsumer;
                }
            }
            // now, we have scanned from the beginning: flip the flag to avoid scan again
            scanFromBeginningIfCurrentConsumerNotAvailable = false;
        }
        Consumer nextConsumer = consumerList.get(resultingAvailableConsumerIndex);
        if (isConsumerAvailable(nextConsumer)) {
            currentConsumerRoundRobinIndex = resultingAvailableConsumerIndex + 1;
            return nextConsumer;
        }
        if (++resultingAvailableConsumerIndex >= consumerList.size()) {
            break;
        }
    } while (true);
    // not found unblocked consumer
    return null;
}
Also used : Consumer(com.yahoo.pulsar.broker.service.Consumer)

Example 15 with Consumer

use of com.yahoo.pulsar.broker.service.Consumer in project pulsar by yahoo.

the class PersistentSubscription method resetCursor.

@Override
public CompletableFuture<Void> resetCursor(long timestamp) {
    CompletableFuture<Void> future = new CompletableFuture<>();
    PersistentMessageFinder persistentMessageFinder = new PersistentMessageFinder(topicName, cursor);
    if (log.isDebugEnabled()) {
        log.debug("[{}][{}] Resetting subscription to timestamp {}", topicName, subName, timestamp);
    }
    persistentMessageFinder.findMessages(timestamp, new AsyncCallbacks.FindEntryCallback() {

        @Override
        public void findEntryComplete(Position position, Object ctx) {
            final Position finalPosition;
            if (position == null) {
                // this should not happen ideally unless a reset is requested for a time
                // that spans beyond the retention limits (time/size)
                finalPosition = cursor.getFirstPosition();
                if (finalPosition == null) {
                    log.warn("[{}][{}] Unable to find position for timestamp {}. Unable to reset cursor to first position", topicName, subName, timestamp);
                    future.completeExceptionally(new SubscriptionInvalidCursorPosition("Unable to find position for specified timestamp"));
                    return;
                }
                log.info("[{}][{}] Unable to find position for timestamp {}. Resetting cursor to first position {} in ledger", topicName, subName, timestamp, finalPosition);
            } else {
                finalPosition = position;
            }
            if (!IS_FENCED_UPDATER.compareAndSet(PersistentSubscription.this, FALSE, TRUE)) {
                future.completeExceptionally(new SubscriptionBusyException("Failed to fence subscription"));
                return;
            }
            final CompletableFuture<Void> disconnectFuture;
            if (dispatcher != null && dispatcher.isConsumerConnected()) {
                disconnectFuture = dispatcher.disconnectAllConsumers();
            } else {
                disconnectFuture = CompletableFuture.completedFuture(null);
            }
            disconnectFuture.whenComplete((aVoid, throwable) -> {
                if (throwable != null) {
                    log.error("[{}][{}] Failed to disconnect consumer from subscription", topicName, subName, throwable);
                    IS_FENCED_UPDATER.set(PersistentSubscription.this, FALSE);
                    future.completeExceptionally(new SubscriptionBusyException("Failed to disconnect consumers from subscription"));
                    return;
                }
                log.info("[{}][{}] Successfully disconnected consumers from subscription, proceeding with cursor reset", topicName, subName);
                try {
                    cursor.asyncResetCursor(finalPosition, new AsyncCallbacks.ResetCursorCallback() {

                        @Override
                        public void resetComplete(Object ctx) {
                            if (log.isDebugEnabled()) {
                                log.debug("[{}][{}] Successfully reset subscription to timestamp {}", topicName, subName, timestamp);
                            }
                            IS_FENCED_UPDATER.set(PersistentSubscription.this, FALSE);
                            future.complete(null);
                        }

                        @Override
                        public void resetFailed(ManagedLedgerException exception, Object ctx) {
                            log.error("[{}][{}] Failed to reset subscription to timestamp {}", topicName, subName, timestamp, exception);
                            IS_FENCED_UPDATER.set(PersistentSubscription.this, FALSE);
                            // or should we just ask user to retry one more time?
                            if (exception instanceof InvalidCursorPositionException) {
                                future.completeExceptionally(new SubscriptionInvalidCursorPosition(exception.getMessage()));
                            } else if (exception instanceof ConcurrentFindCursorPositionException) {
                                future.completeExceptionally(new SubscriptionBusyException(exception.getMessage()));
                            } else {
                                future.completeExceptionally(new BrokerServiceException(exception));
                            }
                        }
                    });
                } catch (Exception e) {
                    log.error("[{}][{}] Error while resetting cursor", topicName, subName, e);
                    IS_FENCED_UPDATER.set(PersistentSubscription.this, FALSE);
                    future.completeExceptionally(new BrokerServiceException(e));
                }
            });
        }

        @Override
        public void findEntryFailed(ManagedLedgerException exception, Object ctx) {
            // todo - what can go wrong here that needs to be retried?
            if (exception instanceof ConcurrentFindCursorPositionException) {
                future.completeExceptionally(new SubscriptionBusyException(exception.getMessage()));
            } else {
                future.completeExceptionally(new BrokerServiceException(exception));
            }
        }
    });
    return future;
}
Also used : SubType(com.yahoo.pulsar.common.api.proto.PulsarApi.CommandSubscribe.SubType) PersistentSubscriptionStats(com.yahoo.pulsar.common.policies.data.PersistentSubscriptionStats) AtomicIntegerFieldUpdater(java.util.concurrent.atomic.AtomicIntegerFieldUpdater) ConsumerStats(com.yahoo.pulsar.common.policies.data.ConsumerStats) CloseCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.CloseCallback) Entry(org.apache.bookkeeper.mledger.Entry) LoggerFactory(org.slf4j.LoggerFactory) CompletableFuture(java.util.concurrent.CompletableFuture) ReadEntryCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.ReadEntryCallback) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException) DeleteCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.DeleteCallback) SubscriptionFencedException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionFencedException) Dispatcher(com.yahoo.pulsar.broker.service.Dispatcher) ClearBacklogCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.ClearBacklogCallback) ManagedCursor(org.apache.bookkeeper.mledger.ManagedCursor) Codec(com.yahoo.pulsar.common.util.Codec) Objects(com.google.common.base.Objects) PositionImpl(org.apache.bookkeeper.mledger.impl.PositionImpl) DestinationName(com.yahoo.pulsar.common.naming.DestinationName) Logger(org.slf4j.Logger) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) PersistenceException(com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException) ServerMetadataException(com.yahoo.pulsar.broker.service.BrokerServiceException.ServerMetadataException) CopyOnWriteArrayList(com.yahoo.pulsar.utils.CopyOnWriteArrayList) ConcurrentFindCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.ConcurrentFindCursorPositionException) Position(org.apache.bookkeeper.mledger.Position) IndividualDeletedEntries(org.apache.bookkeeper.mledger.ManagedCursor.IndividualDeletedEntries) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) SubscriptionInvalidCursorPosition(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionInvalidCursorPosition) Consumer(com.yahoo.pulsar.broker.service.Consumer) List(java.util.List) AckType(com.yahoo.pulsar.common.api.proto.PulsarApi.CommandAck.AckType) MarkDeleteCallback(org.apache.bookkeeper.mledger.AsyncCallbacks.MarkDeleteCallback) InvalidCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.InvalidCursorPositionException) Subscription(com.yahoo.pulsar.broker.service.Subscription) AsyncCallbacks(org.apache.bookkeeper.mledger.AsyncCallbacks) Position(org.apache.bookkeeper.mledger.Position) SubscriptionInvalidCursorPosition(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionInvalidCursorPosition) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) InvalidCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.InvalidCursorPositionException) ConcurrentFindCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.ConcurrentFindCursorPositionException) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException) SubscriptionFencedException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionFencedException) BrokerServiceException(com.yahoo.pulsar.broker.service.BrokerServiceException) PersistenceException(com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException) ServerMetadataException(com.yahoo.pulsar.broker.service.BrokerServiceException.ServerMetadataException) ConcurrentFindCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.ConcurrentFindCursorPositionException) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) InvalidCursorPositionException(org.apache.bookkeeper.mledger.ManagedLedgerException.InvalidCursorPositionException) SubscriptionInvalidCursorPosition(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionInvalidCursorPosition) CompletableFuture(java.util.concurrent.CompletableFuture) ManagedLedgerException(org.apache.bookkeeper.mledger.ManagedLedgerException) AsyncCallbacks(org.apache.bookkeeper.mledger.AsyncCallbacks) SubscriptionBusyException(com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException)

Aggregations

Consumer (com.yahoo.pulsar.broker.service.Consumer)15 PersistentTopic (com.yahoo.pulsar.broker.service.persistent.PersistentTopic)6 PersistentSubscription (com.yahoo.pulsar.broker.service.persistent.PersistentSubscription)5 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)5 PulsarApi (com.yahoo.pulsar.common.api.proto.PulsarApi)4 CountDownLatch (java.util.concurrent.CountDownLatch)4 CyclicBarrier (java.util.concurrent.CyclicBarrier)4 Entry (org.apache.bookkeeper.mledger.Entry)4 ManagedLedgerException (org.apache.bookkeeper.mledger.ManagedLedgerException)4 BrokerServiceException (com.yahoo.pulsar.broker.service.BrokerServiceException)3 PersistenceException (com.yahoo.pulsar.broker.service.BrokerServiceException.PersistenceException)3 ServerMetadataException (com.yahoo.pulsar.broker.service.BrokerServiceException.ServerMetadataException)3 SubscriptionBusyException (com.yahoo.pulsar.broker.service.BrokerServiceException.SubscriptionBusyException)3 PersistentDispatcherSingleActiveConsumer (com.yahoo.pulsar.broker.service.persistent.PersistentDispatcherSingleActiveConsumer)3 ConsumerStats (com.yahoo.pulsar.common.policies.data.ConsumerStats)3 Objects (com.google.common.base.Objects)2 ConsumerBusyException (com.yahoo.pulsar.broker.service.BrokerServiceException.ConsumerBusyException)2 NamingException (com.yahoo.pulsar.broker.service.BrokerServiceException.NamingException)2 TopicBusyException (com.yahoo.pulsar.broker.service.BrokerServiceException.TopicBusyException)2 TopicFencedException (com.yahoo.pulsar.broker.service.BrokerServiceException.TopicFencedException)2