-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
[improve][broker] Handle get owned namespaces admin API in ExtensibleLoadManager #20552
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,14 +37,17 @@ | |
import java.util.concurrent.ScheduledFuture; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
import java.util.stream.Collectors; | ||
import lombok.Getter; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.apache.pulsar.broker.PulsarServerException; | ||
import org.apache.pulsar.broker.PulsarService; | ||
import org.apache.pulsar.broker.ServiceConfiguration; | ||
import org.apache.pulsar.broker.loadbalance.BrokerFilterException; | ||
import org.apache.pulsar.broker.loadbalance.LeaderElectionService; | ||
import org.apache.pulsar.broker.loadbalance.LoadManager; | ||
import org.apache.pulsar.broker.loadbalance.extensions.channel.ServiceUnitState; | ||
import org.apache.pulsar.broker.loadbalance.extensions.channel.ServiceUnitStateChannel; | ||
import org.apache.pulsar.broker.loadbalance.extensions.channel.ServiceUnitStateChannelImpl; | ||
import org.apache.pulsar.broker.loadbalance.extensions.data.BrokerLoadData; | ||
|
@@ -180,6 +183,23 @@ public class ExtensibleLoadManagerImpl implements ExtensibleLoadManager { | |
.build(); | ||
private final CountDownLatch initWaiter = new CountDownLatch(1); | ||
|
||
/** | ||
* Get all the bundles that are owned by this broker. | ||
*/ | ||
public Set<NamespaceBundle> getOwnedServiceUnits() { | ||
var entrySet = serviceUnitStateChannel.getOwnershipEntrySet(); | ||
return entrySet.stream() | ||
.filter(entry -> { | ||
var stateData = entry.getValue(); | ||
return stateData.state() == ServiceUnitState.Owned | ||
&& StringUtils.isNotBlank(stateData.dstBroker()) | ||
&& stateData.dstBroker().equals(brokerRegistry.getBrokerId()); | ||
}).map(entry -> { | ||
var bundle = entry.getKey(); | ||
return this.getNamespaceBundle(bundle); | ||
}).collect(Collectors.toSet()); | ||
} | ||
|
||
public enum Role { | ||
Leader, | ||
Follower | ||
|
@@ -714,6 +734,12 @@ private void monitor() { | |
} | ||
} | ||
|
||
public NamespaceBundle getNamespaceBundle(String bundle) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit:move this to a static LoadManagerShared method. |
||
final String namespaceName = LoadManagerShared.getNamespaceNameFromBundleName(bundle); | ||
final String bundleRange = LoadManagerShared.getBundleRangeFromBundleName(bundle); | ||
return pulsar.getNamespaceService().getNamespaceBundleFactory().getBundle(namespaceName, bundleRange); | ||
} | ||
|
||
public void disableBroker() throws Exception { | ||
serviceUnitStateChannel.cleanOwnerships(); | ||
leaderElectionService.close(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -757,21 +757,42 @@ public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle) { | |
} | ||
|
||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, Optional<String> destinationBroker) { | ||
if (ExtensibleLoadManagerImpl.isLoadManagerExtensionEnabled(config)) { | ||
return ExtensibleLoadManagerImpl.get(loadManager.get()) | ||
.unloadNamespaceBundleAsync(bundle, destinationBroker); | ||
} | ||
|
||
// unload namespace bundle | ||
return unloadNamespaceBundle(bundle, config.getNamespaceBundleUnloadingTimeoutMs(), TimeUnit.MILLISECONDS); | ||
return unloadNamespaceBundle(bundle, destinationBroker, | ||
config.getNamespaceBundleUnloadingTimeoutMs(), TimeUnit.MILLISECONDS); | ||
} | ||
|
||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, | ||
Optional<String> destinationBroker, | ||
long timeout, | ||
TimeUnit timeoutUnit) { | ||
return unloadNamespaceBundle(bundle, destinationBroker, timeout, timeoutUnit, true); | ||
} | ||
|
||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, | ||
long timeout, | ||
TimeUnit timeoutUnit) { | ||
return unloadNamespaceBundle(bundle, Optional.empty(), timeout, timeoutUnit, true); | ||
} | ||
|
||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, long timeout, TimeUnit timeoutUnit) { | ||
return unloadNamespaceBundle(bundle, timeout, timeoutUnit, true); | ||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, | ||
long timeout, | ||
TimeUnit timeoutUnit, | ||
boolean closeWithoutWaitingClientDisconnect) { | ||
return unloadNamespaceBundle(bundle, Optional.empty(), timeout, | ||
timeoutUnit, closeWithoutWaitingClientDisconnect); | ||
} | ||
|
||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, long timeout, | ||
public CompletableFuture<Void> unloadNamespaceBundle(NamespaceBundle bundle, | ||
Optional<String> destinationBroker, | ||
long timeout, | ||
TimeUnit timeoutUnit, | ||
boolean closeWithoutWaitingClientDisconnect) { | ||
if (ExtensibleLoadManagerImpl.isLoadManagerExtensionEnabled(config)) { | ||
return ExtensibleLoadManagerImpl.get(loadManager.get()) | ||
.unloadNamespaceBundleAsync(bundle, destinationBroker); | ||
} | ||
// unload namespace bundle | ||
OwnedBundle ob = ownershipCache.getOwnedBundle(bundle); | ||
if (ob == null) { | ||
|
@@ -790,24 +811,34 @@ public CompletableFuture<Map<String, NamespaceOwnershipStatus>> getOwnedNameSpac | |
.getIsolationDataPoliciesAsync(pulsar.getConfiguration().getClusterName()) | ||
.thenApply(nsIsolationPoliciesOpt -> nsIsolationPoliciesOpt.orElseGet(NamespaceIsolationPolicies::new)) | ||
.thenCompose(namespaceIsolationPolicies -> { | ||
if (ExtensibleLoadManagerImpl.isLoadManagerExtensionEnabled(config)) { | ||
ExtensibleLoadManagerImpl extensibleLoadManager = | ||
ExtensibleLoadManagerImpl.get(loadManager.get()); | ||
var statusMap = extensibleLoadManager.getOwnedServiceUnits().stream() | ||
.collect(Collectors.toMap(NamespaceBundle::toString, | ||
bundle -> getNamespaceOwnershipStatus(true, | ||
namespaceIsolationPolicies.getPolicyByNamespace( | ||
bundle.getNamespaceObject())))); | ||
return CompletableFuture.completedFuture(statusMap); | ||
} | ||
Collection<CompletableFuture<OwnedBundle>> futures = | ||
ownershipCache.getOwnedBundlesAsync().values(); | ||
return FutureUtil.waitForAll(futures) | ||
.thenApply(__ -> futures.stream() | ||
.map(CompletableFuture::join) | ||
.collect(Collectors.toMap(bundle -> bundle.getNamespaceBundle().toString(), | ||
bundle -> getNamespaceOwnershipStatus(bundle, | ||
bundle -> getNamespaceOwnershipStatus(bundle.isActive(), | ||
namespaceIsolationPolicies.getPolicyByNamespace( | ||
bundle.getNamespaceBundle().getNamespaceObject())) | ||
)) | ||
); | ||
}); | ||
} | ||
|
||
private NamespaceOwnershipStatus getNamespaceOwnershipStatus(OwnedBundle nsObj, | ||
private NamespaceOwnershipStatus getNamespaceOwnershipStatus(boolean isActive, | ||
NamespaceIsolationPolicy nsIsolationPolicy) { | ||
NamespaceOwnershipStatus nsOwnedStatus = new NamespaceOwnershipStatus(BrokerAssignment.shared, false, | ||
nsObj.isActive()); | ||
isActive); | ||
if (nsIsolationPolicy == null) { | ||
// no matching policy found, this namespace must be an uncontrolled one and using shared broker | ||
return nsOwnedStatus; | ||
|
@@ -1103,6 +1134,10 @@ public OwnershipCache getOwnershipCache() { | |
} | ||
|
||
public Set<NamespaceBundle> getOwnedServiceUnits() { | ||
if (ExtensibleLoadManagerImpl.isLoadManagerExtensionEnabled(config)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly, having all these references to a specific implementation (ExtensibleLoadManagerImpl) is a code smell. We should rely on object oriented programming principals. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we must do some refactoring in the feature... We might need to do some abstract for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It appears that the new vs old LM logic variations in NamespaceService are more than what we originally estimated. Yes, we can define NamespaceServiceExtension extends NamespaceService. If the community decides to only maintain the extension logic in the future(I assume this wont happen in the near future), I think we can clean the old LMlogic in NamespaceService too. |
||
ExtensibleLoadManagerImpl extensibleLoadManager = ExtensibleLoadManagerImpl.get(loadManager.get()); | ||
return extensibleLoadManager.getOwnedServiceUnits(); | ||
} | ||
return ownershipCache.getOwnedBundles().values().stream().map(OwnedBundle::getNamespaceBundle) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: should we define a local var brokerId to avoid repeated registry access?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is repeated registry access will reduce performance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so. Afaik, the local variables will be likely in the CPU registers, which can be faster.
brokerRegistry.getBrokerId()
will need to deference, which could cause page hit/miss and stack getBrokerId() and deference again.I am not sure if the modern java compiler optimizes this code with local var or not.