Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a "closed" state to FallbackChannelPool to safely handle pool closure, prevent post-close callbacks, and avoid rescheduling tasks. It also replaces the "ignoreError" flag with an AtomicBoolean "outcomeRecorded" to prevent double-counting stream outcomes. The reviewer suggests verifying whether a circular lock dependency actually exists before moving the "onFallback" callback outside of the synchronized block in "updateConfig", offering a code alternative if no deadlock risk is present.
| synchronized void updateConfig(FallbackConfiguration newConfig) { | ||
| if (closed) { | ||
| return; | ||
| } | ||
| config = | ||
| config.toBuilder() | ||
| .setEnabled(newConfig.isEnabled()) | ||
| .setCheckInterval(newConfig.getCheckInterval()) | ||
| .setErrorRate(newConfig.getErrorRate()) | ||
| .build(); | ||
|
|
||
| if (triggerCallback) { | ||
| if (!config.isEnabled() && currentPool.compareAndSet(secondary, primary)) { | ||
| poolFallbackListener.onFallback( | ||
| localConfig.getFallbackName(), | ||
| localConfig.getPrimaryName(), | ||
| config.getFallbackName(), | ||
| config.getPrimaryName(), | ||
| ChannelFallbackReason.FALLBACK_DISABLE); | ||
| } | ||
| } |
There was a problem hiding this comment.
Before refactoring the code to move the poolFallbackListener.onFallback callback outside of the synchronized block, please verify if a true circular lock dependency exists. Nested lock acquisition is safe if the methods called within the locked block only perform thread-safe operations (such as updating atomic variables or statistics) and do not acquire other locks or trigger callbacks that could reverse the lock acquisition order.
If you find that a circular lock dependency or deadlock risk does exist, then we should proceed with refactoring to perform state updates inside the synchronized block and invoke the callback outside of it.
void updateConfig(FallbackConfiguration newConfig) {
boolean triggerCallback = false;
FallbackConfiguration localConfig;
synchronized (this) {
if (closed) {
return;
}
config =
config.toBuilder()
.setEnabled(newConfig.isEnabled())
.setCheckInterval(newConfig.getCheckInterval())
.setErrorRate(newConfig.getErrorRate())
.build();
localConfig = config;
if (!localConfig.isEnabled()) {
triggerCallback = currentPool.compareAndSet(secondary, primary);
}
}
if (triggerCallback) {
poolFallbackListener.onFallback(
localConfig.getFallbackName(),
localConfig.getPrimaryName(),
ChannelFallbackReason.FALLBACK_DISABLE);
}
}References
- Before refactoring code to avoid potential deadlocks by moving method calls outside of synchronized blocks, verify if a true circular lock dependency exists. Nested lock acquisition is safe if the methods called within the locked block only perform thread-safe operations and do not acquire other locks or trigger callbacks that could reverse the lock acquisition order.
Fixes two issues in FallbackChannelPool: