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 @@ -982,8 +982,7 @@ protected void internalAddProducer(Producer producer) throws BrokerServiceExcept

private void tryOverwriteOldProducer(Producer oldProducer, Producer newProducer)
throws BrokerServiceException {
if (newProducer.isSuccessorTo(oldProducer) && !isUserProvidedProducerName(oldProducer)
&& !isUserProvidedProducerName(newProducer)) {
if (newProducer.isSuccessorTo(oldProducer)) {
Comment thread
poorbarcode marked this conversation as resolved.
oldProducer.close(false);
if (!producers.replace(newProducer.getProducerName(), oldProducer, newProducer)) {
// Met concurrent update, throw exception here so that client can try reconnect later.
Expand All @@ -993,6 +992,11 @@ private void tryOverwriteOldProducer(Producer oldProducer, Producer newProducer)
handleProducerRemoved(oldProducer);
}
} else {
// If a producer with the same name tries to use a new connection, async check the old connection is
// available. The producers related the connection that not available are automatically cleaned up.
if (!Objects.equals(oldProducer.getCnx(), newProducer.getCnx())) {
oldProducer.getCnx().checkConnectionLiveness();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns a future that can be used to prevent unnecessary exceptions. Did you consider wiring that up?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
throw new BrokerServiceException.NamingException(
"Producer with name '" + newProducer.getProducerName() + "' is already connected to topic");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1398,36 +1398,36 @@ protected void handleProducer(final CommandProducer cmdProducer) {
CompletableFuture<Producer> existingProducerFuture = producers.putIfAbsent(producerId, producerFuture);

if (existingProducerFuture != null) {
if (existingProducerFuture.isDone() && !existingProducerFuture.isCompletedExceptionally()) {
Producer producer = existingProducerFuture.getNow(null);
log.info("[{}] Producer with the same id is already created:"
+ " producerId={}, producer={}", remoteAddress, producerId, producer);
commandSender.sendProducerSuccessResponse(requestId, producer.getProducerName(),
producer.getSchemaVersion());
return null;
} else {
if (!existingProducerFuture.isDone()) {
// There was an early request to create a producer with same producerId.
// This can happen when client timeout is lower than the broker timeouts.
// We need to wait until the previous producer creation request
// either complete or fails.
ServerError error = null;
if (!existingProducerFuture.isDone()) {
error = ServerError.ServiceNotReady;
} else {
error = getErrorCode(existingProducerFuture);
// remove producer with producerId as it's already completed with exception
producers.remove(producerId, existingProducerFuture);
}
log.warn("[{}][{}] Producer with id is already present on the connection, producerId={}",
remoteAddress, topicName, producerId);
commandSender.sendErrorResponse(requestId, error, "Producer is already present on the connection");
return null;
commandSender.sendErrorResponse(requestId, ServerError.ServiceNotReady,
"Producer is already present on the connection");
Comment thread
codelipenghui marked this conversation as resolved.
} else if (existingProducerFuture.isCompletedExceptionally()) {
Comment thread
codelipenghui marked this conversation as resolved.
// remove producer with producerId as it's already completed with exception
log.warn("[{}][{}] Producer with id is failed to register present on the connection, producerId={}",
remoteAddress, topicName, producerId);
ServerError error = getErrorCode(existingProducerFuture);
producers.remove(producerId, existingProducerFuture);
commandSender.sendErrorResponse(requestId, error,
"Producer is already failed to register present on the connection");
} else {
Producer producer = existingProducerFuture.getNow(null);
log.info("[{}] [{}] Producer with the same id is already created:"
+ " producerId={}, producer={}", remoteAddress, topicName, producerId, producer);
commandSender.sendProducerSuccessResponse(requestId, producer.getProducerName(),
producer.getSchemaVersion());
}
return null;
}

if (log.isDebugEnabled()) {
log.debug("[{}][{}] Creating producer. producerId={}, schema is {}", remoteAddress, topicName,
producerId, schema == null ? "absent" : "present");
log.debug("[{}][{}] Creating producer. producerId={}, producerName={}, schema is {}", remoteAddress,
topicName, producerId, producerName, schema == null ? "absent" : "present");
}

service.getOrCreateTopic(topicName.toString()).thenCompose((Topic topic) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.pulsar.broker.auth;

import static org.apache.pulsar.broker.BrokerTestUtil.spyWithoutRecordingInvocations;
import static org.testng.Assert.assertEquals;
import com.google.common.collect.Sets;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
Expand All @@ -37,17 +38,21 @@
import java.util.function.Predicate;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.TimeoutHandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.pulsar.broker.PulsarService;
import org.apache.pulsar.broker.ServiceConfiguration;
import org.apache.pulsar.broker.service.BrokerService;
import org.apache.pulsar.broker.service.BrokerTestBase;
import org.apache.pulsar.broker.service.persistent.PersistentTopic;
import org.apache.pulsar.broker.testcontext.PulsarTestContext;
import org.apache.pulsar.client.admin.PulsarAdmin;
import org.apache.pulsar.client.admin.PulsarAdminBuilder;
import org.apache.pulsar.client.admin.PulsarAdminException;
import org.apache.pulsar.client.api.ClientBuilder;
import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.PulsarClientException;
import org.apache.pulsar.client.impl.ProducerImpl;
import org.apache.pulsar.common.policies.data.ClusterData;
import org.apache.pulsar.common.policies.data.TenantInfo;
import org.apache.pulsar.common.policies.data.TenantInfoImpl;
Expand All @@ -56,6 +61,7 @@
import org.apache.pulsar.utils.ResourceUtils;
import org.apache.zookeeper.MockZooKeeper;
import org.awaitility.Awaitility;
import org.awaitility.reflect.WhiteboxImpl;
import org.mockito.Mockito;
import org.mockito.internal.util.MockUtil;
import org.slf4j.Logger;
Expand Down Expand Up @@ -644,5 +650,23 @@ public Object[][] incorrectPersistentPolicies() {
};
}

protected ServiceProducer getServiceProducer(ProducerImpl clientProducer, String topicName) {
PersistentTopic persistentTopic =
(PersistentTopic) pulsar.getBrokerService().getTopic(topicName, false).join().get();
org.apache.pulsar.broker.service.Producer serviceProducer =
persistentTopic.getProducers().get(clientProducer.getProducerName());
long clientProducerId = WhiteboxImpl.getInternalState(clientProducer, "producerId");
assertEquals(serviceProducer.getProducerId(), clientProducerId);
assertEquals(serviceProducer.getEpoch(), clientProducer.getConnectionHandler().getEpoch());
return new ServiceProducer(serviceProducer, persistentTopic);
}

@Data
@AllArgsConstructor
public static class ServiceProducer {
private org.apache.pulsar.broker.service.Producer serviceProducer;
private PersistentTopic persistentTopic;
}

private static final Logger log = LoggerFactory.getLogger(MockedPulsarServiceBaseTest.class);
}
Loading