BitoAgent commented on code in PR #13786: URL: https://github.com/apache/dubbo/pull/13786#discussion_r1568049650
########## dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java: ########## @@ -16,123 +16,103 @@ */ package org.apache.dubbo.rpc.protocol.tri.h12.grpc; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.exception.EncodeException; import org.apache.dubbo.remoting.http12.message.HttpMessageCodec; import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.MethodDescriptor; +import org.apache.dubbo.rpc.model.PackableMethod; +import org.apache.dubbo.rpc.model.PackableMethodFactory; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; -import com.google.protobuf.Message; - -import static org.apache.dubbo.common.constants.CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME; +import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PACKABLE_METHOD_FACTORY; public class GrpcCompositeCodec implements HttpMessageCodec { - private final ProtobufHttpMessageCodec protobufHttpMessageCodec; + private static final String PACKABLE_METHOD_CACHE = "PACKABLE_METHOD_CACHE"; - private final WrapperHttpMessageCodec wrapperHttpMessageCodec; + private final URL url; - public GrpcCompositeCodec( - ProtobufHttpMessageCodec protobufHttpMessageCodec, WrapperHttpMessageCodec wrapperHttpMessageCodec) { - this.protobufHttpMessageCodec = protobufHttpMessageCodec; - this.wrapperHttpMessageCodec = wrapperHttpMessageCodec; - } + private final FrameworkModel frameworkModel; + + private final String mediaType; - public void setEncodeTypes(Class<?>[] encodeTypes) { - this.wrapperHttpMessageCodec.setEncodeTypes(encodeTypes); + private PackableMethod packableMethod; + + public GrpcCompositeCodec(URL url, FrameworkModel frameworkModel, String mediaType) { + this.url = url; + this.frameworkModel = frameworkModel; + this.mediaType = mediaType; } - public void setDecodeTypes(Class<?>[] decodeTypes) { - this.wrapperHttpMessageCodec.setDecodeTypes(decodeTypes); + public void loadPackableMethod(MethodDescriptor methodDescriptor) { + if (methodDescriptor instanceof PackableMethod) { + packableMethod = (PackableMethod) methodDescriptor; + return; + } + Map<MethodDescriptor, PackableMethod> cacheMap = (Map<MethodDescriptor, PackableMethod>) url.getServiceModel() + .getServiceMetadata() + .getAttributeMap() + .computeIfAbsent(PACKABLE_METHOD_CACHE, k -> new ConcurrentHashMap<>()); + packableMethod = cacheMap.computeIfAbsent(methodDescriptor, md -> frameworkModel + .getExtensionLoader(PackableMethodFactory.class) + .getExtension(ConfigurationUtils.getGlobalConfiguration(url.getApplicationModel()) + .getString(DUBBO_PACKABLE_METHOD_FACTORY, DEFAULT_KEY)) + .create(methodDescriptor, url, mediaType)); Review Comment: **Scalability Issue**: The implementation of loading and caching PackableMethod instances involves accessing a ConcurrentHashMap and potentially creating new instances of PackableMethod. This could become a scalability bottleneck under high concurrency, as multiple threads might contend for locks within ConcurrentHashMap or experience increased latency due to cache misses and the subsequent creation of new PackableMethod instances. <br> **Fix**: Consider using a more efficient concurrent data structure or caching mechanism that minimizes lock contention and efficiently handles high read/write concurrency. Evaluate the use of a ConcurrentLinkedQueue with a thread-local storage pattern for read-heavy scenarios, ensuring that the creation of new PackableMethod instances is minimized and efficiently handled in a lock-free manner. <br> **Code Suggestion**: ``` +import java.util.concurrent.ConcurrentLinkedQueue; +import java.lang.ThreadLocal; -Map<MethodDescriptor, PackableMethod> cacheMap = (Map<MethodDescriptor, PackableMethod>) url.getServiceModel() +ThreadLocal<ConcurrentLinkedQueue<PackableMethod>> cacheMap = ThreadLocal.withInitial(() -> new ConcurrentLinkedQueue<>()); +PackableMethod cachedMethod = cacheMap.get().stream().filter(m -> m.matches(methodDescriptor)).findFirst().orElseGet(() -> { + PackableMethod newMethod = frameworkModel + .getExtensionLoader(PackableMethodFactory.class) + .getExtension(ConfigurationUtils.getGlobalConfiguration(url.getApplicationModel()) + .getString(DUBBO_PACKABLE_METHOD_FACTORY, DEFAULT_KEY)) + .create(methodDescriptor, url, mediaType); + cacheMap.get().add(newMethod); + return newMethod; +}); +packableMethod = cachedMethod; ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org For additional commands, e-mail: notifications-h...@dubbo.apache.org