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 }