@@ -18,11 +18,12 @@ import Control.Monad (foldM)
1818import Control.Concurrent.STM (TVar , atomically , readTVarIO , modifyTVar )
1919import Data.Aeson (ToJSON , FromJSON , FromJSONKey , ToJSONKey , toJSON )
2020import Data.Default (Default (.. ))
21+ import Data.List (maximumBy )
2122import qualified Data.Aeson as Aeson
23+ import Data.Ord (comparing )
2224import Data.Time.Clock.POSIX (POSIXTime , getPOSIXTime )
2325import Data.Time.Clock (nominalDiffTimeToSeconds , secondsToNominalDiffTime )
2426import Data.Void (Void )
25- import Data.Maybe (fromMaybe )
2627import Data.Map.Strict (Map )
2728import qualified Data.Map.Strict as Map
2829import GHC.Generics (Generic )
@@ -91,19 +92,11 @@ connect trackerVar (PollingConnector getId poll (PollingInterval interval) maxTr
9192 loop
9293
9394-- | Boundary tracker for enumerable ids. Takes advantage of ranges.
94- data BoundaryTracker
95- = EmptyTracker
96- | BoundaryTracker
97- { b_lowest :: EntryId -- ^ the lowest entry we ever saw
98- , b_baseline :: Maybe EntryId -- ^ we only care about ids higher than this
99- , b_ranges :: Map EntryId Range -- ^ Map by range's low Id
100- }
95+ newtype BoundaryTracker = BoundaryTracker (Map EntryId Range ) -- ^ Map by range's low Id
10196 deriving (Generic , Show )
97+ deriving newtype (Default )
10298 deriving anyclass (FromJSON , ToJSON )
10399
104- instance Default BoundaryTracker where
105- def = EmptyTracker
106-
107100data Range = Range
108101 { _r_low :: EntryId
109102 , r_high :: EntryId
@@ -113,30 +106,23 @@ data Range = Range
113106 deriving anyclass (FromJSON , ToJSON )
114107
115108mark :: POSIXTime -> EntryId -> BoundaryTracker -> BoundaryTracker
116- mark time el EmptyTracker =
117- BoundaryTracker el Nothing (Map. singleton el (Range el el time))
118- mark time el (BoundaryTracker lowest baseline m) =
119- if el < fromMaybe el baseline
120- then BoundaryTracker (min lowest el) baseline m
121- else BoundaryTracker (min lowest el) baseline rangeMap
109+ mark time el (BoundaryTracker m) = BoundaryTracker $
110+ case Map. lookupLE el m of
111+ Nothing -> checkAbove
112+ Just (_, Range low high _)
113+ -- already in range
114+ | el <= high -> m
115+ | el == succ high ->
116+ case Map. lookup (succ el) m of
117+ Just (Range _ h t) ->
118+ -- join ranges
119+ Map. insert low (Range low h t) $
120+ Map. delete (succ el) m
121+ Nothing ->
122+ -- extend range upwards
123+ Map. insert low (Range low el time) m
124+ | otherwise -> checkAbove
122125 where
123- rangeMap =
124- case Map. lookupLE el m of
125- Nothing -> checkAbove
126- Just (_, Range low high _)
127- -- already in range
128- | el <= high -> m
129- | el == succ high ->
130- case Map. lookup (succ el) m of
131- Just (Range _ h t) ->
132- -- join ranges
133- Map. insert low (Range low h t) $
134- Map. delete (succ el) m
135- Nothing ->
136- -- extend range upwards
137- Map. insert low (Range low el time) m
138- | otherwise -> checkAbove
139-
140126 checkAbove =
141127 case Map. lookupGT el m of
142128 Nothing ->
@@ -152,36 +138,23 @@ mark time el (BoundaryTracker lowest baseline m) =
152138 Map. insert el (Range el el time) m
153139
154140boundaries :: BoundaryTracker -> Boundaries
155- boundaries EmptyTracker = Boundaries []
156- boundaries (BoundaryTracker lowest baseline m) = Boundaries $
157- case [(l, h) | Range l h _ <- Map. elems m] of
158- [] ->
159- case baseline of
160- Nothing -> [(lowest, lowest)]
161- Just b -> [(lowest, b)]
162- (low, high) : xs ->
163- case baseline of
164- Nothing -> (lowest, high) : xs
165- Just b
166- | low <= succ b -> (lowest, high) : xs
167- | otherwise -> (lowest, b) : (low, high) : xs
141+ boundaries (BoundaryTracker m) =
142+ Boundaries [(l, h) | Range l h _ <- Map. elems m]
168143
169144-- | To avoid having our list of ranges grow indefinitely, we will
170145-- clean it up by ignoring all range gaps below some safe time boundary.
171146compact :: POSIXTime -> BoundaryTracker -> BoundaryTracker
172- compact _ EmptyTracker = EmptyTracker
173- compact bound (BoundaryTracker lowest baseline m) =
174- BoundaryTracker lowest newBaseline (Map. fromList over)
147+ compact bound (BoundaryTracker m) =
148+ if Map. null m
149+ then BoundaryTracker m
150+ else BoundaryTracker $ Map. fromList $ base : over
175151 where
176152 -- split between ranges where the high's value was collected under or over the time boundary.
177153 (under, over) = span (\ (_, range) -> r_highTime range <= bound) $ Map. toList m
178154
179- newBaseline =
180- if null under
181- then baseline
182- else
183- let maxUnder = maximum $ fmap (r_high . snd ) under in
184- case baseline of
185- Nothing -> Just maxUnder
186- Just b -> Just $ max b maxUnder
187-
155+ base = (lowest, Range lowest baseline basetime)
156+ lowest = minimum $ [low | Range low _ _ <- Map. elems m]
157+ (baseline, basetime) =
158+ case under of
159+ [] -> (lowest, bound)
160+ xs -> maximumBy (comparing fst ) [ (high, htime) | (_, Range _ high htime) <- xs ]
0 commit comments