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();
}
}
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();
}
}
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();
}
}
Aggregations