netty5/codec-http2/src/main/java/io/netty/handler/codec/http2/Http2RemoteFlowController.java

171 lines
7.5 KiB
Java
Raw Normal View History

/*
* Copyright 2014 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 License for the specific language governing permissions and limitations under
* the License.
*/
package io.netty.handler.codec.http2;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.UnstableApi;
/**
* A {@link Http2FlowController} for controlling the flow of outbound {@code DATA} frames to the remote
* endpoint.
*/
@UnstableApi
public interface Http2RemoteFlowController extends Http2FlowController {
/**
* Get the {@link ChannelHandlerContext} for which to apply flow control on.
* <p>
* This is intended for us by {@link FlowControlled} implementations only. Use with caution.
* @return The {@link ChannelHandlerContext} for which to apply flow control on.
*/
ChannelHandlerContext channelHandlerContext();
/**
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
* Queues a payload for transmission to the remote endpoint. There is no guarantee as to when the data
* will be written or how it will be assigned to frames.
* before sending.
* <p>
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
* Writes do not actually occur until {@link #writePendingBytes()} is called.
*
* @param stream the subject stream. Must not be the connection stream object.
* @param payload payload to write subject to flow-control accounting and ordering rules.
*/
void addFlowControlled(Http2Stream stream, FlowControlled payload);
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
/**
* Determine if {@code stream} has any {@link FlowControlled} frames currently queued.
* @param stream the stream to check if it has flow controlled frames.
* @return {@code true} if {@code stream} has any {@link FlowControlled} frames currently queued.
*/
boolean hasFlowControlled(Http2Stream stream);
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
/**
* Write all data pending in the flow controller up to the flow-control limits.
*
* @throws Http2Exception throws if a protocol-related error occurred.
*/
void writePendingBytes() throws Http2Exception;
/**
* Set the active listener on the flow-controller.
*
* @param listener to notify when the a write occurs, can be {@code null}.
*/
void listener(Listener listener);
/**
* Determine if the {@code stream} has bytes remaining for use in the flow control window.
* <p>
* Note that this method respects channel writability. The channel must be writable for this method to
* return {@code true}.
*
* @param stream The stream to test.
* @return {@code true} if the {@code stream} has bytes remaining for use in the flow control window and the
* channel is writable, {@code false} otherwise.
*/
boolean isWritable(Http2Stream stream);
/**
* Notification that the writability of {@link #channelHandlerContext()} has changed.
* @throws Http2Exception If any writes occur as a result of this call and encounter errors.
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
*/
void channelWritabilityChanged() throws Http2Exception;
HTTP/2 Non Active Stream RFC Corrections Motivation: codec-http2 couples the dependency tree state with the remainder of the stream state (Http2Stream). This makes implementing constraints where stream state and dependency tree state diverge in the RFC challenging. For example the RFC recommends retaining dependency tree state after a stream transitions to closed [1]. Dependency tree state can be exchanged on streams in IDLE. In practice clients may use stream IDs for the purpose of establishing QoS classes and therefore retaining this dependency tree state can be important to client perceived performance. It is difficult to limit the total amount of state we retain when stream state and dependency tree state is combined. Modifications: - Remove dependency tree, priority, and weight related items from public facing Http2Connection and Http2Stream APIs. This information is optional to track and depends on the flow controller implementation. - Move all dependency tree, priority, and weight related code from DefaultHttp2Connection to WeightedFairQueueByteDistributor. This is currently the only place which cares about priority. We can pull out the dependency tree related code in the future if it is generally useful to expose for other implementations. - DefaultHttp2Connection should explicitly limit the number of reserved streams now that IDLE streams are no longer created. Result: More compliant with the HTTP/2 RFC. Fixes https://github.com/netty/netty/issues/6206. [1] https://tools.ietf.org/html/rfc7540#section-5.3.4
2017-01-24 21:50:39 +01:00
/**
* Explicitly update the dependency tree. This method is called independently of stream state changes.
* @param childStreamId The stream identifier associated with the child stream.
* @param parentStreamId The stream identifier associated with the parent stream. May be {@code 0},
* to make {@code childStreamId} and immediate child of the connection.
* @param weight The weight which is used relative to other child streams for {@code parentStreamId}. This value
* must be between 1 and 256 (inclusive).
* @param exclusive If {@code childStreamId} should be the exclusive dependency of {@code parentStreamId}.
*/
void updateDependencyTree(int childStreamId, int parentStreamId, short weight, boolean exclusive);
/**
* Implementations of this interface are used to progressively write chunks of the underlying
* payload to the stream. A payload is considered to be fully written if {@link #write} has
* been called at least once and it's {@link #size} is now zero.
*/
interface FlowControlled {
/**
* The size of the payload in terms of bytes applied to the flow-control window.
* Some payloads like {@code HEADER} frames have no cost against flow control and would
* return 0 for this value even though they produce a non-zero number of bytes on
* the wire. Other frames like {@code DATA} frames have both their payload and padding count
* against flow-control.
*/
int size();
/**
* Called to indicate that an error occurred before this object could be completely written.
* <p>
* The {@link Http2RemoteFlowController} will make exactly one call to either
* this method or {@link #writeComplete()}.
* </p>
*
* @param ctx The context to use if any communication needs to occur as a result of the error.
* This may be {@code null} if an exception occurs when the connection has not been established yet.
* @param cause of the error.
*/
void error(ChannelHandlerContext ctx, Throwable cause);
/**
* Called after this object has been successfully written.
* <p>
* The {@link Http2RemoteFlowController} will make exactly one call to either
* this method or {@link #error(ChannelHandlerContext, Throwable)}.
* </p>
*/
void writeComplete();
/**
* Writes up to {@code allowedBytes} of the encapsulated payload to the stream. Note that
* a value of 0 may be passed which will allow payloads with flow-control size == 0 to be
* written. The flow-controller may call this method multiple times with different values until
* the payload is fully written, i.e it's size after the write is 0.
* <p>
* When an exception is thrown the {@link Http2RemoteFlowController} will make a call to
* {@link #error(ChannelHandlerContext, Throwable)}.
* </p>
*
* @param ctx The context to use for writing.
* @param allowedBytes an upper bound on the number of bytes the payload can write at this time.
*/
void write(ChannelHandlerContext ctx, int allowedBytes);
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
/**
* Merge the contents of the {@code next} message into this message so they can be written out as one unit.
* This allows many small messages to be written as a single DATA frame.
*
* @return {@code true} if {@code next} was successfully merged and does not need to be enqueued,
* {@code false} otherwise.
*/
boolean merge(ChannelHandlerContext ctx, FlowControlled next);
Make the flow-controllers write fewer, fatter frames to improve throughput. Motivation: Coalescing many small writes into a larger DATA frame reduces framing overheads on the wire and reduces the number of calls to Http2FrameListeners on the remote side. Delaying the write of WINDOW_UPDATE until flush allows for more consumed bytes to be returned as the aggregate of consumed bytes is returned and not the amount consumed when the threshold was crossed. Modifications: - Remote flow controller no longer immediately writes bytes when a flow-controlled payload is enqueued. Sequential data payloads are now merged into a single CompositeByteBuf which are written when 'writePendingBytes' is called. - Listener added to remote flow-controller which observes written bytes per stream. - Local flow-controller no longer immediately writes WINDOW_UPDATE when the ratio threshold is crossed. Now an explicit call to 'writeWindowUpdates' triggers the WINDOW_UPDATE for all streams who's ratio is exceeded at that time. This results in fewer window updates being sent and more bytes being returned. - Http2ConnectionHandler.flush triggers 'writeWindowUpdates' on the local flow-controller followed by 'writePendingBytes' on the remote flow-controller so WINDOW_UPDATES preceed DATA frames on the wire. Result: - Better throughput for writing many small DATA chunks followed by a flush, saving 9-bytes per coalesced frame. - Fewer WINDOW_UPDATES being written and more flow-control bytes returned to remote side more quickly, thereby improving throughput.
2015-06-04 20:55:18 +02:00
}
/**
* Listener to the number of flow-controlled bytes written per stream.
*/
interface Listener {
/**
* Notification that {@link Http2RemoteFlowController#isWritable(Http2Stream)} has changed for {@code stream}.
* <p>
* This method should not throw. Any thrown exceptions are considered a programming error and are ignored.
* @param stream The stream which writability has changed for.
*/
void writabilityChanged(Http2Stream stream);
}
}