3-2-1.Netty源码:避免空轮循的bug

避免空轮循的bug

Posted by ZhaoLe on January 31, 2019
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 //NioEventLoop.java
//重新构造个selector
private void rebuildSelector0() {
  final Selector oldSelector = selector;
  final SelectorTuple newSelectorTuple;
  ...
  try {
    newSelectorTuple = openSelector();
  }
  ...
  
  //获取这个selector上所有注册的channelkey
  for (SelectionKey key : oldSelector.keys()) {
    Object a = key.attachment();
    try {
        if (!key.isValid() || key.channel().keyFor(newSelectorTuple.unwrappedSelector) != null) {
            continue;
        }
        //这个select上所有感兴趣事件
        int interestOps = key.interestOps();
        key.cancel();
        
        SelectionKey newKey = key.channel().register(newSelectorTuple.unwrappedSelector, interestOps, a);
        if (a instanceof AbstractNioChannel) {
            ((AbstractNioChannel) a).selectionKey = newKey;
        }
        nChannels++;
    } catch (Exception e) {
        ...
    }
  }

  selector = newSelectorTuple.selector;
  unwrappedSelector = newSelectorTuple.unwrappedSelector;

  try {
      // time to close the old selector as everything else is registered to the new one
      oldSelector.close();
  } 
  ...
}
  • 【7】创建 Selector 对象,netty优化了selector创建(解释过长,移步到下面的openSelector()方法说明)
  • 【12-30】 获取产生空轮循selecor上的所有的channel,注册到新创建的selector上。
    • 【13】获取每个注册selecor上的SelectoionKey,并且获取这些key的attachment
    • 【15-17】判断这些key是否可用。
    • 【20】 将老的channel以及它的参数和感兴趣事件注册到新的selector上
  • 【32-33】将selectorunwrappedSelector指向新的 Selector 对象。
  • 【37】关闭旧的selector

openSelector()方法说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 //NioEventLoop.java
 private SelectorTuple openSelector() {
    final Selector unwrappedSelector;
    
    try {
        unwrappedSelector = provider.openSelector();
    } catch (IOException e) {
        throw new ChannelException("failed to open a new selector", e);
    }
    if (DISABLE_KEYSET_OPTIMIZATION) {
        return new SelectorTuple(unwrappedSelector);
    }

    Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
            try {
                return Class.forName(
                        "sun.nio.ch.SelectorImpl",
                        false,
                        PlatformDependent.getSystemClassLoader());
            } catch (Throwable cause) {
                return cause;
            }
        }
    });

    if (!(maybeSelectorImplClass instanceof Class) ||
            !((Class<?>) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
        if (maybeSelectorImplClass instanceof Throwable) {
            Throwable t = (Throwable) maybeSelectorImplClass;
            logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
        }
        return new SelectorTuple(unwrappedSelector);
    }

    final Class<?> selectorImplClass = (Class<?>) maybeSelectorImplClass;

    final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();

    Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
        @Override
        public Object run() {
            try {
                
                Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
                Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");

                if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) {
                    long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField);
                    long publicSelectedKeysFieldOffset = PlatformDependent.objectFieldOffset(publicSelectedKeysField);

                    if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) {
                        PlatformDependent.putObject(
                                unwrappedSelector, selectedKeysFieldOffset, selectedKeySet);
                        PlatformDependent.putObject(
                                unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet);
                        return null;
                    }
                }
                
                Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
                if (cause != null) {
                    return cause;
                }
                cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
                if (cause != null) {
                    return cause;
                }
                
                selectedKeysField.set(unwrappedSelector, selectedKeySet);
                publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
                return null;
            } catch (NoSuchFieldException e) {
                return e;
            } catch (IllegalAccessException e) {
                return e;
            }
        }
    });

    if (maybeException instanceof Exception) {
        selectedKeys = null;
        Exception e = (Exception) maybeException;
        logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
        return new SelectorTuple(unwrappedSelector);
    }
    selectedKeys = selectedKeySet;
    logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
    return new SelectorTuple(unwrappedSelector,
            new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
}
  • 【4-8】使用原生的方法创建 Selector 对象。
  • 【9-12】默认使用selector优化。
  • 【13-25反射的方法构建sun.nio.ch.SelectorImpl的类
  • 【27-34】获得 SelectorImpl 类失败,则返回SelectorTuple对象。
  • 【38】创建SelectedSelectionKeySet对象 ,是对Selector 中的selectionKeys重写.用预定义1024大小的列表替换原来HashSet。数组的add方法复杂度比HashSet的add方法复杂度要低.
  • 【40-79】将创建好的SelectedSelectionKeySet对象利用反射重新设置到 unwrappedSelector 中的selectedKeyspublicSelectedKeys
    • 【45-46】获得selectorImplClass中的 “selectedKeys” 和”publicSelectedKeys” 的 Field。
    • 【61-68】设置两个Field的访问权限。
    • 【70-71】设置SelectedSelectionKeySet对象到 unwrappedSelector中的 Field 中。
  • 【81-90】如果设置失败,返回 SelectorTuple 对象,如果成功设置个selectedKeys成员变量,并且返回新创建的SelectorTuple对象