netty5/handler/src/main/java/io/netty/handler/timeout/WriteTimeoutHandler.java

234 lines
7.7 KiB
Java
Raw Normal View History

/*
2012-06-04 22:31:44 +02:00
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
2009-08-28 09:15:49 +02:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2009-08-28 09:15:49 +02:00
* License for the specific language governing permissions and limitations
* under the License.
*/
2011-12-09 04:38:59 +01:00
package io.netty.handler.timeout;
2011-12-09 04:38:59 +01:00
import io.netty.bootstrap.ServerBootstrap;
2012-12-19 21:08:47 +01:00
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
2011-12-09 04:38:59 +01:00
import io.netty.channel.ChannelHandlerContext;
2012-12-19 21:08:47 +01:00
import io.netty.channel.ChannelInitializer;
Clean up Future/Promises API (#11575) Motivation: The generics for the existing futures, promises, and listeners are too complicated. This complication comes from the existence of `ChannelPromise` and `ChannelFuture`, which forces listeners to care about the particular _type_ of future being listened on. Modification: * Add a `FutureContextListener` which can take a context object as an additional argument. This allows our listeners to have the channel piped through to them, so they don't need to rely on the `ChannelFuture.channel()` method. * Make the `FutureListener`, along with the `FutureContextListener` sibling, the default listener API, retiring the `GenericFutureListener` since we no longer need to abstract over the type of the future. * Change all uses of `ChannelPromise` to `Promise<Void>`. * Change all uses of `ChannelFuture` to `Future<Void>`. * Change all uses of `GenericFutureListener` to either `FutureListener` or `FutureContextListener` as needed. * Remove `ChannelFutureListener` and `GenericFutureListener`. * Introduce a `ChannelFutureListeners` enum to house the constants that previously lived in `ChannelFutureListener`. These constants now implement `FutureContextListener` and take the `Channel` as a context. * Remove `ChannelPromise` and `ChannelFuture` — all usages now rely on the plain `Future` and `Promise` APIs. * Add static factory methods to `DefaultPromise` that allow us to create promises that are initialised as successful or failed. * Remove `CompleteFuture`, `SucceededFuture`, `FailedFuture`, `CompleteChannelFuture`, `SucceededChannelFuture`, and `FailedChannelFuture`. * Remove `ChannelPromiseNotifier`. Result: Cleaner generics and more straight forward code.
2021-08-20 09:55:16 +02:00
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import java.util.concurrent.TimeUnit;
Clean up Future/Promises API (#11575) Motivation: The generics for the existing futures, promises, and listeners are too complicated. This complication comes from the existence of `ChannelPromise` and `ChannelFuture`, which forces listeners to care about the particular _type_ of future being listened on. Modification: * Add a `FutureContextListener` which can take a context object as an additional argument. This allows our listeners to have the channel piped through to them, so they don't need to rely on the `ChannelFuture.channel()` method. * Make the `FutureListener`, along with the `FutureContextListener` sibling, the default listener API, retiring the `GenericFutureListener` since we no longer need to abstract over the type of the future. * Change all uses of `ChannelPromise` to `Promise<Void>`. * Change all uses of `ChannelFuture` to `Future<Void>`. * Change all uses of `GenericFutureListener` to either `FutureListener` or `FutureContextListener` as needed. * Remove `ChannelFutureListener` and `GenericFutureListener`. * Introduce a `ChannelFutureListeners` enum to house the constants that previously lived in `ChannelFutureListener`. These constants now implement `FutureContextListener` and take the `Channel` as a context. * Remove `ChannelPromise` and `ChannelFuture` — all usages now rely on the plain `Future` and `Promise` APIs. * Add static factory methods to `DefaultPromise` that allow us to create promises that are initialised as successful or failed. * Remove `CompleteFuture`, `SucceededFuture`, `FailedFuture`, `CompleteChannelFuture`, `SucceededChannelFuture`, and `FailedChannelFuture`. * Remove `ChannelPromiseNotifier`. Result: Cleaner generics and more straight forward code.
2021-08-20 09:55:16 +02:00
import static java.util.Objects.requireNonNull;
/**
* Raises a {@link WriteTimeoutException} when a write operation cannot finish in a certain period of time.
2009-06-19 13:33:38 +02:00
*
* <pre>
* // The connection is closed when a write operation cannot finish in 30 seconds.
*
* public class MyChannelInitializer extends {@link ChannelInitializer}&lt;{@link Channel}&gt; {
2012-12-19 21:08:47 +01:00
* public void initChannel({@link Channel} channel) {
2012-12-20 15:45:49 +01:00
* channel.pipeline().addLast("writeTimeoutHandler", new {@link WriteTimeoutHandler}(30);
* channel.pipeline().addLast("myHandler", new MyHandler());
* }
2012-12-19 21:08:47 +01:00
* }
*
2012-12-19 21:08:47 +01:00
* // Handler should handle the {@link WriteTimeoutException}.
* public class MyHandler implements {@link ChannelHandler} {
2012-12-19 21:08:47 +01:00
* {@code @Override}
* public void exceptionCaught({@link ChannelHandlerContext} ctx, {@link Throwable} cause)
* throws {@link Exception} {
* if (cause instanceof {@link WriteTimeoutException}) {
* // do something
* } else {
* super.exceptionCaught(ctx, cause);
* }
* }
* }
*
2010-02-02 03:00:04 +01:00
* {@link ServerBootstrap} bootstrap = ...;
* ...
2012-12-19 21:08:47 +01:00
* bootstrap.childHandler(new MyChannelInitializer());
* ...
* </pre>
2009-06-19 13:33:38 +02:00
* @see ReadTimeoutHandler
* @see IdleStateHandler
*/
public class WriteTimeoutHandler implements ChannelHandler {
private static final long MIN_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(1);
private final long timeoutNanos;
/**
* A doubly-linked list to track all WriteTimeoutTasks
*/
private WriteTimeoutTask lastTask;
private boolean closed;
2009-06-19 13:33:38 +02:00
/**
* Creates a new instance.
*
* @param timeoutSeconds
* write timeout in seconds
*/
public WriteTimeoutHandler(int timeoutSeconds) {
this(timeoutSeconds, TimeUnit.SECONDS);
2009-02-11 06:23:05 +01:00
}
2009-06-19 13:33:38 +02:00
/**
* Creates a new instance.
*
* @param timeout
* write timeout
* @param unit
* the {@link TimeUnit} of {@code timeout}
*/
public WriteTimeoutHandler(long timeout, TimeUnit unit) {
requireNonNull(unit, "unit");
2009-09-04 09:19:32 +02:00
if (timeout <= 0) {
timeoutNanos = 0;
2009-09-04 09:19:32 +02:00
} else {
timeoutNanos = Math.max(unit.toNanos(timeout), MIN_TIMEOUT_NANOS);
2009-09-04 09:19:32 +02:00
}
}
@Override
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
public Future<Void> write(ChannelHandlerContext ctx, Object msg) {
Future<Void> f = ctx.write(msg);
if (timeoutNanos > 0) {
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
scheduleTimeout(ctx, f);
}
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
return f;
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
assert ctx.executor().inEventLoop();
WriteTimeoutTask task = lastTask;
lastTask = null;
while (task != null) {
assert task.ctx.executor().inEventLoop();
task.scheduledFuture.cancel(false);
WriteTimeoutTask prev = task.prev;
task.prev = null;
task.next = null;
task = prev;
}
}
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
private void scheduleTimeout(final ChannelHandlerContext ctx, final Future<Void> future) {
// Schedule a timeout.
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
final WriteTimeoutTask task = new WriteTimeoutTask(ctx, future);
task.scheduledFuture = ctx.executor().schedule(task, timeoutNanos, TimeUnit.NANOSECONDS);
if (!task.scheduledFuture.isDone()) {
addWriteTimeoutTask(task);
// Cancel the scheduled timeout if the flush promise is complete.
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
future.addListener(task);
}
}
private void addWriteTimeoutTask(WriteTimeoutTask task) {
assert task.ctx.executor().inEventLoop();
if (lastTask != null) {
lastTask.next = task;
task.prev = lastTask;
}
lastTask = task;
}
private void removeWriteTimeoutTask(WriteTimeoutTask task) {
assert task.ctx.executor().inEventLoop();
if (task == lastTask) {
// task is the tail of list
assert task.next == null;
lastTask = lastTask.prev;
if (lastTask != null) {
lastTask.next = null;
}
} else if (task.prev == null && task.next == null) {
// Since task is not lastTask, then it has been removed or not been added.
return;
} else if (task.prev == null) {
// task is the head of list and the list has at least 2 nodes
task.next.prev = null;
} else {
task.prev.next = task.next;
task.next.prev = task.prev;
}
task.prev = null;
task.next = null;
}
2009-06-19 13:17:38 +02:00
2013-07-12 15:43:50 +02:00
/**
* Is called when a write timeout was detected
*/
protected void writeTimedOut(ChannelHandlerContext ctx) throws Exception {
if (!closed) {
ctx.fireExceptionCaught(WriteTimeoutException.INSTANCE);
ctx.close();
closed = true;
2009-03-04 15:08:31 +01:00
}
}
Clean up Future/Promises API (#11575) Motivation: The generics for the existing futures, promises, and listeners are too complicated. This complication comes from the existence of `ChannelPromise` and `ChannelFuture`, which forces listeners to care about the particular _type_ of future being listened on. Modification: * Add a `FutureContextListener` which can take a context object as an additional argument. This allows our listeners to have the channel piped through to them, so they don't need to rely on the `ChannelFuture.channel()` method. * Make the `FutureListener`, along with the `FutureContextListener` sibling, the default listener API, retiring the `GenericFutureListener` since we no longer need to abstract over the type of the future. * Change all uses of `ChannelPromise` to `Promise<Void>`. * Change all uses of `ChannelFuture` to `Future<Void>`. * Change all uses of `GenericFutureListener` to either `FutureListener` or `FutureContextListener` as needed. * Remove `ChannelFutureListener` and `GenericFutureListener`. * Introduce a `ChannelFutureListeners` enum to house the constants that previously lived in `ChannelFutureListener`. These constants now implement `FutureContextListener` and take the `Channel` as a context. * Remove `ChannelPromise` and `ChannelFuture` — all usages now rely on the plain `Future` and `Promise` APIs. * Add static factory methods to `DefaultPromise` that allow us to create promises that are initialised as successful or failed. * Remove `CompleteFuture`, `SucceededFuture`, `FailedFuture`, `CompleteChannelFuture`, `SucceededChannelFuture`, and `FailedChannelFuture`. * Remove `ChannelPromiseNotifier`. Result: Cleaner generics and more straight forward code.
2021-08-20 09:55:16 +02:00
private final class WriteTimeoutTask implements Runnable, FutureListener<Void> {
private final ChannelHandlerContext ctx;
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
private final Future<Void> future;
// WriteTimeoutTask is also a node of a doubly-linked list
WriteTimeoutTask prev;
WriteTimeoutTask next;
Future<?> scheduledFuture;
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
WriteTimeoutTask(ChannelHandlerContext ctx, Future<Void> future) {
this.ctx = ctx;
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
this.future = future;
}
@Override
public void run() {
// Was not written yet so issue a write timeout
// The promise itself will be failed with a ClosedChannelException once the close() was issued
// See https://github.com/netty/netty/issues/2159
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
if (!future.isDone()) {
try {
writeTimedOut(ctx);
} catch (Throwable t) {
ctx.fireExceptionCaught(t);
}
}
removeWriteTimeoutTask(this);
}
@Override
Clean up Future/Promises API (#11575) Motivation: The generics for the existing futures, promises, and listeners are too complicated. This complication comes from the existence of `ChannelPromise` and `ChannelFuture`, which forces listeners to care about the particular _type_ of future being listened on. Modification: * Add a `FutureContextListener` which can take a context object as an additional argument. This allows our listeners to have the channel piped through to them, so they don't need to rely on the `ChannelFuture.channel()` method. * Make the `FutureListener`, along with the `FutureContextListener` sibling, the default listener API, retiring the `GenericFutureListener` since we no longer need to abstract over the type of the future. * Change all uses of `ChannelPromise` to `Promise<Void>`. * Change all uses of `ChannelFuture` to `Future<Void>`. * Change all uses of `GenericFutureListener` to either `FutureListener` or `FutureContextListener` as needed. * Remove `ChannelFutureListener` and `GenericFutureListener`. * Introduce a `ChannelFutureListeners` enum to house the constants that previously lived in `ChannelFutureListener`. These constants now implement `FutureContextListener` and take the `Channel` as a context. * Remove `ChannelPromise` and `ChannelFuture` — all usages now rely on the plain `Future` and `Promise` APIs. * Add static factory methods to `DefaultPromise` that allow us to create promises that are initialised as successful or failed. * Remove `CompleteFuture`, `SucceededFuture`, `FailedFuture`, `CompleteChannelFuture`, `SucceededChannelFuture`, and `FailedChannelFuture`. * Remove `ChannelPromiseNotifier`. Result: Cleaner generics and more straight forward code.
2021-08-20 09:55:16 +02:00
public void operationComplete(Future<? extends Void> future) throws Exception {
// scheduledFuture has already be set when reaching here
scheduledFuture.cancel(false);
// Check if its safe to modify the "doubly-linked-list" that we maintain. If its not we will schedule the
// modification so its picked up by the executor..
if (ctx.executor().inEventLoop()) {
removeWriteTimeoutTask(this);
} else {
// So let's just pass outself to the executor which will then take care of remove this task
// from the doubly-linked list. Schedule ourself is fine as the promise itself is done.
//
// This fixes https://github.com/netty/netty/issues/11053
Don't take Promise as argument in Channel API. (#11346) Motivation: At the moment the outbound operations of ChannelHandler take a Promise as argument. This Promise needs to be carried forward to the next handler in the pipeline until it hits the transport. This is API choice has a few quirks which we should aim to remove: - There is a difference between if you add a FutureListener to the Promise or the Future that is returned by the outbound method in terms of the ordering of execution of the listeners. Sometimes we add the listener to the promise while in reality we usually always want to add it to the future to ensure the listerns are executed in the "correct order". - It is quite easy to "loose" a promise by forgetting to use the right method which also takes a promise - We have no idea what EventExecutor is used for the passed in Promise which may invalid our assumption of threading. While changing the method signature of the outbound operations of the ChannelHandler is a good step forward we should also take care of just remove all the methods from ChannelOutboundInvoker (and its sub-types) that take a Promise and just always use the methods that return a Future only. Modifications: - Change the signature of the methods that took a Promise to not take one anymore and just return a Future - Remove all operations for ChannelOutboundInvoker that take a Promise. - Adjust all code to cope with the API changes Result: Cleaner API which is easier to reason about and easier to use.
2021-08-25 14:12:33 +02:00
assert future.isDone();
ctx.executor().execute(this);
}
}
}
}