Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
windows.py134 linesDownload Raw Back to h2
1"""2h2/windows3~~~~~~~~~~4 5Defines tools for managing HTTP/2 flow control windows.6 7The objects defined in this module are used to automatically manage HTTP/28flow control windows. Specifically, they keep track of what the size of the9window is, how much data has been consumed from that window, and how much data10the user has already used. It then implements a basic algorithm that attempts11to manage the flow control window without user input, trying to ensure that it12does not emit too many WINDOW_UPDATE frames.13"""14from __future__ import annotations15 16from .exceptions import FlowControlError17 18# The largest acceptable value for a HTTP/2 flow control window.19LARGEST_FLOW_CONTROL_WINDOW = 2**31 - 120 21 22class WindowManager:23    """24    A basic HTTP/2 window manager.25 26    :param max_window_size: The maximum size of the flow control window.27    :type max_window_size: ``int``28    """29 30    def __init__(self, max_window_size: int) -> None:31        assert max_window_size <= LARGEST_FLOW_CONTROL_WINDOW32        self.max_window_size = max_window_size33        self.current_window_size = max_window_size34        self._bytes_processed = 035 36    def window_consumed(self, size: int) -> None:37        """38        We have received a certain number of bytes from the remote peer. This39        necessarily shrinks the flow control window!40 41        :param size: The number of flow controlled bytes we received from the42            remote peer.43        :type size: ``int``44        :returns: Nothing.45        :rtype: ``None``46        """47        self.current_window_size -= size48        if self.current_window_size < 0:49            msg = "Flow control window shrunk below 0"50            raise FlowControlError(msg)51 52    def window_opened(self, size: int) -> None:53        """54        The flow control window has been incremented, either because of manual55        flow control management or because of the user changing the flow56        control settings. This can have the effect of increasing what we57        consider to be the "maximum" flow control window size.58 59        This does not increase our view of how many bytes have been processed,60        only of how much space is in the window.61 62        :param size: The increment to the flow control window we received.63        :type size: ``int``64        :returns: Nothing65        :rtype: ``None``66        """67        self.current_window_size += size68 69        if self.current_window_size > LARGEST_FLOW_CONTROL_WINDOW:70            msg = f"Flow control window mustn't exceed {LARGEST_FLOW_CONTROL_WINDOW}"71            raise FlowControlError(msg)72 73        self.max_window_size = max(self.current_window_size, self.max_window_size)74 75    def process_bytes(self, size: int) -> int | None:76        """77        The application has informed us that it has processed a certain number78        of bytes. This may cause us to want to emit a window update frame. If79        we do want to emit a window update frame, this method will return the80        number of bytes that we should increment the window by.81 82        :param size: The number of flow controlled bytes that the application83            has processed.84        :type size: ``int``85        :returns: The number of bytes to increment the flow control window by,86            or ``None``.87        :rtype: ``int`` or ``None``88        """89        self._bytes_processed += size90        return self._maybe_update_window()91 92    def _maybe_update_window(self) -> int | None:93        """94        Run the algorithm.95 96        Our current algorithm can be described like this.97 98        1. If no bytes have been processed, we immediately return 0. There is99           no meaningful way for us to hand space in the window back to the100           remote peer, so let's not even try.101        2. If there is no space in the flow control window, and we have102           processed at least 1024 bytes (or 1/4 of the window, if the window103           is smaller), we will emit a window update frame. This is to avoid104           the risk of blocking a stream altogether.105        3. If there is space in the flow control window, and we have processed106           at least 1/2 of the window worth of bytes, we will emit a window107           update frame. This is to minimise the number of window update frames108           we have to emit.109 110        In a healthy system with large flow control windows, this will111        irregularly emit WINDOW_UPDATE frames. This prevents us starving the112        connection by emitting eleventy bajillion WINDOW_UPDATE frames,113        especially in situations where the remote peer is sending a lot of very114        small DATA frames.115        """116        # TODO: Can the window be smaller than 1024 bytes? If not, we can117        # streamline this algorithm.118        if not self._bytes_processed:119            return None120 121        max_increment = (self.max_window_size - self.current_window_size)122        increment = 0123 124        # Note that, even though we may increment less than _bytes_processed,125        # we still want to set it to zero whenever we emit an increment. This126        # is because we'll always increment up to the maximum we can.127        if ((self.current_window_size == 0) and (128                self._bytes_processed > min(1024, self.max_window_size // 4))) or self._bytes_processed >= (self.max_window_size // 2):129            increment = min(self._bytes_processed, max_increment)130            self._bytes_processed = 0131 132        self.current_window_size += increment133        return increment134 
codekingpro/portable-devtools · Team Ai