Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fix][broker] Fix NPE when set AutoTopicCreationOverride #15653

Merged
merged 1 commit into from May 20, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -97,6 +97,7 @@
import org.apache.pulsar.common.policies.data.SubscriptionAuthMode;
import org.apache.pulsar.common.policies.data.TenantOperation;
import org.apache.pulsar.common.policies.data.TopicHashPositions;
import org.apache.pulsar.common.policies.data.TopicType;
import org.apache.pulsar.common.policies.data.ValidateResult;
import org.apache.pulsar.common.policies.data.impl.AutoTopicCreationOverrideImpl;
import org.apache.pulsar.common.policies.data.impl.DispatchRateImpl;
Expand Down Expand Up @@ -834,9 +835,11 @@ protected void internalSetAutoTopicCreation(AsyncResponse asyncResponse,
"Invalid configuration for autoTopicCreationOverride. the detail is "
+ validateResult.getErrorInfo());
}
if (maxPartitions > 0 && autoTopicCreationOverride.getDefaultNumPartitions() > maxPartitions) {
throw new RestException(Status.NOT_ACCEPTABLE,
"Number of partitions should be less than or equal to " + maxPartitions);
if (Objects.equals(autoTopicCreationOverride.getTopicType(), TopicType.PARTITIONED.toString())) {
if (maxPartitions > 0 && autoTopicCreationOverride.getDefaultNumPartitions() > maxPartitions) {
Copy link
Contributor

Choose a reason for hiding this comment

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

if the problem is that autoTopicCreationOverride.getDefaultNumPartitions() can be null then we have to simply add a null check and fail the request if it is not passed while maxPartitions is > 0

Copy link
Member Author

Choose a reason for hiding this comment

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

A simple null check cannot clearly express why it is null here, which will increase the burden on the maintainers later.
I think a better approach is to use logical judgments to avoid null checks everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

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

But you should add the null check anyway. Because here we can fail with NPE

Copy link
Member Author

Choose a reason for hiding this comment

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

The null check already exists in bellow code:

public static ValidateResult validateOverride(AutoTopicCreationOverride override) {
if (override == null) {
return ValidateResult.fail("[AutoTopicCreationOverride] can not be null");
}
if (override.isAllowAutoTopicCreation()) {
if (!TopicType.isValidTopicType(override.getTopicType())) {
return ValidateResult.fail(String.format("Unknown topic type [%s]", override.getTopicType()));
}
if (TopicType.PARTITIONED.toString().equals(override.getTopicType())) {
if (override.getDefaultNumPartitions() == null) {
return ValidateResult.fail("[defaultNumPartitions] cannot be null when the type is partitioned.");
}
if (override.getDefaultNumPartitions() <= 0) {
return ValidateResult.fail("[defaultNumPartitions] cannot be less than 1 for partition type.");
}
} else if (TopicType.NON_PARTITIONED.toString().equals(override.getTopicType())) {
if (override.getDefaultNumPartitions() != null) {
return ValidateResult.fail("[defaultNumPartitions] is not allowed to be"
+ " set when the type is non-partition.");
}
}
}
return ValidateResult.success();
}

throw new RestException(Status.NOT_ACCEPTABLE,
"Number of partitions should be less than or equal to " + maxPartitions);
}
}
}
// Force to read the data s.t. the watch to the cache content is setup.
Expand Down
Expand Up @@ -45,6 +45,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import javax.ws.rs.NotAcceptableException;
import javax.ws.rs.core.Response.Status;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -84,6 +85,7 @@
import org.apache.pulsar.common.naming.TopicName;
import org.apache.pulsar.common.policies.data.AutoFailoverPolicyData;
import org.apache.pulsar.common.policies.data.AutoFailoverPolicyType;
import org.apache.pulsar.common.policies.data.AutoTopicCreationOverride;
import org.apache.pulsar.common.policies.data.BacklogQuota;
import org.apache.pulsar.common.policies.data.BrokerNamespaceIsolationData;
import org.apache.pulsar.common.policies.data.BrokerNamespaceIsolationDataImpl;
Expand Down Expand Up @@ -1708,6 +1710,48 @@ public void testMaxNamespacesPerTenant() throws Exception {
}
}

@Test
public void testAutoTopicCreationOverrideWithMaxNumPartitionsLimit() throws Exception{
super.internalCleanup();
conf.setMaxNumPartitionsPerPartitionedTopic(10);
super.internalSetup();
admin.clusters().createCluster("test", ClusterData.builder().serviceUrl(brokerUrl.toString()).build());
TenantInfoImpl tenantInfo = new TenantInfoImpl(
Sets.newHashSet("role1", "role2"), Sets.newHashSet("test"));
admin.tenants().createTenant("testTenant", tenantInfo);
// test non-partitioned
admin.namespaces().createNamespace("testTenant/ns1", Sets.newHashSet("test"));
AutoTopicCreationOverride overridePolicy = AutoTopicCreationOverride
.builder().allowAutoTopicCreation(true)
.topicType("non-partitioned")
.build();
admin.namespaces().setAutoTopicCreation("testTenant/ns1", overridePolicy);
AutoTopicCreationOverride newOverridePolicy =
admin.namespaces().getAutoTopicCreation("testTenant/ns1");
assertEquals(overridePolicy, newOverridePolicy);
// test partitioned
AutoTopicCreationOverride partitionedOverridePolicy = AutoTopicCreationOverride
.builder().allowAutoTopicCreation(true)
.topicType("partitioned")
.defaultNumPartitions(10)
.build();
admin.namespaces().setAutoTopicCreation("testTenant/ns1", partitionedOverridePolicy);
AutoTopicCreationOverride partitionedNewOverridePolicy =
admin.namespaces().getAutoTopicCreation("testTenant/ns1");
assertEquals(partitionedOverridePolicy, partitionedNewOverridePolicy);
// test partitioned with error
AutoTopicCreationOverride partitionedWrongOverridePolicy = AutoTopicCreationOverride
.builder().allowAutoTopicCreation(true)
.topicType("partitioned")
.defaultNumPartitions(123)
.build();
try {
admin.namespaces().setAutoTopicCreation("testTenant/ns1", partitionedWrongOverridePolicy);
fail();
} catch (Exception ex) {
assertTrue(ex.getCause() instanceof NotAcceptableException);
}
}
@Test
public void testMaxTopicsPerNamespace() throws Exception {
super.internalCleanup();
Expand Down