Skip to content

Commit d072ad4

Browse files
committed
Simplify
1 parent 31431a8 commit d072ad4

File tree

2 files changed

+35
-59
lines changed

2 files changed

+35
-59
lines changed

src/Ambar/Emulator/Connector/Poll.hs

Lines changed: 32 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ import Control.Monad (foldM)
1818
import Control.Concurrent.STM (TVar, atomically, readTVarIO, modifyTVar)
1919
import Data.Aeson (ToJSON, FromJSON, FromJSONKey, ToJSONKey, toJSON)
2020
import Data.Default (Default(..))
21+
import Data.List (maximumBy)
2122
import qualified Data.Aeson as Aeson
23+
import Data.Ord (comparing)
2224
import Data.Time.Clock.POSIX (POSIXTime, getPOSIXTime)
2325
import Data.Time.Clock (nominalDiffTimeToSeconds, secondsToNominalDiffTime)
2426
import Data.Void (Void)
25-
import Data.Maybe (fromMaybe)
2627
import Data.Map.Strict (Map)
2728
import qualified Data.Map.Strict as Map
2829
import 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-
107100
data Range = Range
108101
{ _r_low :: EntryId
109102
, r_high :: EntryId
@@ -113,30 +106,23 @@ data Range = Range
113106
deriving anyclass (FromJSON, ToJSON)
114107

115108
mark :: 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

154140
boundaries :: 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.
171146
compact :: 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 ]

tests/Test/Connector.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,6 @@ testPollingConnector = describe "Poll" $
7777

7878
it "compact doesn't remove ranges ending higher than time given" $ do
7979
(boundaries . compact 2 . bs) [1 ,2, 5, 3] `shouldBe` Boundaries [(1,3), (5,5)]
80+
81+
it "can compact empty boundaries" $ do
82+
(boundaries . compact 2 . bs) [] `shouldBe` Boundaries []

0 commit comments

Comments
 (0)