Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package ghc-network-control for
openSUSE:Factory checked in at 2024-11-12 19:20:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ghc-network-control (Old)
and /work/SRC/openSUSE:Factory/.ghc-network-control.new.2017 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-network-control"
Tue Nov 12 19:20:14 2024 rev:2 rq:1222959 version:0.1.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/ghc-network-control/ghc-network-control.changes
2023-12-05 17:03:57.634793848 +0100
+++
/work/SRC/openSUSE:Factory/.ghc-network-control.new.2017/ghc-network-control.changes
2024-11-12 19:20:41.193620558 +0100
@@ -1,0 +2,24 @@
+Thu Jul 18 22:56:21 UTC 2024 - Peter Simons <[email protected]>
+
+- Update network-control to version 0.1.3.
+ ## 0.1.3
+
+ * Simplify `maybeOpenRxWindow` and improve docs
+ [#7](https://github.com/kazu-yamamoto/network-control/pull/7)
+
+ ## 0.1.2
+
+ * introducing a minimum size for window update
+ [#5](https://github.com/kazu-yamamoto/network-control/pull/5)
+
+ ## 0.1.1
+
+ * Change defaultMaxData
+ [#4](https://github.com/kazu-yamamoto/network-control/pull/4)
+
+ ## 0.1.0
+
+ * Breaking change: Renaming rxfWindow to rxfBufSize.
+ * Updating the document about flow control.
+
+-------------------------------------------------------------------
Old:
----
network-control-0.0.2.tar.gz
New:
----
network-control-0.1.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ ghc-network-control.spec ++++++
--- /var/tmp/diff_new_pack.LJih3E/_old 2024-11-12 19:20:42.977695362 +0100
+++ /var/tmp/diff_new_pack.LJih3E/_new 2024-11-12 19:20:42.989695865 +0100
@@ -1,7 +1,7 @@
#
# spec file for package ghc-network-control
#
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,8 +18,9 @@
%global pkg_name network-control
%global pkgver %{pkg_name}-%{version}
+%bcond_with tests
Name: ghc-%{pkg_name}
-Version: 0.0.2
+Version: 0.1.3
Release: 0
Summary: Library to control network protocols
License: BSD-3-Clause
@@ -34,6 +35,16 @@
BuildRequires: ghc-unix-time-devel
BuildRequires: ghc-unix-time-prof
ExcludeArch: %{ix86}
+%if %{with tests}
+BuildRequires: ghc-QuickCheck-devel
+BuildRequires: ghc-QuickCheck-prof
+BuildRequires: ghc-hspec-devel
+BuildRequires: ghc-hspec-prof
+BuildRequires: ghc-pretty-simple-devel
+BuildRequires: ghc-pretty-simple-prof
+BuildRequires: ghc-text-devel
+BuildRequires: ghc-text-prof
+%endif
%description
Common parts to control network protocols.
@@ -74,6 +85,9 @@
%install
%ghc_lib_install
+%check
+%cabal_test
+
%post devel
%ghc_pkg_recache
++++++ network-control-0.0.2.tar.gz -> network-control-0.1.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/network-control-0.0.2/Changelog.md
new/network-control-0.1.3/Changelog.md
--- old/network-control-0.0.2/Changelog.md 2001-09-09 03:46:40.000000000
+0200
+++ new/network-control-0.1.3/Changelog.md 2001-09-09 03:46:40.000000000
+0200
@@ -1,5 +1,25 @@
# Revision history for network-control
+## 0.1.3
+
+* Simplify `maybeOpenRxWindow` and improve docs
+ [#7](https://github.com/kazu-yamamoto/network-control/pull/7)
+
+## 0.1.2
+
+* introducing a minimum size for window update
+ [#5](https://github.com/kazu-yamamoto/network-control/pull/5)
+
+## 0.1.1
+
+* Change defaultMaxData
+ [#4](https://github.com/kazu-yamamoto/network-control/pull/4)
+
+## 0.1.0
+
+* Breaking change: Renaming rxfWindow to rxfBufSize.
+* Updating the document about flow control.
+
## 0.0.2
* Adding constants.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/network-control-0.0.2/Network/Control/Flow.hs
new/network-control-0.1.3/Network/Control/Flow.hs
--- old/network-control-0.0.2/Network/Control/Flow.hs 2001-09-09
03:46:40.000000000 +0200
+++ new/network-control-0.1.3/Network/Control/Flow.hs 2001-09-09
03:46:40.000000000 +0200
@@ -1,20 +1,27 @@
{-# LANGUAGE RecordWildCards #-}
module Network.Control.Flow (
- -- * Constants for flow control.
+ -- * Flow control
+
+ -- | This is based on the total approach of QUIC rather than
+ -- the difference approach of HTTP\/2 because QUIC'one is
+ -- considered safer. Please refer to [Using HTTP\/3 Stream Limits in
HTTP\/2](https://datatracker.ietf.org/doc/draft-thomson-httpbis-h2-stream-limits/)
to understand that QUIC's approaches are better though its topic is about
stream concurrency.
+
+ -- ** Constants for flow control.
defaultMaxStreams,
defaultMaxStreamData,
defaultMaxData,
- -- * Flow control for sending
+ -- ** Flow control for sending
TxFlow (..),
newTxFlow,
txWindowSize,
WindowSize,
- -- * Flow control for receiving
+ -- ** Flow control for receiving
RxFlow (..),
newRxFlow,
+ rxWindowSize,
FlowControlType (..),
maybeOpenRxWindow,
checkRxLimit,
@@ -30,21 +37,41 @@
defaultMaxStreamData :: Int
defaultMaxStreamData = 262144
--- | Default max data of a connection. (1M bytes)
+-- | Default max data of a connection.
+--
+-- By default, this is set to @defaultMaxStreams * defaultMaxStreamData@. This
+-- ensures that streams that are not currently handled cannot exhaust the
+-- connection window.
+--
+-- If you use a smaller connection window size, you __must__ ensure that if you
+-- are handling fewer concurrent streams than allowed by 'defaultMaxStreams',
+-- that the unhandled streams cannot exhaust the connection window, or risk the
+-- entire system deadlocking.
defaultMaxData :: Int
-defaultMaxData = 1048576
+defaultMaxData = defaultMaxStreamData * defaultMaxStreams
-- | Window size.
type WindowSize = Int
-- | Flow for sending
+--
+-- @
+-- -------------------------------------->
+-- ^ ^
+-- txfSent txfLimit
+--
+-- |-----------| The size which this node can send
+-- txWindowSize
+-- @
data TxFlow = TxFlow
{ txfSent :: Int
+ -- ^ The total size of sent data.
, txfLimit :: Int
+ -- ^ The total size of data which can be sent.
}
- deriving (Show)
+ deriving (Eq, Show)
--- | Creating TX flow with an initial window size.
+-- | Creating TX flow with a receive buffer size.
newTxFlow :: WindowSize -> TxFlow
newTxFlow win = TxFlow 0 win
@@ -52,19 +79,71 @@
txWindowSize :: TxFlow -> WindowSize
txWindowSize TxFlow{..} = txfLimit - txfSent
--- | Flow for receiving
+-- | Flow for receiving.
+--
+-- The goal of 'RxFlow' is to ensure that our network peer does not send us
data
+-- faster than we can consume it. We therefore impose a maximum number of
+-- unconsumed bytes that we are willing to receive from the peer, which we
refer
+-- to as the buffer size:
+--
+-- @
+-- rxfBufSize
+-- |---------------------------|
+-- -------------------------------------------->
+-- ^ ^
+-- rxfConsumed rxvReceived
+-- @
+--
+-- The peer does not know of course how many bytes we have consumed of the data
+-- that they sent us, so they keep track of their own limit of how much data
+-- they are allowed to send. We keep track of this limit also:
+--
+-- @
+-- rxfBufSize
+-- |---------------------------|
+-- -------------------------------------------->
+-- ^ ^ ^
+-- rxfConsumed rxvReceived |
+-- rxfLimit
+-- @
+--
+-- Each time we receive data from the peer, we check that they do not exceed
the
+-- limit ('checkRxLimit'). When we consume data, we periodically send the peer
+-- an update (known as a _window update_) of what their new limit is
+-- ('maybeOpenRxWindow'). To decrease overhead, we only this if the window
+-- update is at least half the window size.
data RxFlow = RxFlow
- { rxfWindow :: WindowSize
+ { rxfBufSize :: Int
+ -- ^ Maxinum number of unconsumed bytes the peer can send us
+ --
+ -- See discussion above for details.
, rxfConsumed :: Int
+ -- ^ How much of the data that the peer has sent us have we consumed?
+ --
+ -- This is an absolute number: the total about of bytes consumed over the
+ -- lifetime of the connection or stream (i.e., not relative to the window).
, rxfReceived :: Int
+ -- ^ How much data have we received from the peer?
+ --
+ -- Like 'rxfConsumed', this is an absolute number.
, rxfLimit :: Int
+ -- ^ Current limit on how many bytes the peer is allowed to send us.
+ --
+ -- Like 'rxfConsumed, this is an absolute number.
}
- deriving (Show)
+ deriving (Eq, Show)
-- | Creating RX flow with an initial window size.
newRxFlow :: WindowSize -> RxFlow
newRxFlow win = RxFlow win 0 0 win
+-- | 'rxfLimit' - 'rxfReceived'.
+--
+-- This is the number of bytes the peer is still allowed to send before they
+-- must wait for a window update; see 'RxFlow' for details.
+rxWindowSize :: RxFlow -> WindowSize
+rxWindowSize RxFlow{..} = rxfLimit - rxfReceived
+
-- | The representation of window size update.
data FlowControlType
= -- | HTTP\/2 style
@@ -72,10 +151,9 @@
| -- | QUIC style
FCTMaxData
--- | When an application consumed received data,
--- this function should be called to update 'rxfConsumed'.
--- If the window size is less than the half of the initial window.
--- the representation of window size update is returned.
+-- | Record that we have consumed some received data
+--
+-- May return a window update; see 'RxFlow' for details.
maybeOpenRxWindow
:: Int
-- ^ The consumed size.
@@ -84,24 +162,28 @@
-> (RxFlow, Maybe Int)
-- ^ 'Just' if the size should be informed to the peer.
maybeOpenRxWindow consumed fct flow@RxFlow{..}
- | available < threshold =
- let limit = consumed' + rxfWindow
- flow' =
+ | winUpdate >= threshold =
+ let flow' =
flow
- { rxfConsumed = consumed'
- , rxfLimit = limit
+ { rxfConsumed = rxfConsumed'
+ , rxfLimit = rxfLimit'
}
update = case fct of
- FCTWindowUpdate -> limit - rxfLimit
- FCTMaxData -> limit
+ FCTWindowUpdate -> winUpdate
+ FCTMaxData -> rxfLimit'
in (flow', Just update)
| otherwise =
- let flow' = flow{rxfConsumed = consumed'}
+ let flow' = flow{rxfConsumed = rxfConsumed'}
in (flow', Nothing)
where
- available = rxfLimit - rxfReceived
- threshold = rxfWindow `unsafeShiftR` 1
- consumed' = rxfConsumed + consumed
+ rxfConsumed' = rxfConsumed + consumed
+
+ -- Minimum window update size
+ threshold = rxfBufSize `unsafeShiftR` 1
+
+ -- The window update, /if/ we choose to send it
+ rxfLimit' = rxfConsumed' + rxfBufSize
+ winUpdate = rxfLimit' - rxfLimit
-- | Checking if received data is acceptable against the
-- current window.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/network-control-0.0.2/Network/Control.hs
new/network-control-0.1.3/Network/Control.hs
--- old/network-control-0.0.2/Network/Control.hs 2001-09-09
03:46:40.000000000 +0200
+++ new/network-control-0.1.3/Network/Control.hs 2001-09-09
03:46:40.000000000 +0200
@@ -1,4 +1,5 @@
-- | Common parts to control network protocols.
+-- This library assumes that 'Int' is 64bit.
module Network.Control (
module Network.Control.Flow,
module Network.Control.LRUCache,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/network-control-0.0.2/network-control.cabal
new/network-control-0.1.3/network-control.cabal
--- old/network-control-0.0.2/network-control.cabal 2001-09-09
03:46:40.000000000 +0200
+++ new/network-control-0.1.3/network-control.cabal 2001-09-09
03:46:40.000000000 +0200
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: network-control
-version: 0.0.2
+version: 0.1.3
license: BSD-3-Clause
license-file: LICENSE
maintainer: [email protected]
@@ -25,3 +25,22 @@
base >=4.14 && <5,
psqueues,
unix-time
+
+test-suite spec
+ type: exitcode-stdio-1.0
+ main-is: Spec.hs
+ build-tool-depends: hspec-discover:hspec-discover
+ hs-source-dirs: test
+ other-modules:
+ Network.Control.FlowSpec
+
+ default-language: Haskell2010
+ default-extensions: Strict StrictData
+ ghc-options: -Wall -threaded
+ build-depends:
+ base,
+ hspec >=1.3,
+ network-control,
+ QuickCheck,
+ pretty-simple,
+ text
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/network-control-0.0.2/test/Network/Control/FlowSpec.hs
new/network-control-0.1.3/test/Network/Control/FlowSpec.hs
--- old/network-control-0.0.2/test/Network/Control/FlowSpec.hs 1970-01-01
01:00:00.000000000 +0100
+++ new/network-control-0.1.3/test/Network/Control/FlowSpec.hs 2001-09-09
03:46:40.000000000 +0200
@@ -0,0 +1,163 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE NumericUnderscores #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# OPTIONS_GHC -Wno-orphans -Wno-incomplete-patterns #-}
+
+module Network.Control.FlowSpec where
+
+import Data.List
+import Data.Text.Lazy (unpack)
+import Network.Control
+import Test.Hspec
+import Test.Hspec.QuickCheck
+import Test.QuickCheck
+import Text.Pretty.Simple
+
+-- types
+
+data Op = Consume | Receive
+ deriving (Eq, Show, Bounded, Enum)
+
+data OpWithResult = ConsumeWithResult (Maybe Int) | ReceiveWithResult Bool
+ deriving (Eq, Show)
+
+data Step op = Step {stepOp :: op, stepArg :: Int}
+ deriving (Eq, Show)
+
+data Trace = Trace
+ { traceStart :: RxFlow
+ , traceSteps :: [(Int, Step OpWithResult, RxFlow)]
+ }
+ deriving (Eq, Show)
+
+-- arbitrary instances
+
+maxWindowSize :: Int
+maxWindowSize = 200 -- (more realistic: 2_000_000)
+
+instance Arbitrary RxFlow where
+ -- Prefer to generate a simple window size
+ arbitrary =
+ newRxFlow
+ <$> oneof
+ [ elements [1, 10, 50, 100]
+ , chooseInt (1, maxWindowSize)
+ ]
+
+instance Arbitrary Op where
+ arbitrary = elements [minBound ..]
+
+instance Arbitrary Trace where
+ arbitrary = do
+ initialFlow <- arbitrary
+ len <- chooseInt (0, 500)
+ Trace initialFlow <$> runManySteps len 0 initialFlow
+ where
+ runManySteps :: Int -> Int -> RxFlow -> Gen [(Int, Step OpWithResult,
RxFlow)]
+ runManySteps 0 _ _ = pure []
+ runManySteps len ix oldFlow = do
+ (newStep, newFlow) <- runStep oldFlow <$> genStep oldFlow
+ ((ix, newStep, newFlow) :) <$> runManySteps (len - 1) (ix + 1)
newFlow
+
+ genStep :: RxFlow -> Gen (Step Op)
+ genStep oldFlow = oneof [mkConsume, mkReceive]
+ where
+ -- Negative frames are non-sensical; frames larger than the window
+ -- size are theoretically possible (but will trivially be rejected
+ -- as exceeding the window).
+ mkReceive =
+ Step Receive <$> chooseInt (0, rxfBufSize oldFlow * 2)
+
+ -- We can only consume as much as we have received
+ -- (but it is in principle not a problem to consume 0 bytes)
+ mkConsume =
+ Step Consume <$> chooseInt (0, rxfReceived oldFlow -
rxfConsumed oldFlow)
+
+ runStep :: RxFlow -> Step Op -> (Step OpWithResult, RxFlow)
+ runStep oldFlow = \case
+ Step Consume arg ->
+ let (newFlow, limitDelta) = maybeOpenRxWindow arg
FCTWindowUpdate oldFlow
+ in (Step (ConsumeWithResult limitDelta) arg, newFlow)
+ Step Receive arg ->
+ let (newFlow, isAcceptable) = checkRxLimit arg oldFlow
+ in (Step (ReceiveWithResult isAcceptable) arg, newFlow)
+
+ shrink (Trace initialFlow steps) =
+ concat
+ [ -- Take a prefix (starting with the same initialFlow)
+ Trace initialFlow <$> init (inits steps)
+ , -- Take a suffix (starting with a later initialFlow)
+ map shiftInitialFlow $ tail (tails steps)
+ ]
+ where
+ shiftInitialFlow :: [(Int, Step OpWithResult, RxFlow)] -> Trace
+ shiftInitialFlow [] = Trace initialFlow []
+ shiftInitialFlow ((_, _, initialFlow') : rest) = Trace initialFlow'
rest
+
+-- invariants
+
+assertTrace :: Trace -> Property
+assertTrace (Trace initialFlow steps) = assertStep initialFlow steps
+
+assertStep :: RxFlow -> [(Int, Step OpWithResult, RxFlow)] -> Property
+assertStep _ [] = property True
+assertStep oldFlow ((ix, step, newFlow) : steps) =
+ (counterexample ("step #" <> show ix) check) .&. assertStep newFlow steps
+ where
+ check :: Expectation
+ check = case step of
+ Step (ConsumeWithResult limitDelta) arg -> do
+ -- There is no point duplicating precisely the same logic here as
in
+ -- 'maybeOpenRxWindow': that would result in circular reasoning.
+ -- Instead, we leave 'maybeOpenRxWindow' some implementation
+ -- freedom, and only verify that the window update makes sense:
+ --
+ -- (a) It can't be too large: the new window after the update
should
+ -- never exceed the specified buffer size.
+ -- (b) It can't be too late: if we consume /all/ received data, and
+ -- do not allow the peer to send any further data, then the
+ -- system deadlocks.
+ -- (c) It shouldn't be too small: very small window updates are
+ -- wasteful.
+ --
+ -- Within these parameters 'maybeOpenRxWindow' can decide when to
+ -- send window updates and how large they should be. We also don't
+ -- set the bound on (c) too strict.
+ newFlow
+ `shouldBe` RxFlow
+ { rxfBufSize = rxfBufSize oldFlow
+ , rxfConsumed = rxfConsumed oldFlow + arg
+ , rxfReceived = rxfReceived oldFlow
+ , rxfLimit = case limitDelta of
+ Nothing -> rxfLimit oldFlow
+ Just upd -> rxfLimit oldFlow + upd
+ }
+ -- Condition (a)
+ newFlow `shouldSatisfy` \flow ->
+ rxfLimit flow - rxfConsumed flow <= rxfBufSize flow
+ -- Condition (b)
+ newFlow `shouldSatisfy` \flow ->
+ rxfLimit flow > rxfConsumed flow
+ -- Condition (c)
+ limitDelta `shouldSatisfy` \mUpd ->
+ case mUpd of
+ Nothing -> True
+ Just upd -> upd >= rxfBufSize newFlow `div` 8
+ Step (ReceiveWithResult isAcceptable) arg -> do
+ newFlow
+ `shouldBe` if isAcceptable
+ then
+ RxFlow
+ { rxfBufSize = rxfBufSize newFlow
+ , rxfConsumed = rxfConsumed oldFlow
+ , rxfReceived = rxfReceived oldFlow + arg
+ , rxfLimit = rxfLimit oldFlow
+ }
+ else oldFlow
+
+spec :: Spec
+spec = do
+ focus . prop "state transition graph checks out" $
+ \trace -> counterexample (unpack $ pShowNoColor trace) (assertTrace
trace)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/network-control-0.0.2/test/Spec.hs
new/network-control-0.1.3/test/Spec.hs
--- old/network-control-0.0.2/test/Spec.hs 1970-01-01 01:00:00.000000000
+0100
+++ new/network-control-0.1.3/test/Spec.hs 2001-09-09 03:46:40.000000000
+0200
@@ -0,0 +1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}