use of org.apache.pulsar.broker.service.Subscription in project incubator-pulsar by apache.
the class NamespacesBase method unsubscribe.
private void unsubscribe(NamespaceName nsName, String bundleRange, String subscription) {
try {
List<Topic> topicList = pulsar().getBrokerService().getAllTopicsFromNamespaceBundle(nsName.toString(), nsName.toString() + "/" + bundleRange);
List<CompletableFuture<Void>> futures = Lists.newArrayList();
if (subscription.startsWith(pulsar().getConfiguration().getReplicatorPrefix())) {
throw new RestException(Status.PRECONDITION_FAILED, "Cannot unsubscribe a replication cursor");
} else {
for (Topic topic : topicList) {
Subscription sub = topic.getSubscription(subscription);
if (sub != null) {
futures.add(sub.delete());
}
}
}
FutureUtil.waitForAll(futures).get();
} catch (RestException re) {
throw re;
} catch (Exception e) {
log.error("[{}] Failed to unsubscribe {} for namespace {}/{}", clientAppId(), subscription, nsName.toString(), bundleRange, e);
if (e.getCause() instanceof SubscriptionBusyException) {
throw new RestException(Status.PRECONDITION_FAILED, "Subscription has active connected consumers");
}
throw new RestException(e.getCause());
}
}
use of org.apache.pulsar.broker.service.Subscription in project incubator-pulsar by apache.
the class PersistentTopicsBase method internalDeleteSubscription.
protected void internalDeleteSubscription(String subName, boolean authoritative) {
if (topicName.isGlobal()) {
validateGlobalNamespaceOwnership(namespaceName);
}
PartitionedTopicMetadata partitionMetadata = getPartitionedTopicMetadata(topicName, authoritative);
if (partitionMetadata.partitions > 0) {
try {
for (int i = 0; i < partitionMetadata.partitions; i++) {
pulsar().getAdminClient().persistentTopics().deleteSubscription(topicName.getPartition(i).toString(), subName);
}
} catch (Exception e) {
if (e instanceof NotFoundException) {
throw new RestException(Status.NOT_FOUND, "Subscription not found");
} else if (e instanceof PreconditionFailedException) {
throw new RestException(Status.PRECONDITION_FAILED, "Subscription has active connected consumers");
} else {
log.error("[{}] Failed to delete subscription {} {}", clientAppId(), topicName, subName, e);
throw new RestException(e);
}
}
} else {
validateAdminOperationOnTopic(authoritative);
Topic topic = getTopicReference(topicName);
try {
Subscription sub = topic.getSubscription(subName);
checkNotNull(sub);
sub.delete().get();
log.info("[{}][{}] Deleted subscription {}", clientAppId(), topicName, subName);
} catch (Exception e) {
Throwable t = e.getCause();
if (e instanceof NullPointerException) {
throw new RestException(Status.NOT_FOUND, "Subscription not found");
} else if (t instanceof SubscriptionBusyException) {
throw new RestException(Status.PRECONDITION_FAILED, "Subscription has active connected consumers");
} else {
log.error("[{}] Failed to delete subscription {} {}", clientAppId(), topicName, subName, e);
throw new RestException(t);
}
}
}
}
use of org.apache.pulsar.broker.service.Subscription in project incubator-pulsar by apache.
the class PersistentTopic method subscribe.
@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<>();
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;
}
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;
}
use of org.apache.pulsar.broker.service.Subscription in project incubator-pulsar by apache.
the class PersistentTopic method getDurableSubscription.
private CompletableFuture<Subscription> getDurableSubscription(String subscriptionName, InitialPosition initialPosition) {
CompletableFuture<Subscription> subscriptionFuture = new CompletableFuture<>();
ledger.asyncOpenCursor(Codec.encode(subscriptionName), initialPosition, new OpenCursorCallback() {
@Override
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);
USAGE_COUNT_UPDATER.decrementAndGet(PersistentTopic.this);
subscriptionFuture.completeExceptionally(new PersistenceException(exception));
}
}, null);
return subscriptionFuture;
}
use of org.apache.pulsar.broker.service.Subscription in project incubator-pulsar by apache.
the class NonPersistentTopic method publishMessage.
@Override
public void publishMessage(ByteBuf data, PublishContext callback) {
AtomicInteger msgDeliveryCount = new AtomicInteger(2);
ENTRIES_ADDED_COUNTER_UPDATER.incrementAndGet(this);
// retain data for sub/replication because io-thread will release actual payload
data.retain(2);
this.executor.submitOrdered(topic, SafeRun.safeRun(() -> {
subscriptions.forEach((name, subscription) -> {
ByteBuf duplicateBuffer = data.retainedDuplicate();
Entry entry = create(0L, 0L, duplicateBuffer);
// entry internally retains data so, duplicateBuffer should be release here
duplicateBuffer.release();
if (subscription.getDispatcher() != null) {
subscription.getDispatcher().sendMessages(Lists.newArrayList(entry));
} else {
// it happens when subscription is created but dispatcher is not created as consumer is not added
// yet
entry.release();
}
});
data.release();
if (msgDeliveryCount.decrementAndGet() == 0) {
callback.completed(null, 0L, 0L);
}
}));
this.executor.submitOrdered(topic, SafeRun.safeRun(() -> {
replicators.forEach((name, replicator) -> {
ByteBuf duplicateBuffer = data.retainedDuplicate();
Entry entry = create(0L, 0L, duplicateBuffer);
// entry internally retains data so, duplicateBuffer should be release here
duplicateBuffer.release();
((NonPersistentReplicator) replicator).sendMessage(entry);
});
data.release();
if (msgDeliveryCount.decrementAndGet() == 0) {
callback.completed(null, 0L, 0L);
}
}));
}
Aggregations