View Javadoc
1   /*
2    * Copyright 2024 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel;
17  
18  import io.netty.util.concurrent.EventExecutor;
19  import io.netty.util.concurrent.EventExecutorChooserFactory;
20  import io.netty.util.internal.EmptyArrays;
21  import io.netty.util.internal.ObjectUtil;
22  
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.concurrent.Executor;
27  import java.util.concurrent.ThreadFactory;
28  
29  /**
30   * {@link IoEventLoopGroup} implementation that will handle its tasks with multiple threads.
31   * <p>
32   * This group supports advanced thread management strategies, such as dynamic auto-scaling,
33   * by providing a custom {@link EventExecutorChooserFactory}. To enable utilization-based
34   * auto-scaling, pass an instance of
35   * {@link io.netty.util.concurrent.AutoScalingEventExecutorChooserFactory}.
36   */
37  public class MultiThreadIoEventLoopGroup extends MultithreadEventLoopGroup implements IoEventLoopGroup {
38  
39      /**
40       * Creates a new instance of the {@link MultiThreadIoEventLoopGroup} using the default number
41       * of threads and default {@link ThreadFactory}.
42       */
43      public MultiThreadIoEventLoopGroup(IoHandlerFactory ioHandlerFactory) {
44          this(0, ioHandlerFactory);
45      }
46  
47      /**
48       /**
49       * Creates a new instance of the {@link MultiThreadIoEventLoopGroup} using the default {@link ThreadFactory}.
50       *
51       * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
52       * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
53       *                          IO.
54       */
55      public MultiThreadIoEventLoopGroup(int nThreads, IoHandlerFactory ioHandlerFactory) {
56          this(nThreads, (Executor) null, ioHandlerFactory);
57      }
58  
59      /**
60       * Create a new instance using the default number of thread.
61       *
62       * @param threadFactory     the {@link ThreadFactory} that is used.
63       * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
64       *                          IO.
65       */
66      public MultiThreadIoEventLoopGroup(ThreadFactory threadFactory, IoHandlerFactory ioHandlerFactory) {
67          this(0, threadFactory, ioHandlerFactory);
68      }
69  
70      /**
71       * Creates a new instance of the {@link MultiThreadIoEventLoopGroup} using the default number
72       * of threads.
73       *
74       * @param executor          the {@link Executor} that is used.
75       * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
76       *                          IO.
77       */
78      public MultiThreadIoEventLoopGroup(Executor executor,
79                                         IoHandlerFactory ioHandlerFactory) {
80          super(0, executor, ioHandlerFactory);
81      }
82  
83      /**
84       * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
85       *
86       * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
87       * @param executor          the {@link Executor} that is used.
88       * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
89       *                          IO.
90       */
91      public MultiThreadIoEventLoopGroup(int nThreads, Executor executor,
92                                         IoHandlerFactory ioHandlerFactory) {
93          super(nThreads, executor, ioHandlerFactory);
94      }
95  
96      /**
97       * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
98       *
99       * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
100      * @param threadFactory     the {@link ThreadFactory} that is used.
101      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
102      *                          IO.
103      */
104     public MultiThreadIoEventLoopGroup(int nThreads, ThreadFactory threadFactory,
105                                        IoHandlerFactory ioHandlerFactory) {
106         super(nThreads, threadFactory, ioHandlerFactory);
107     }
108 
109     /**
110      * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
111      *
112      * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
113      * @param executor          the {@link Executor} that is used.
114      * @param chooserFactory    the {@link EventExecutorChooserFactory} that is used to choose the
115      *                          {@link IoEventLoop} when {@link MultiThreadIoEventLoopGroup#next()} is
116      *                          called.
117      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
118      *                          IO.
119      */
120     public MultiThreadIoEventLoopGroup(int nThreads, Executor executor,
121                                        EventExecutorChooserFactory chooserFactory,
122                                        IoHandlerFactory ioHandlerFactory) {
123         super(nThreads, executor, chooserFactory, ioHandlerFactory);
124     }
125 
126     /**
127      * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
128      *
129      * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
130      * @param executor          the {@link Executor} that is used.
131      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
132      *                          IO.
133      * @param args              extra args that are passed to {@link #newChild(Executor, Object...)} method.
134      */
135     protected MultiThreadIoEventLoopGroup(int nThreads, Executor executor,
136                                           IoHandlerFactory ioHandlerFactory, Object... args) {
137         super(nThreads, executor, combine(ioHandlerFactory, args));
138     }
139 
140     /**
141      * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
142      *
143      * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
144      * @param threadFactory     the {@link ThreadFactory} that is used.
145      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
146      *                          IO.
147      * @param args              extra args that are passed to {@link #newChild(Executor, Object...)} method.
148      */
149     protected MultiThreadIoEventLoopGroup(int nThreads, ThreadFactory threadFactory,
150                                           IoHandlerFactory ioHandlerFactory, Object... args) {
151         super(nThreads, threadFactory, combine(ioHandlerFactory, args));
152     }
153 
154     /**
155      * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
156      *
157      * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
158      * @param threadFactory     the {@link ThreadFactory} that is used.
159      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
160      *                          IO.
161      * @param chooserFactory    the {@link EventExecutorChooserFactory} that is used to choose the
162      * @param args              extra args that are passed to {@link #newChild(Executor, Object...)} method.
163      */
164     protected MultiThreadIoEventLoopGroup(int nThreads, ThreadFactory threadFactory,
165                                           IoHandlerFactory ioHandlerFactory,
166                                           EventExecutorChooserFactory chooserFactory,
167                                           Object... args) {
168         super(nThreads, threadFactory, chooserFactory, combine(ioHandlerFactory, args));
169     }
170 
171     /**
172      * Creates a new instance of the {@link MultiThreadIoEventLoopGroup}.
173      *
174      * @param nThreads          the number of threads and so {@link EventLoop}s that are created.
175      * @param executor          the {@link Executor} that is used.
176      * @param ioHandlerFactory  the {@link IoHandlerFactory} that will be used to create {@link IoHandler} for handling
177      *                          IO.
178      * @param chooserFactory    the {@link EventExecutorChooserFactory} that is used to choose the
179      * @param args              extra args that are passed to {@link #newChild(Executor, Object...)} method.
180      */
181     protected MultiThreadIoEventLoopGroup(int nThreads, Executor executor,
182                                           IoHandlerFactory ioHandlerFactory,
183                                           EventExecutorChooserFactory chooserFactory,
184                                           Object... args) {
185         super(nThreads, executor, chooserFactory, combine(ioHandlerFactory, args));
186     }
187 
188     // The return type should be IoHandleEventLoop but we choose EventLoop to allow us to introduce the IoHandle
189     // concept without breaking API.
190     @Override
191     protected EventLoop newChild(Executor executor, Object... args) throws Exception {
192         IoHandlerFactory handlerFactory = (IoHandlerFactory) args[0];
193         Object[] argsCopy;
194         if (args.length > 1) {
195             argsCopy = new Object[args.length - 1];
196             System.arraycopy(args, 1, argsCopy, 0, argsCopy.length);
197         } else {
198             argsCopy = EmptyArrays.EMPTY_OBJECTS;
199         }
200         return newChild(executor, handlerFactory, argsCopy);
201     }
202 
203     /**
204      * Creates a new {@link IoEventLoop} to use with the given {@link Executor} and {@link IoHandler}.
205      *
206      * @param executor              the {@link Executor} that should be used to handle execution of tasks and IO.
207      * @param ioHandlerFactory      the {@link IoHandlerFactory} that should be used to obtain {@link IoHandler} to
208      *                              handle IO.
209      * @param args                  extra arguments that are based by the constructor.
210      * @return                      the created {@link IoEventLoop}.
211      */
212     protected IoEventLoop newChild(Executor executor, IoHandlerFactory ioHandlerFactory,
213                                    @SuppressWarnings("unused") Object... args) {
214         return new SingleThreadIoEventLoop(this, executor, ioHandlerFactory);
215     }
216 
217     /**
218      * Sets the {@link SingleThreadIoEventLoop#setIoRatio(int)} for all the {@link SingleThreadIoEventLoop}s
219      * managed by this group.
220      */
221     public void setIoRatio(int ioRatio) {
222         ObjectUtil.checkInRange(ioRatio, 1, 100, "ioRatio");
223         for (EventExecutor e: this) {
224             if (!(e instanceof SingleThreadIoEventLoop)) {
225                 throw new UnsupportedOperationException("Only support by " +
226                     SingleThreadIoEventLoop.class.getSimpleName() + ": " + e);
227             }
228         }
229         for (EventExecutor e: this) {
230             ((SingleThreadIoEventLoop) e).setIoRatio(ioRatio);
231         }
232     }
233 
234     @Override
235     public IoEventLoop next() {
236         return (IoEventLoop) super.next();
237     }
238 
239     private static Object[] combine(IoHandlerFactory handlerFactory, Object... args) {
240         List<Object> combinedList = new ArrayList<Object>();
241         combinedList.add(handlerFactory);
242         if (args != null) {
243             Collections.addAll(combinedList, args);
244         }
245         return combinedList.toArray(new Object[0]);
246     }
247 }