Skip to content

[3.0] MultiplexProtocolConnectionManagerTest指令重排暴露的问题 #8978

@zrlw

Description

@zrlw

Environment

  • Dubbo version: 3.0
    github构建日志
[INFO] Running org.apache.dubbo.remoting.api.MultiplexProtocolConnectionManagerTest
Error:  Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.046 s <<< FAILURE! - in org.apache.dubbo.remoting.api.MultiplexProtocolConnectionManagerTest
Error:  testForEachConnection  Time elapsed: 0.029 s  <<< ERROR!
java.lang.IllegalStateException: No such extension org.apache.dubbo.remoting.api.WireProtocol by name tri, no related exception was found, please check whether related SPI module is missing.
	at org.apache.dubbo.remoting.api.MultiplexProtocolConnectionManagerTest.testForEachConnection(MultiplexProtocolConnectionManagerTest.java:53)

测试方法代码:

    public void testForEachConnection() throws RemotingException {
        {
            URL url = URL.valueOf("empty://127.0.0.1:8080?foo=bar");
            Connection connect = connectionManager.connect(url);
        }
        {
            URL url = URL.valueOf("tri://127.0.0.1:8080?foo=bar");
            Connection connect = connectionManager.connect(url); <== throw IllegalStateException at line 53
        }
  
        Consumer<Connection> consumer = new Consumer<Connection>() {
            @Override
            public void accept(Connection connection) {
                try {
                    Assertions.assertEquals("empty", connection.getUrl().getProtocol());
                } catch (Exception e) {
                    Assertions.assertEquals("tri", connection.getUrl().getProtocol());
                }

            }
        };

        connectionManager.forEachConnection(consumer);
    }

问题重现方法:
把创建两个Connection的代码块顺序颠倒一下,首先创建tri的connection。

分析原因:
指令重排导致tri的连接先行创建,但META-INF/dubbo/internal/org.apache.dubbo.remoting.api.WireProtocol文件里没有配置tri扩展。
其他问题:

  1. 两个connection的url用了相同的地址(host和port相同),导致只会建一个Connection;
  2. catch捕捉的类型错, 断言异常AssertionFailedError是Error类型,捕获Exception是捕获不到的 ;
  3. 测试方法结束时两个connection都没有关闭,SingleProtocolConnectionManager全局对象里的connections没有清空,影响后续测试类,修复前两个问题会导致windows环境github构建失败(windows默认按字母顺序执行测试,SingleProtocolConnectionManagerTest在MultiplexProtocolConnectionManagerTest后面)。

另外有个涉及MultiplexProtocolConnectionManager的疑问:
MultiplexProtocolConnectionManager的createSingleProtocolConnectionManager方法虽然传入了protocol:

    private ConnectionManager createSingleProtocolConnectionManager(String protocol) {
        return frameworkModel.getExtensionLoader(ConnectionManager.class).getExtension("single");
    }

但并没有用到这个protocol参数,返回的SingleProtocolConnectionManager都是同一个对象,这样MultiplexProtocolConnectionManager的connect方法往下面这个map里面放的ConnectionManager都是同一个SingleProtocolConnectionManager对象:

private final ConcurrentMap<String, ConnectionManager> protocols = new ConcurrentHashMap<>();

只有一个SingleProtocolConnectionManager为啥还要搞个map?MultiplexProtocolConnectionManager的forEachConnection方法遍历上面这个protocols,每个protocol都要搞一遍所有协议的全部连接,这样设计不太符合常理。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions