Skip to content

Commit 3130a93

Browse files
[improve][broker] Improve the performance of TopicName constructor (#24463)
1 parent 8c4e83d commit 3130a93

1 file changed

Lines changed: 44 additions & 43 deletions

File tree

  • pulsar-common/src/main/java/org/apache/pulsar/common/naming

pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -120,41 +120,46 @@ private TopicName(String completeTopicName) {
120120
try {
121121
// The topic name can be in two different forms, one is fully qualified topic name,
122122
// the other one is short topic name
123-
if (!completeTopicName.contains("://")) {
123+
int index = completeTopicName.indexOf("://");
124+
if (index < 0) {
124125
// The short topic name can be:
125126
// - <topic>
126127
// - <tenant>/<namespace>/<topic>
127-
String[] parts = StringUtils.split(completeTopicName, '/');
128-
if (parts.length == 3) {
129-
completeTopicName = TopicDomain.persistent.name() + "://" + completeTopicName;
130-
} else if (parts.length == 1) {
131-
completeTopicName = TopicDomain.persistent.name() + "://"
132-
+ PUBLIC_TENANT + "/" + DEFAULT_NAMESPACE + "/" + parts[0];
128+
List<String> parts = splitBySlash(completeTopicName, 0);
129+
this.domain = TopicDomain.persistent;
130+
if (parts.size() == 3) {
131+
this.tenant = parts.get(0);
132+
this.namespacePortion = parts.get(1);
133+
this.localName = parts.get(2);
134+
} else if (parts.size() == 1) {
135+
this.tenant = PUBLIC_TENANT;
136+
this.namespacePortion = DEFAULT_NAMESPACE;
137+
this.localName = parts.get(0);
133138
} else {
134139
throw new IllegalArgumentException(
135140
"Invalid short topic name '" + completeTopicName + "', it should be in the format of "
136141
+ "<tenant>/<namespace>/<topic> or <topic>");
137142
}
138-
}
139-
140-
// Expected format: persistent://tenant/namespace/topic
141-
List<String> parts = Splitter.on("://").limit(2).splitToList(completeTopicName);
142-
this.domain = TopicDomain.getEnum(parts.get(0));
143-
144-
String rest = parts.get(1);
145-
146-
// Scalable topic domains (topic://, segment://) only support the new format
147-
// and local names may contain '/', so use limit(3) to keep the rest as localName.
148-
boolean isScalableDomain = this.domain == TopicDomain.topic
149-
|| this.domain == TopicDomain.segment;
150-
int splitLimit = isScalableDomain ? 3 : 4;
151-
parts = Splitter.on("/").limit(splitLimit).splitToList(rest);
152-
if (parts.size() == 4) {
153-
throw new IllegalArgumentException(
154-
"V1 topic names (with cluster component) are no longer supported. "
155-
+ "Please use the V2 format: '<domain>://tenant/namespace/topic'. Got: "
156-
+ completeTopicName);
157-
} else if (parts.size() == 3) {
143+
this.segmentRange = null;
144+
this.segmentId = -1;
145+
this.completeTopicName = domain.name() + "://" + tenant + "/" + namespacePortion + "/" + localName;
146+
} else {
147+
this.domain = TopicDomain.getEnum(completeTopicName.substring(0, index));
148+
// Scalable topic domains (topic://, segment://) only support the new format
149+
// and local names may contain '/', so use limit(3) to keep the rest as localName.
150+
boolean isScalableDomain = this.domain == TopicDomain.topic
151+
|| this.domain == TopicDomain.segment;
152+
int splitLimit = isScalableDomain ? 3 : 4;
153+
List<String> parts = splitBySlash(completeTopicName.substring(index + "://".length()),
154+
splitLimit);
155+
if (parts.size() == 4) {
156+
throw new IllegalArgumentException(
157+
"V1 topic names (with cluster component) are no longer supported. "
158+
+ "Please use the V2 format: '<domain>://tenant/namespace/topic'. Got: "
159+
+ completeTopicName);
160+
} else if (parts.size() != 3) {
161+
throw new IllegalArgumentException("Invalid topic name " + completeTopicName);
162+
}
158163
this.tenant = parts.get(0);
159164
this.namespacePortion = parts.get(1);
160165
String rawLocalName = parts.get(2);
@@ -165,16 +170,16 @@ private TopicName(String completeTopicName) {
165170
if (lastSlash <= 0) {
166171
throw new IllegalArgumentException(
167172
"Invalid segment topic name: local name must contain"
168-
+ " '<parent-topic>/<hashStart>-<hashEnd>-<segmentId>'. Got: "
169-
+ completeTopicName);
173+
+ " '<parent-topic>/<hashStart>-<hashEnd>-<segmentId>'. Got: "
174+
+ completeTopicName);
170175
}
171176
this.localName = rawLocalName.substring(0, lastSlash);
172177
String descriptor = rawLocalName.substring(lastSlash + 1);
173178
String[] descParts = descriptor.split("-");
174179
if (descParts.length != 3) {
175180
throw new IllegalArgumentException(
176181
"Invalid segment descriptor: expected '<hexStart>-<hexEnd>-<segmentId>',"
177-
+ " got: '" + descriptor + "'");
182+
+ " got: '" + descriptor + "'");
178183
}
179184
this.segmentRange = HashRange.of(
180185
Integer.parseInt(descParts[0], 16),
@@ -186,28 +191,24 @@ private TopicName(String completeTopicName) {
186191
this.segmentId = -1;
187192
}
188193

189-
this.partitionIndex = getPartitionIndex(completeTopicName);
190-
this.namespaceName = NamespaceName.get(tenant, namespacePortion);
191-
} else {
192-
throw new IllegalArgumentException("Invalid topic name: " + completeTopicName);
194+
if (this.domain == TopicDomain.segment) {
195+
this.completeTopicName = String.format("%s://%s/%s/%s/%s",
196+
domain, tenant, namespacePortion, localName,
197+
String.format("%04x-%04x-%d", segmentRange.start(), segmentRange.end(), segmentId));
198+
} else {
199+
this.completeTopicName = completeTopicName;
200+
}
193201
}
194202

195203
if (StringUtils.isBlank(localName)) {
196204
throw new IllegalArgumentException(String.format("Invalid topic name: %s. Topic local name must not"
197205
+ " be blank.", completeTopicName));
198206
}
199-
207+
this.partitionIndex = getPartitionIndex(localName);
208+
this.namespaceName = NamespaceName.get(tenant, namespacePortion);
200209
} catch (NullPointerException e) {
201210
throw new IllegalArgumentException("Invalid topic name: " + completeTopicName, e);
202211
}
203-
if (this.domain == TopicDomain.segment) {
204-
this.completeTopicName = String.format("%s://%s/%s/%s/%s",
205-
domain, tenant, namespacePortion, localName,
206-
String.format("%04x-%04x-%d", segmentRange.start(), segmentRange.end(), segmentId));
207-
} else {
208-
this.completeTopicName = String.format("%s://%s/%s/%s",
209-
domain, tenant, namespacePortion, localName);
210-
}
211212
}
212213

213214
public boolean isPersistent() {

0 commit comments

Comments
 (0)