Replace synchronized with ConcurrentHashMap in Http2StreamChannelBootstrap (#9848)
Motivation:
97361fa2c8
replace synchronized with ConcurrentHashMap in *Bootstrap classes but missed to do the same for the Http2 variant.
Modifications:
- Use ConcurrentHashMap
- Simplify code in *Bootstrap classes
Result:
Less contention
This commit is contained in:
parent
4a5712f8d9
commit
254732b43c
@ -34,15 +34,19 @@ import io.netty.util.internal.logging.InternalLogger;
|
|||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
public final class Http2StreamChannelBootstrap {
|
public final class Http2StreamChannelBootstrap {
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2StreamChannelBootstrap.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Http2StreamChannelBootstrap.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final Map.Entry<ChannelOption<?>, Object>[] EMPTY_OPTION_ARRAY = new Map.Entry[0];
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static final Map.Entry<AttributeKey<?>, Object>[] EMPTY_ATTRIBUTE_ARRAY = new Map.Entry[0];
|
||||||
|
|
||||||
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<>();
|
private final Map<ChannelOption<?>, Object> options = new ConcurrentHashMap<>();
|
||||||
private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<>();
|
private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap<>();
|
||||||
private final Channel channel;
|
private final Channel channel;
|
||||||
private volatile ChannelHandler handler;
|
private volatile ChannelHandler handler;
|
||||||
|
|
||||||
@ -61,14 +65,10 @@ public final class Http2StreamChannelBootstrap {
|
|||||||
public <T> Http2StreamChannelBootstrap option(ChannelOption<T> option, T value) {
|
public <T> Http2StreamChannelBootstrap option(ChannelOption<T> option, T value) {
|
||||||
requireNonNull(option, "option");
|
requireNonNull(option, "option");
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
synchronized (options) {
|
|
||||||
options.remove(option);
|
options.remove(option);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (options) {
|
|
||||||
options.put(option, value);
|
options.put(option, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,14 +80,10 @@ public final class Http2StreamChannelBootstrap {
|
|||||||
public <T> Http2StreamChannelBootstrap attr(AttributeKey<T> key, T value) {
|
public <T> Http2StreamChannelBootstrap attr(AttributeKey<T> key, T value) {
|
||||||
requireNonNull(key, "key");
|
requireNonNull(key, "key");
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
synchronized (attrs) {
|
|
||||||
attrs.remove(key);
|
attrs.remove(key);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (attrs) {
|
|
||||||
attrs.put(key, value);
|
attrs.put(key, value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,36 +189,29 @@ public final class Http2StreamChannelBootstrap {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void init(Channel channel) {
|
private void init(Channel channel) {
|
||||||
ChannelPipeline p = channel.pipeline();
|
ChannelPipeline p = channel.pipeline();
|
||||||
ChannelHandler handler = this.handler;
|
ChannelHandler handler = this.handler;
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
p.addLast(handler);
|
p.addLast(handler);
|
||||||
}
|
}
|
||||||
synchronized (options) {
|
setChannelOptions(channel, options.entrySet().toArray(EMPTY_OPTION_ARRAY));
|
||||||
setChannelOptions(channel, options);
|
setAttributes(channel, attrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (attrs) {
|
|
||||||
for (Map.Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
|
|
||||||
channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setChannelOptions(
|
private static void setChannelOptions(
|
||||||
Channel channel, Map<ChannelOption<?>, Object> options) {
|
Channel channel, Map.Entry<ChannelOption<?>, Object>[] options) {
|
||||||
for (Map.Entry<ChannelOption<?>, Object> e: options.entrySet()) {
|
for (Map.Entry<ChannelOption<?>, Object> e: options) {
|
||||||
setChannelOption(channel, e.getKey(), e.getValue());
|
setChannelOption(channel, e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static void setChannelOption(
|
private static void setChannelOption(
|
||||||
Channel channel, ChannelOption<?> option, Object value) {
|
Channel channel, ChannelOption<?> option, Object value) {
|
||||||
try {
|
try {
|
||||||
if (!channel.config().setOption((ChannelOption<Object>) option, value)) {
|
@SuppressWarnings("unchecked")
|
||||||
|
ChannelOption<Object> opt = (ChannelOption<Object>) option;
|
||||||
|
if (!channel.config().setOption(opt, value)) {
|
||||||
logger.warn("Unknown channel option '{}' for channel '{}'", option, channel);
|
logger.warn("Unknown channel option '{}' for channel '{}'", option, channel);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@ -230,4 +219,13 @@ public final class Http2StreamChannelBootstrap {
|
|||||||
"Failed to set channel option '{}' with value '{}' for channel '{}'", option, value, channel, t);
|
"Failed to set channel option '{}' with value '{}' for channel '{}'", option, value, channel, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void setAttributes(
|
||||||
|
Channel channel, Map.Entry<AttributeKey<?>, Object>[] options) {
|
||||||
|
for (Map.Entry<AttributeKey<?>, Object> e: options) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
|
||||||
|
channel.attr(key).set(e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,10 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*/
|
*/
|
||||||
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C, F>, C extends Channel, F>
|
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C, F>, C extends Channel, F>
|
||||||
implements Cloneable {
|
implements Cloneable {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static final Map.Entry<ChannelOption<?>, Object>[] EMPTY_OPTION_ARRAY = new Map.Entry[0];
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
static final Map.Entry<AttributeKey<?>, Object>[] EMPTY_ATTRIBUTE_ARRAY = new Map.Entry[0];
|
||||||
|
|
||||||
volatile EventLoopGroup group;
|
volatile EventLoopGroup group;
|
||||||
private volatile SocketAddress localAddress;
|
private volatile SocketAddress localAddress;
|
||||||
@ -353,16 +357,6 @@ public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C, F>, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static Map.Entry<AttributeKey<?>, Object>[] newAttrArray(int size) {
|
|
||||||
return new Map.Entry[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static Map.Entry<ChannelOption<?>, Object>[] newOptionArray(int size) {
|
|
||||||
return new Map.Entry[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static void setChannelOption(
|
private static void setChannelOption(
|
||||||
Channel channel, ChannelOption<?> option, Object value, InternalLogger logger) {
|
Channel channel, ChannelOption<?> option, Object value, InternalLogger logger) {
|
||||||
|
@ -277,8 +277,8 @@ public class Bootstrap extends AbstractBootstrap<Bootstrap, Channel, ChannelFact
|
|||||||
ChannelPipeline p = channel.pipeline();
|
ChannelPipeline p = channel.pipeline();
|
||||||
p.addLast(config.handler());
|
p.addLast(config.handler());
|
||||||
|
|
||||||
setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
|
setChannelOptions(channel, options0().entrySet().toArray(EMPTY_OPTION_ARRAY), logger);
|
||||||
setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
|
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
|
||||||
|
|
||||||
return promise.setSuccess();
|
return promise.setSuccess();
|
||||||
}
|
}
|
||||||
|
@ -160,15 +160,15 @@ public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerCh
|
|||||||
@Override
|
@Override
|
||||||
ChannelFuture init(Channel channel) {
|
ChannelFuture init(Channel channel) {
|
||||||
final ChannelPromise promise = channel.newPromise();
|
final ChannelPromise promise = channel.newPromise();
|
||||||
setChannelOptions(channel, options0().entrySet().toArray(newOptionArray(0)), logger);
|
setChannelOptions(channel, options0().entrySet().toArray(EMPTY_OPTION_ARRAY), logger);
|
||||||
setAttributes(channel, attrs0().entrySet().toArray(newAttrArray(0)));
|
setAttributes(channel, attrs0().entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY));
|
||||||
|
|
||||||
ChannelPipeline p = channel.pipeline();
|
ChannelPipeline p = channel.pipeline();
|
||||||
|
|
||||||
final ChannelHandler currentChildHandler = childHandler;
|
final ChannelHandler currentChildHandler = childHandler;
|
||||||
final Entry<ChannelOption<?>, Object>[] currentChildOptions =
|
final Entry<ChannelOption<?>, Object>[] currentChildOptions =
|
||||||
childOptions.entrySet().toArray(newOptionArray(0));
|
childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
|
||||||
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(0));
|
final Entry<AttributeKey<?>, Object>[] currentChildAttrs = childAttrs.entrySet().toArray(EMPTY_ATTRIBUTE_ARRAY);
|
||||||
|
|
||||||
p.addLast(new ChannelInitializer<Channel>() {
|
p.addLast(new ChannelInitializer<Channel>() {
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user