Search in sources :

Example 1 with ProducerFencedException

use of org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException in project pulsar by apache.

the class AbstractTopic method incrementTopicEpochIfNeeded.

protected CompletableFuture<Optional<Long>> incrementTopicEpochIfNeeded(Producer producer, CompletableFuture<Void> producerQueuedFuture) {
    lock.writeLock().lock();
    try {
        switch(producer.getAccessMode()) {
            case Shared:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerBusyException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else {
                    // Normal producer getting added, we don't need a new epoch
                    return CompletableFuture.completedFuture(topicEpoch);
                }
            case Exclusive:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else if (!producers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has existing shared producers"));
                } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                    // to be fenced, because a new producer had been present in between.
                    return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                } else {
                    // There are currently no existing producers
                    hasExclusiveProducer = true;
                    exclusiveProducerName = producer.getProducerName();
                    CompletableFuture<Long> future;
                    if (producer.getTopicEpoch().isPresent()) {
                        future = setTopicEpoch(producer.getTopicEpoch().get());
                    } else {
                        future = incrementTopicEpoch(topicEpoch);
                    }
                    future.exceptionally(ex -> {
                        hasExclusiveProducer = false;
                        exclusiveProducerName = null;
                        return null;
                    });
                    return future.thenApply(epoch -> {
                        topicEpoch = Optional.of(epoch);
                        return topicEpoch;
                    });
                }
            case WaitForExclusive:
                {
                    if (hasExclusiveProducer || !producers.isEmpty()) {
                        CompletableFuture<Optional<Long>> future = new CompletableFuture<>();
                        log.info("[{}] Queuing producer {} since there's already a producer", topic, producer);
                        waitingExclusiveProducers.add(Pair.of(producer, future));
                        producerQueuedFuture.complete(null);
                        return future;
                    } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                        // to be fenced, because a new producer had been present in between.
                        return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                    } else {
                        // There are currently no existing producers
                        hasExclusiveProducer = true;
                        exclusiveProducerName = producer.getProducerName();
                        CompletableFuture<Long> future;
                        if (producer.getTopicEpoch().isPresent()) {
                            future = setTopicEpoch(producer.getTopicEpoch().get());
                        } else {
                            future = incrementTopicEpoch(topicEpoch);
                        }
                        future.exceptionally(ex -> {
                            hasExclusiveProducer = false;
                            exclusiveProducerName = null;
                            return null;
                        });
                        return future.thenApply(epoch -> {
                            topicEpoch = Optional.of(epoch);
                            return topicEpoch;
                        });
                    }
                }
            default:
                return FutureUtil.failedFuture(new BrokerServiceException("Invalid producer access mode: " + producer.getAccessMode()));
        }
    } catch (Exception e) {
        log.error("Encountered unexpected error during exclusive producer creation", e);
        return FutureUtil.failedFuture(new BrokerServiceException(e));
    } finally {
        lock.writeLock().unlock();
    }
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) TopicTerminatedException(org.apache.pulsar.broker.service.BrokerServiceException.TopicTerminatedException) IncompatibleSchemaException(org.apache.pulsar.broker.service.schema.exceptions.IncompatibleSchemaException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException) ConsumerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException)

Example 2 with ProducerFencedException

use of org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException in project pulsar by yahoo.

the class AbstractTopic method incrementTopicEpochIfNeeded.

protected CompletableFuture<Optional<Long>> incrementTopicEpochIfNeeded(Producer producer, CompletableFuture<Void> producerQueuedFuture) {
    lock.writeLock().lock();
    try {
        switch(producer.getAccessMode()) {
            case Shared:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerBusyException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else {
                    // Normal producer getting added, we don't need a new epoch
                    return CompletableFuture.completedFuture(topicEpoch);
                }
            case Exclusive:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else if (!producers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has existing shared producers"));
                } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                    // to be fenced, because a new producer had been present in between.
                    return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                } else {
                    // There are currently no existing producers
                    hasExclusiveProducer = true;
                    exclusiveProducerName = producer.getProducerName();
                    CompletableFuture<Long> future;
                    if (producer.getTopicEpoch().isPresent()) {
                        future = setTopicEpoch(producer.getTopicEpoch().get());
                    } else {
                        future = incrementTopicEpoch(topicEpoch);
                    }
                    future.exceptionally(ex -> {
                        hasExclusiveProducer = false;
                        exclusiveProducerName = null;
                        return null;
                    });
                    return future.thenApply(epoch -> {
                        topicEpoch = Optional.of(epoch);
                        return topicEpoch;
                    });
                }
            case ExclusiveWithFencing:
                if (hasExclusiveProducer || !producers.isEmpty()) {
                    // clear all waiting producers
                    // otherwise closing any producer will trigger the promotion
                    // of the next pending producer
                    List<Pair<Producer, CompletableFuture<Optional<Long>>>> waitingExclusiveProducersCopy = new ArrayList<>(waitingExclusiveProducers);
                    waitingExclusiveProducers.clear();
                    waitingExclusiveProducersCopy.forEach((Pair<Producer, CompletableFuture<Optional<Long>>> handle) -> {
                        log.info("[{}] Failing waiting producer {}", topic, handle.getKey());
                        handle.getValue().completeExceptionally(new ProducerFencedException("Fenced out"));
                        handle.getKey().close(true);
                    });
                    producers.forEach((k, currentProducer) -> {
                        log.info("[{}] Fencing out producer {}", topic, currentProducer);
                        currentProducer.close(true);
                    });
                }
                if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                    // If a producer reconnects, but all the topic epoch has already moved forward,
                    // this producer needs to be fenced, because a new producer had been present in between.
                    hasExclusiveProducer = false;
                    return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                } else {
                    // There are currently no existing producers
                    hasExclusiveProducer = true;
                    exclusiveProducerName = producer.getProducerName();
                    CompletableFuture<Long> future;
                    if (producer.getTopicEpoch().isPresent()) {
                        future = setTopicEpoch(producer.getTopicEpoch().get());
                    } else {
                        future = incrementTopicEpoch(topicEpoch);
                    }
                    future.exceptionally(ex -> {
                        hasExclusiveProducer = false;
                        exclusiveProducerName = null;
                        return null;
                    });
                    return future.thenApply(epoch -> {
                        topicEpoch = Optional.of(epoch);
                        return topicEpoch;
                    });
                }
            case WaitForExclusive:
                {
                    if (hasExclusiveProducer || !producers.isEmpty()) {
                        CompletableFuture<Optional<Long>> future = new CompletableFuture<>();
                        log.info("[{}] Queuing producer {} since there's already a producer", topic, producer);
                        waitingExclusiveProducers.add(Pair.of(producer, future));
                        producerQueuedFuture.complete(null);
                        return future;
                    } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                        // to be fenced, because a new producer had been present in between.
                        return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                    } else {
                        // There are currently no existing producers
                        hasExclusiveProducer = true;
                        exclusiveProducerName = producer.getProducerName();
                        CompletableFuture<Long> future;
                        if (producer.getTopicEpoch().isPresent()) {
                            future = setTopicEpoch(producer.getTopicEpoch().get());
                        } else {
                            future = incrementTopicEpoch(topicEpoch);
                        }
                        future.exceptionally(ex -> {
                            hasExclusiveProducer = false;
                            exclusiveProducerName = null;
                            return null;
                        });
                        return future.thenApply(epoch -> {
                            topicEpoch = Optional.of(epoch);
                            return topicEpoch;
                        });
                    }
                }
            default:
                return FutureUtil.failedFuture(new BrokerServiceException("Invalid producer access mode: " + producer.getAccessMode()));
        }
    } catch (Exception e) {
        log.error("Encountered unexpected error during exclusive producer creation", e);
        return FutureUtil.failedFuture(new BrokerServiceException(e));
    } finally {
        lock.writeLock().unlock();
    }
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) Optional(java.util.Optional) ArrayList(java.util.ArrayList) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) TopicTerminatedException(org.apache.pulsar.broker.service.BrokerServiceException.TopicTerminatedException) IncompatibleSchemaException(org.apache.pulsar.broker.service.schema.exceptions.IncompatibleSchemaException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException) ConsumerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException) Pair(org.apache.commons.lang3.tuple.Pair)

Example 3 with ProducerFencedException

use of org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException in project incubator-pulsar by apache.

the class AbstractTopic method incrementTopicEpochIfNeeded.

protected CompletableFuture<Optional<Long>> incrementTopicEpochIfNeeded(Producer producer, CompletableFuture<Void> producerQueuedFuture) {
    lock.writeLock().lock();
    try {
        switch(producer.getAccessMode()) {
            case Shared:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerBusyException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else {
                    // Normal producer getting added, we don't need a new epoch
                    return CompletableFuture.completedFuture(topicEpoch);
                }
            case Exclusive:
                if (hasExclusiveProducer || !waitingExclusiveProducers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has an existing exclusive producer: " + exclusiveProducerName));
                } else if (!producers.isEmpty()) {
                    return FutureUtil.failedFuture(new ProducerFencedException("Topic has existing shared producers"));
                } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                    // to be fenced, because a new producer had been present in between.
                    return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                } else {
                    // There are currently no existing producers
                    hasExclusiveProducer = true;
                    exclusiveProducerName = producer.getProducerName();
                    CompletableFuture<Long> future;
                    if (producer.getTopicEpoch().isPresent()) {
                        future = setTopicEpoch(producer.getTopicEpoch().get());
                    } else {
                        future = incrementTopicEpoch(topicEpoch);
                    }
                    future.exceptionally(ex -> {
                        hasExclusiveProducer = false;
                        exclusiveProducerName = null;
                        return null;
                    });
                    return future.thenApply(epoch -> {
                        topicEpoch = Optional.of(epoch);
                        return topicEpoch;
                    });
                }
            case ExclusiveWithFencing:
                if (hasExclusiveProducer || !producers.isEmpty()) {
                    // clear all waiting producers
                    // otherwise closing any producer will trigger the promotion
                    // of the next pending producer
                    List<Pair<Producer, CompletableFuture<Optional<Long>>>> waitingExclusiveProducersCopy = new ArrayList<>(waitingExclusiveProducers);
                    waitingExclusiveProducers.clear();
                    waitingExclusiveProducersCopy.forEach((Pair<Producer, CompletableFuture<Optional<Long>>> handle) -> {
                        log.info("[{}] Failing waiting producer {}", topic, handle.getKey());
                        handle.getValue().completeExceptionally(new ProducerFencedException("Fenced out"));
                        handle.getKey().close(true);
                    });
                    producers.forEach((k, currentProducer) -> {
                        log.info("[{}] Fencing out producer {}", topic, currentProducer);
                        currentProducer.close(true);
                    });
                }
                if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                    // If a producer reconnects, but all the topic epoch has already moved forward,
                    // this producer needs to be fenced, because a new producer had been present in between.
                    hasExclusiveProducer = false;
                    return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                } else {
                    // There are currently no existing producers
                    hasExclusiveProducer = true;
                    exclusiveProducerName = producer.getProducerName();
                    CompletableFuture<Long> future;
                    if (producer.getTopicEpoch().isPresent()) {
                        future = setTopicEpoch(producer.getTopicEpoch().get());
                    } else {
                        future = incrementTopicEpoch(topicEpoch);
                    }
                    future.exceptionally(ex -> {
                        hasExclusiveProducer = false;
                        exclusiveProducerName = null;
                        return null;
                    });
                    return future.thenApply(epoch -> {
                        topicEpoch = Optional.of(epoch);
                        return topicEpoch;
                    });
                }
            case WaitForExclusive:
                {
                    if (hasExclusiveProducer || !producers.isEmpty()) {
                        CompletableFuture<Optional<Long>> future = new CompletableFuture<>();
                        log.info("[{}] Queuing producer {} since there's already a producer", topic, producer);
                        waitingExclusiveProducers.add(Pair.of(producer, future));
                        producerQueuedFuture.complete(null);
                        return future;
                    } else if (producer.getTopicEpoch().isPresent() && producer.getTopicEpoch().get() < topicEpoch.orElse(-1L)) {
                        // to be fenced, because a new producer had been present in between.
                        return FutureUtil.failedFuture(new ProducerFencedException(String.format("Topic epoch has already moved. Current epoch: %d, Producer epoch: %d", topicEpoch.get(), producer.getTopicEpoch().get())));
                    } else {
                        // There are currently no existing producers
                        hasExclusiveProducer = true;
                        exclusiveProducerName = producer.getProducerName();
                        CompletableFuture<Long> future;
                        if (producer.getTopicEpoch().isPresent()) {
                            future = setTopicEpoch(producer.getTopicEpoch().get());
                        } else {
                            future = incrementTopicEpoch(topicEpoch);
                        }
                        future.exceptionally(ex -> {
                            hasExclusiveProducer = false;
                            exclusiveProducerName = null;
                            return null;
                        });
                        return future.thenApply(epoch -> {
                            topicEpoch = Optional.of(epoch);
                            return topicEpoch;
                        });
                    }
                }
            default:
                return FutureUtil.failedFuture(new BrokerServiceException("Invalid producer access mode: " + producer.getAccessMode()));
        }
    } catch (Exception e) {
        log.error("Encountered unexpected error during exclusive producer creation", e);
        return FutureUtil.failedFuture(new BrokerServiceException(e));
    } finally {
        lock.writeLock().unlock();
    }
}
Also used : CompletableFuture(java.util.concurrent.CompletableFuture) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) Optional(java.util.Optional) ArrayList(java.util.ArrayList) ProducerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException) TopicTerminatedException(org.apache.pulsar.broker.service.BrokerServiceException.TopicTerminatedException) IncompatibleSchemaException(org.apache.pulsar.broker.service.schema.exceptions.IncompatibleSchemaException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException) ConsumerBusyException(org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException) ProducerFencedException(org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException) Pair(org.apache.commons.lang3.tuple.Pair)

Aggregations

CompletableFuture (java.util.concurrent.CompletableFuture)3 ConsumerBusyException (org.apache.pulsar.broker.service.BrokerServiceException.ConsumerBusyException)3 ProducerBusyException (org.apache.pulsar.broker.service.BrokerServiceException.ProducerBusyException)3 ProducerFencedException (org.apache.pulsar.broker.service.BrokerServiceException.ProducerFencedException)3 TopicTerminatedException (org.apache.pulsar.broker.service.BrokerServiceException.TopicTerminatedException)3 IncompatibleSchemaException (org.apache.pulsar.broker.service.schema.exceptions.IncompatibleSchemaException)3 ArrayList (java.util.ArrayList)2 Optional (java.util.Optional)2 Pair (org.apache.commons.lang3.tuple.Pair)2