Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -87,6 +88,7 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import java.util.function.Supplier;
import lombok.Cleanup;
import lombok.CustomLog;
import lombok.Data;
Expand Down Expand Up @@ -167,7 +169,7 @@ public Object[][] checkOwnershipFlagProvider() {
return new Object[][] { { Boolean.TRUE }, { Boolean.FALSE } };
}

private void makeAddEntryTimeout(ManagedLedgerImpl ml, AtomicBoolean addEntryFinished) throws Exception {
public static void makeAddEntryTimeout(ManagedLedgerImpl ml, AtomicBoolean addEntryFinished) throws Exception {
LedgerHandle currentLedger = ml.currentLedger;
final LedgerHandle spyLedgerHandle = spy(currentLedger);
doAnswer(invocation -> {
Expand All @@ -183,6 +185,23 @@ private void makeAddEntryTimeout(ManagedLedgerImpl ml, AtomicBoolean addEntryFin
ml.currentLedger = spyLedgerHandle;
}

public static void makeReadEntryProbFail(ManagedLedgerImpl ml, Supplier<ManagedLedgerException> errorOrNot)
throws Exception {
ml.entryCache.clear();
LedgerHandle currentLedger = ml.currentLedger;
final LedgerHandle spyLedgerHandle = spy(currentLedger);
doAnswer(invocation -> {
long ledgerId = (long) invocation.getArguments()[0];
long entryId = (long) invocation.getArguments()[1];
ManagedLedgerException mightError = errorOrNot.get();
if (mightError != null) {
return CompletableFuture.failedFuture(mightError);
}
return currentLedger.readUnconfirmedAsync(ledgerId, entryId);
}).when(spyLedgerHandle).readUnconfirmedAsync(anyLong(), anyLong());
ml.currentLedger = spyLedgerHandle;
}

@Data
private static class DeleteLedgerInfo{
volatile boolean hasCalled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ public CompletableFuture<MessageId> getFuture() {

@Override
public void readEntriesFailed(ManagedLedgerException exception, Object ctx) {
InFlightTask inFlightTask = (InFlightTask) ctx;
if (state != Started) {
log.info("Replicator was disconnected while reading entries, stopping reads");
return;
Expand All @@ -514,12 +515,14 @@ public void readEntriesFailed(ManagedLedgerException exception, Object ctx) {
terminate();
return;
} else if (!(exception instanceof TooManyRequestsException)) {
inFlightTask.setEntries(Collections.emptyList());
log.error()
.attr("ctx", ctx)
.attr("waitTimeSec", waitTimeMillis / 1000.0)
.exception(exception)
.log("Error reading entries, retrying");
} else {
inFlightTask.setEntries(Collections.emptyList());
log.debug()
.attr("ctx", ctx)
.attr("waitTimeSec", waitTimeMillis / 1000.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import org.apache.bookkeeper.mledger.ManagedLedgerException;
import org.apache.bookkeeper.mledger.impl.ManagedCursorImpl;
import org.apache.bookkeeper.mledger.impl.ManagedLedgerImpl;
import org.apache.bookkeeper.mledger.impl.ManagedLedgerTest;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.pulsar.broker.BrokerTestUtil;
import org.apache.pulsar.broker.resources.ClusterResources;
Expand Down Expand Up @@ -648,6 +649,77 @@ public void testCreateRemoteConsumerFirst() throws Exception {
});
}

@Test(timeOut = 45 * 1000)
public void testProbBKErrorWhenReplicating() throws Exception {
// creates topics.
final String topicName = BrokerTestUtil.newUniqueName("persistent://" + nonReplicatedNamespace + "/tp_");
final String subscription = "s1";
final int totalMsg = 10_000;
admin1.topics().createNonPartitionedTopic(topicName);
admin2.topics().createNonPartitionedTopic(topicName);
RetentionPolicies retentionPolicies = new RetentionPolicies(10, -1);
admin1.topicPolicies().setRetention(topicName, retentionPolicies);
admin2.topicPolicies().setRetention(topicName, retentionPolicies);
PersistentTopic topic1 = (PersistentTopic) broker1.getTopic(topicName, false).join().get();
ManagedLedgerImpl ml1 = (ManagedLedgerImpl) topic1.getManagedLedger();
PersistentTopic topic2 = (PersistentTopic) broker2.getTopic(topicName, false).join().get();
Awaitility.await().untilAsserted(() -> {
HierarchyTopicPolicies policies1 = topic1.getHierarchyTopicPolicies();
HierarchyTopicPolicies policies2 = topic2.getHierarchyTopicPolicies();
assertEquals(policies1.getRetentionPolicies().get().getRetentionTimeInMinutes(), 10);
assertEquals(policies2.getRetentionPolicies().get().getRetentionTimeInMinutes(), 10);
});
// Publishes messages.
Producer<String> producer1 = client1.newProducer(Schema.STRING).topic(topicName).create();
Set<String> msgPublished = new HashSet<>();
for (int i = 0; i < totalMsg; i++) {
msgPublished.add("msg" + i);
producer1.send("msg" + i);
}

// Inject a probable error.
AtomicInteger roundrobin = new AtomicInteger();
Supplier<ManagedLedgerException> bkErrorOrNot = () -> {
if (roundrobin.incrementAndGet() % 2 == 0) {
return null;
}
return new ManagedLedgerException.TooManyRequestsException("mocked error");
};
ManagedLedgerTest.makeReadEntryProbFail(ml1, bkErrorOrNot);

// Verify: the replication will finish even though received ManagedLedgerException.TooManyRequestsException.
pulsar1.getConfig().setReplicationStartAt("earliest");
admin1.topics().setReplicationClusters(topicName, Arrays.asList(cluster1, cluster2));
waitReplicatorStarted(topicName);
Awaitility.await().atMost(Duration.ofSeconds(600)).pollInterval(Duration.ofSeconds(1)).untilAsserted(() -> {
TopicStats topicStats = admin1.topics().getStats(topicName);
assertEquals(topicStats.getReplication().get(cluster2).getReplicationBacklog(), 0);
});

// Verify: messages were replicated.
admin2.topics().createSubscription(topicName, subscription, MessageId.earliest);
Set<String> received = new HashSet<>();
Consumer<String> consumer2 = client2.newConsumer(Schema.STRING)
.subscriptionName(subscription).topic(topicName).subscribe();
while (true) {
Message<String> msg = consumer2.receive(2, TimeUnit.SECONDS);
if (msg == null) {
break;
}
received.add(msg.getValue());
}
assertEquals(received.size(), msgPublished.size());
assertEquals(received, msgPublished);

// cleanup.
producer1.close();
consumer2.close();
admin1.topics().setReplicationClusters(topicName, Arrays.asList(cluster1));
waitReplicatorStopped(topicName, false);
admin1.topics().delete(topicName);
admin2.topics().delete(topicName);
}

/**
* Since {@link NonPersistentReplicator} never implement the rate limitation, the config
* "replicationProducerQueueSize" should not affect {@link NonPersistentReplicator}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ public void testCreateRemoteConsumerFirst() throws Exception {
super.testReplicatorProducerStatInTopic();
}

@Override
@Test(enabled = false)
public void testProbBKErrorWhenReplicating() throws Exception {
super.testProbBKErrorWhenReplicating();
}

@Override
@Test(enabled = false)
public void testTopicCloseWhenInternalProducerCloseErrorOnce() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,12 @@ public void testCreateRemoteConsumerFirst() throws Exception {
super.testReplicatorProducerStatInTopic();
}

@Override
@Test(enabled = false)
public void testProbBKErrorWhenReplicating() throws Exception {
super.testProbBKErrorWhenReplicating();
}

@Test(enabled = false)
public void testTopicCloseWhenInternalProducerCloseErrorOnce() throws Exception {
super.testReplicatorProducerStatInTopic();
Expand Down
Loading