use of org.apache.pulsar.broker.service.BrokerServiceException.PersistenceException in project incubator-pulsar by apache.
the class PersistentTopic method removeReplicator.
CompletableFuture<Void> removeReplicator(String remoteCluster) {
log.info("[{}] Removing replicator to {}", topic, remoteCluster);
final CompletableFuture<Void> future = new CompletableFuture<>();
String name = PersistentReplicator.getReplicatorName(replicatorPrefix, remoteCluster);
replicators.get(remoteCluster).disconnect().thenRun(() -> {
ledger.asyncDeleteCursor(name, new DeleteCursorCallback() {
@Override
public void deleteCursorComplete(Object ctx) {
replicators.remove(remoteCluster);
future.complete(null);
}
@Override
public void deleteCursorFailed(ManagedLedgerException exception, Object ctx) {
log.error("[{}] Failed to delete cursor {} {}", topic, name, exception.getMessage(), exception);
future.completeExceptionally(new PersistenceException(exception));
}
}, null);
}).exceptionally(e -> {
log.error("[{}] Failed to close replication producer {} {}", topic, name, e.getMessage(), e);
future.completeExceptionally(e);
return null;
});
return future;
}
use of org.apache.pulsar.broker.service.BrokerServiceException.PersistenceException in project incubator-pulsar by apache.
the class BrokerServiceTest method testLedgerOpenFailureShouldNotHaveDeadLock.
@Test
public void testLedgerOpenFailureShouldNotHaveDeadLock() throws Exception {
final String namespace = "prop/usw/my-ns";
final String deadLockTestTopic = "persistent://" + namespace + "/deadLockTestTopic";
// let this broker own this namespace bundle by creating a topic
try {
final String successfulTopic = "persistent://" + namespace + "/ownBundleTopic";
Producer<byte[]> producer = pulsarClient.newProducer().topic(successfulTopic).create();
producer.close();
} catch (Exception e) {
fail(e.getMessage());
}
ExecutorService executor = Executors.newSingleThreadExecutor();
BrokerService service = spy(pulsar.getBrokerService());
// create topic will fail to get managedLedgerConfig
CompletableFuture<ManagedLedgerConfig> failedManagedLedgerConfig = new CompletableFuture<>();
failedManagedLedgerConfig.complete(null);
doReturn(failedManagedLedgerConfig).when(service).getManagedLedgerConfig(anyObject());
CompletableFuture<Void> topicCreation = new CompletableFuture<Void>();
// fail managed-ledger future
Field ledgerField = ManagedLedgerFactoryImpl.class.getDeclaredField("ledgers");
ledgerField.setAccessible(true);
@SuppressWarnings("unchecked") ConcurrentHashMap<String, CompletableFuture<ManagedLedgerImpl>> ledgers = (ConcurrentHashMap<String, CompletableFuture<ManagedLedgerImpl>>) ledgerField.get(pulsar.getManagedLedgerFactory());
CompletableFuture<ManagedLedgerImpl> future = new CompletableFuture<>();
future.completeExceptionally(new ManagedLedgerException("ledger opening failed"));
ledgers.put(namespace + "/persistent/deadLockTestTopic", future);
// create topic async and wait on the future completion
executor.submit(() -> {
service.getTopic(deadLockTestTopic).thenAccept(topic -> topicCreation.complete(null)).exceptionally(e -> {
topicCreation.completeExceptionally(e.getCause());
return null;
});
});
// future-result should be completed with exception
try {
topicCreation.get(1, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException e) {
fail("there is a dead-lock and it should have been prevented");
} catch (ExecutionException e) {
assertTrue(e.getCause() instanceof PersistenceException);
} finally {
executor.shutdownNow();
ledgers.clear();
}
}
use of org.apache.pulsar.broker.service.BrokerServiceException.PersistenceException in project incubator-pulsar by apache.
the class PersistentSubscription method close.
/**
* Close the cursor ledger for this subscription. Requires that there are no active consumers on the dispatcher
*
* @return CompletableFuture indicating the completion of delete operation
*/
@Override
public CompletableFuture<Void> close() {
CompletableFuture<Void> closeFuture = new CompletableFuture<>();
synchronized (this) {
if (dispatcher != null && dispatcher.isConsumerConnected()) {
closeFuture.completeExceptionally(new SubscriptionBusyException("Subscription has active consumers"));
return closeFuture;
}
IS_FENCED_UPDATER.set(this, TRUE);
log.info("[{}][{}] Successfully fenced cursor ledger [{}]", topicName, subName, cursor);
}
cursor.asyncClose(new CloseCallback() {
@Override
public void closeComplete(Object ctx) {
if (log.isDebugEnabled()) {
log.debug("[{}][{}] Successfully closed cursor ledger", topicName, subName);
}
closeFuture.complete(null);
}
@Override
public void closeFailed(ManagedLedgerException exception, Object ctx) {
IS_FENCED_UPDATER.set(PersistentSubscription.this, FALSE);
log.error("[{}][{}] Error closing cursor for subscription", topicName, subName, exception);
closeFuture.completeExceptionally(new PersistenceException(exception));
}
}, null);
return closeFuture;
}
use of org.apache.pulsar.broker.service.BrokerServiceException.PersistenceException in project incubator-pulsar by apache.
the class PersistentTopic method delete.
/**
* Delete the managed ledger associated with this topic
*
* @param failIfHasSubscriptions
* 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
*
* @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) {
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;
}
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 deleteFuture;
}
} 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"));
}
} finally {
lock.writeLock().unlock();
}
return deleteFuture;
}
Aggregations