@@ -23,10 +23,9 @@ module Ouroboros.Consensus.Storage.PerasCertDB.Impl
23
23
import Control.Monad (join )
24
24
import Control.Tracer (Tracer , nullTracer , traceWith )
25
25
import Data.Kind (Type )
26
+ import qualified Data.Map.Merge.Strict as Map
26
27
import Data.Map.Strict (Map )
27
28
import qualified Data.Map.Strict as Map
28
- import Data.Set (Set )
29
- import qualified Data.Set as Set
30
29
import GHC.Generics (Generic )
31
30
import NoThunks.Class
32
31
import Ouroboros.Consensus.Block
@@ -58,20 +57,19 @@ openDB ::
58
57
Complete PerasCertDbArgs m blk ->
59
58
m (PerasCertDB m blk )
60
59
openDB args = do
61
- pcdbRoundNos <- newTVarIO Set. empty
62
- pcdbWeightByPoint <- newTVarIO Map. empty
60
+ pcdbVolatileState <- newTVarIO initialPerasVolatileCertState
63
61
let env =
64
62
PerasCertDbEnv
65
63
{ pcdbTracer
66
- , pcdbRoundNos
67
- , pcdbWeightByPoint
64
+ , pcdbVolatileState
68
65
}
69
66
h <- PerasCertDbHandle <$> newTVarIO (PerasCertDbOpen env)
70
67
traceWith pcdbTracer OpenedPerasCertDB
71
68
pure
72
69
PerasCertDB
73
70
{ addCert = getEnv1 h implAddCert
74
71
, getWeightSnapshot = getEnvSTM h implGetWeightSnapshot
72
+ , garbageCollect = getEnv1 h implGarbageCollect
75
73
, closeDB = implCloseDB h
76
74
}
77
75
where
@@ -93,13 +91,8 @@ data PerasCertDbState m blk
93
91
94
92
data PerasCertDbEnv m blk = PerasCertDbEnv
95
93
{ pcdbTracer :: ! (Tracer m (TraceEvent blk ))
96
- , pcdbRoundNos :: ! (StrictTVar m (Set PerasRoundNo ))
94
+ , pcdbVolatileState :: ! (StrictTVar m (PerasVolatileCertState blk ))
97
95
-- ^ The 'RoundNo's of all certificates currently in the db.
98
- , pcdbWeightByPoint :: ! (StrictTVar m (Map (Point blk ) PerasWeight ))
99
- -- ^ The weight of boosted blocks w.r.t. the certificates currently in the
100
- -- db.
101
- --
102
- -- INVARIANT: In sync with 'pcdbRoundNos'.
103
96
}
104
97
deriving NoThunks via OnlyCheckWhnfNamed " PerasCertDbEnv" (PerasCertDbEnv m blk )
105
98
@@ -154,20 +147,25 @@ implAddCert ::
154
147
implAddCert env cert = do
155
148
traceWith pcdbTracer $ AddingPerasCert roundNo boostedPt
156
149
join $ atomically $ do
157
- roundNos <- readTVar pcdbRoundNos
158
- if Set . member roundNo roundNos
150
+ PerasVolatileCertState {pvcsCerts, pvcsWeightByPoint} <- readTVar pcdbVolatileState
151
+ if Map . member roundNo pvcsCerts
159
152
then do
160
153
pure $ traceWith pcdbTracer $ IgnoredCertAlreadyInDB roundNo boostedPt
161
154
else do
162
- writeTVar pcdbRoundNos $ Set. insert roundNo roundNos
163
- -- Note that the same block might be boosted by multiple points.
164
- modifyTVar pcdbWeightByPoint $ Map. insertWith (<>) boostedPt boostPerCert
155
+ writeTVar
156
+ pcdbVolatileState
157
+ PerasVolatileCertState
158
+ { pvcsCerts =
159
+ Map. insert roundNo cert pvcsCerts
160
+ , -- Note that the same block might be boosted by multiple points.
161
+ pvcsWeightByPoint =
162
+ Map. insertWith (<>) boostedPt boostPerCert pvcsWeightByPoint
163
+ }
165
164
pure $ traceWith pcdbTracer $ AddedPerasCert roundNo boostedPt
166
165
where
167
166
PerasCertDbEnv
168
167
{ pcdbTracer
169
- , pcdbRoundNos
170
- , pcdbWeightByPoint
168
+ , pcdbVolatileState
171
169
} = env
172
170
173
171
roundNo = perasCertRound cert
@@ -176,8 +174,72 @@ implAddCert env cert = do
176
174
implGetWeightSnapshot ::
177
175
IOLike m =>
178
176
PerasCertDbEnv m blk -> STM m (PerasWeightSnapshot blk )
179
- implGetWeightSnapshot PerasCertDbEnv {pcdbWeightByPoint} =
180
- PerasWeightSnapshot <$> readTVar pcdbWeightByPoint
177
+ implGetWeightSnapshot PerasCertDbEnv {pcdbVolatileState} =
178
+ PerasWeightSnapshot . pvcsWeightByPoint <$> readTVar pcdbVolatileState
179
+
180
+ implGarbageCollect ::
181
+ forall m blk .
182
+ (IOLike m , StandardHash blk ) =>
183
+ PerasCertDbEnv m blk -> SlotNo -> m ()
184
+ implGarbageCollect PerasCertDbEnv {pcdbVolatileState} slot =
185
+ atomically $ modifyTVar pcdbVolatileState gc
186
+ where
187
+ gc :: PerasVolatileCertState blk -> PerasVolatileCertState blk
188
+ gc PerasVolatileCertState {pvcsCerts, pvcsWeightByPoint} =
189
+ PerasVolatileCertState
190
+ { pvcsCerts = certsToKeep
191
+ , pvcsWeightByPoint =
192
+ Map. merge
193
+ -- Do not touch weight of boosted blocks that we do not subtract any
194
+ -- weight from.
195
+ Map. preserveMissing
196
+ -- Irrelevant, the key set of @weightToRemove@ is a subset of the
197
+ -- key set of @pvcsWeightByPoint@.
198
+ Map. dropMissing
199
+ (Map. zipWithMaybeMatched $ \ _pt -> subtractWeight)
200
+ pvcsWeightByPoint
201
+ weightToRemove
202
+ }
203
+ where
204
+ (certsToRemove, certsToKeep) =
205
+ Map. partition isTooOld pvcsCerts
206
+ isTooOld cert =
207
+ pointSlot (perasCertBoostedBlock cert) < NotOrigin slot
208
+ weightToRemove =
209
+ Map. fromListWith
210
+ (<>)
211
+ [ (perasCertBoostedBlock cert, boostPerCert)
212
+ | cert <- Map. elems certsToRemove
213
+ ]
214
+
215
+ subtractWeight :: PerasWeight -> PerasWeight -> Maybe PerasWeight
216
+ subtractWeight (PerasWeight w1) (PerasWeight w2)
217
+ | w1 > w2 = Just $ PerasWeight (w1 - w2)
218
+ | otherwise = Nothing
219
+
220
+ {- ------------------------------------------------------------------------------
221
+ Implementation-internal types
222
+ -------------------------------------------------------------------------------}
223
+
224
+ -- | Volatile Peras certificate state, i.e. certificates that could influence
225
+ -- chain selection by boosting a volatile block.
226
+ data PerasVolatileCertState blk = PerasVolatileCertState
227
+ { pvcsCerts :: ! (Map PerasRoundNo (PerasCert blk ))
228
+ -- ^ The boosted blocks by 'RoundNo' of all certificates currently in the db.
229
+ , pvcsWeightByPoint :: ! (Map (Point blk ) PerasWeight )
230
+ -- ^ The weight of boosted blocks w.r.t. the certificates currently in the db.
231
+ --
232
+ -- INVARIANT: In sync with 'pvcsCerts'.
233
+ }
234
+ deriving stock (Show , Generic )
235
+ deriving anyclass NoThunks
236
+
237
+ initialPerasVolatileCertState :: PerasVolatileCertState blk
238
+ initialPerasVolatileCertState =
239
+ PerasVolatileCertState
240
+ { pvcsCerts = Map. empty
241
+ , pvcsWeightByPoint = Map. empty
242
+ }
181
243
182
244
{- ------------------------------------------------------------------------------
183
245
Trace types
0 commit comments