2020-01-23 07:16:09 +03:00
|
|
|
{-|
|
2020-05-28 21:21:43 +03:00
|
|
|
High-Level Serf Interface
|
2019-07-17 02:14:46 +03:00
|
|
|
-}
|
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
module Urbit.Vere.Serf
|
2020-06-02 00:31:24 +03:00
|
|
|
( withSerf
|
2020-05-27 02:01:03 +03:00
|
|
|
, execReplay
|
2020-06-02 00:31:24 +03:00
|
|
|
, collectFX
|
|
|
|
, module X
|
2020-05-27 02:01:03 +03:00
|
|
|
)
|
|
|
|
where
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Prelude
|
2019-06-01 01:55:21 +03:00
|
|
|
|
2019-07-24 04:34:16 +03:00
|
|
|
import Data.Conduit
|
2020-01-24 08:28:38 +03:00
|
|
|
import Urbit.Vere.Pier.Types
|
2020-05-27 02:01:03 +03:00
|
|
|
import Urbit.Vere.Serf.IPC
|
2020-05-28 21:21:43 +03:00
|
|
|
|
2020-06-05 00:10:33 +03:00
|
|
|
import Control.Monad.Trans.Resource (runResourceT)
|
|
|
|
import Urbit.Arvo (FX)
|
2020-06-11 02:41:09 +03:00
|
|
|
import Urbit.King.App.Class (HasStderrLogFunc(..))
|
2020-05-28 21:21:43 +03:00
|
|
|
|
2020-01-24 05:57:22 +03:00
|
|
|
import qualified Data.Conduit.Combinators as CC
|
2020-06-07 03:26:59 +03:00
|
|
|
import qualified System.ProgressBar as PB
|
2020-06-09 00:27:58 +03:00
|
|
|
import qualified Urbit.EventLog.LMDB as Log
|
2020-06-02 00:31:24 +03:00
|
|
|
|
2020-06-10 23:53:55 +03:00
|
|
|
import qualified Urbit.Vere.Serf.IPC as X (Config (..), EvErr (..), Flag (..),
|
|
|
|
RunReq (..), Serf, WorkError (..),
|
|
|
|
run, sendSIGINT, snapshot, start,
|
|
|
|
stop)
|
2020-06-02 00:31:24 +03:00
|
|
|
|
2019-07-19 03:52:53 +03:00
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
2020-06-02 00:31:24 +03:00
|
|
|
parseLogRow :: MonadIO m => ByteString -> m (Mug, Noun)
|
|
|
|
parseLogRow = cueBSExn >=> fromNounExn
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2020-05-28 01:57:34 +03:00
|
|
|
withSerf :: HasLogFunc e => Config -> RAcquire e Serf
|
2020-05-29 05:14:25 +03:00
|
|
|
withSerf config = mkRAcquire startup kill
|
2020-05-27 02:01:03 +03:00
|
|
|
where
|
2020-05-29 05:14:25 +03:00
|
|
|
startup = do
|
|
|
|
(serf, st) <- io $ start config
|
2020-06-11 05:02:09 +03:00
|
|
|
logDebug (displayShow ("serf state", st))
|
2020-05-29 05:14:25 +03:00
|
|
|
pure serf
|
2020-05-28 01:57:34 +03:00
|
|
|
kill serf = do
|
2020-06-01 20:51:37 +03:00
|
|
|
void $ rio $ stop serf
|
2020-05-27 02:01:03 +03:00
|
|
|
|
|
|
|
execReplay
|
|
|
|
:: forall e
|
2020-06-07 03:26:59 +03:00
|
|
|
. (HasLogFunc e, HasStderrLogFunc e)
|
2020-05-27 02:01:03 +03:00
|
|
|
=> Serf
|
|
|
|
-> Log.EventLog
|
|
|
|
-> Maybe Word64
|
2020-06-08 20:45:41 +03:00
|
|
|
-> RIO e (Either PlayBail Word)
|
2020-05-27 02:01:03 +03:00
|
|
|
execReplay serf log last = do
|
2020-05-28 01:57:34 +03:00
|
|
|
lastEventInSnap <- io (serfLastEventBlocking serf)
|
2020-05-27 02:01:03 +03:00
|
|
|
if lastEventInSnap == 0 then doBoot else doReplay
|
|
|
|
where
|
2020-06-08 20:45:41 +03:00
|
|
|
doBoot :: RIO e (Either PlayBail Word)
|
2020-05-27 02:01:03 +03:00
|
|
|
doBoot = do
|
2020-06-11 05:02:09 +03:00
|
|
|
logDebug "Beginning boot sequence"
|
2020-05-28 01:57:34 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
let bootSeqLen = lifecycleLen (Log.identity log)
|
|
|
|
|
|
|
|
evs <- runConduit $ Log.streamEvents log 1
|
|
|
|
.| CC.take (fromIntegral bootSeqLen)
|
2020-06-02 00:31:24 +03:00
|
|
|
.| CC.mapM (fmap snd . parseLogRow)
|
2020-05-27 02:01:03 +03:00
|
|
|
.| CC.sinkList
|
|
|
|
|
|
|
|
let numEvs = fromIntegral (length evs)
|
|
|
|
|
2020-05-28 01:57:34 +03:00
|
|
|
when (numEvs /= bootSeqLen) $ do
|
|
|
|
throwIO (MissingBootEventsInEventLog numEvs bootSeqLen)
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2020-06-11 05:02:09 +03:00
|
|
|
logDebug $ display ("Sending " <> tshow numEvs <> " boot events to serf")
|
2020-06-08 02:35:54 +03:00
|
|
|
|
2020-06-01 20:51:37 +03:00
|
|
|
io (boot serf evs) >>= \case
|
2020-06-08 02:35:54 +03:00
|
|
|
Just err -> do
|
2020-06-11 05:02:09 +03:00
|
|
|
logDebug "Error on replay, exiting"
|
2020-06-08 20:45:41 +03:00
|
|
|
pure (Left err)
|
2020-06-08 02:35:54 +03:00
|
|
|
Nothing -> do
|
2020-06-11 05:02:09 +03:00
|
|
|
logDebug "Finished boot events, moving on to more events from log."
|
2020-06-08 20:45:41 +03:00
|
|
|
doReplay <&> \case
|
|
|
|
Left err -> Left err
|
|
|
|
Right num -> Right (num + numEvs)
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2020-06-08 20:45:41 +03:00
|
|
|
doReplay :: RIO e (Either PlayBail Word)
|
2020-05-27 02:01:03 +03:00
|
|
|
doReplay = do
|
2020-02-06 02:20:32 +03:00
|
|
|
logTrace "Beginning event log replay"
|
|
|
|
|
2020-05-28 01:57:34 +03:00
|
|
|
lastEventInSnap <- io (serfLastEventBlocking serf)
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2020-02-06 02:20:32 +03:00
|
|
|
last & \case
|
|
|
|
Nothing -> pure ()
|
|
|
|
Just lt -> logTrace $ display $
|
|
|
|
"User requested to replay up to event #" <> tshow lt
|
|
|
|
|
2020-06-03 02:03:04 +03:00
|
|
|
logLastEv :: Word64 <- atomically $ fromIntegral <$> Log.lastEv log
|
2020-02-06 02:20:32 +03:00
|
|
|
|
|
|
|
logTrace $ display $ "Last event in event log is #" <> tshow logLastEv
|
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
let replayUpTo = min (fromMaybe logLastEv last) logLastEv
|
2020-02-06 02:20:32 +03:00
|
|
|
|
|
|
|
let numEvs :: Int = fromIntegral replayUpTo - fromIntegral lastEventInSnap
|
2020-01-11 01:07:29 +03:00
|
|
|
|
2020-05-27 02:01:03 +03:00
|
|
|
when (numEvs < 0) $ do
|
2020-06-08 02:35:54 +03:00
|
|
|
throwIO (SnapshotAheadOfLog logLastEv lastEventInSnap)
|
2020-05-27 02:01:03 +03:00
|
|
|
|
2020-06-07 03:26:59 +03:00
|
|
|
incProgress <- logStderr (trackProgress (fromIntegral numEvs))
|
|
|
|
|
2020-02-06 02:20:32 +03:00
|
|
|
logTrace $ display $ "Replaying up to event #" <> tshow replayUpTo
|
|
|
|
logTrace $ display $ "Will replay " <> tshow numEvs <> " in total."
|
2020-01-11 01:07:29 +03:00
|
|
|
|
2020-06-07 00:33:15 +03:00
|
|
|
env <- ask
|
|
|
|
|
2020-06-07 03:26:59 +03:00
|
|
|
res <- runResourceT
|
2020-06-05 00:10:33 +03:00
|
|
|
$ runConduit
|
|
|
|
$ Log.streamEvents log (lastEventInSnap + 1)
|
|
|
|
.| CC.take (fromIntegral numEvs)
|
|
|
|
.| CC.mapM (fmap snd . parseLogRow)
|
2020-06-07 03:26:59 +03:00
|
|
|
.| replay 5 incProgress serf
|
|
|
|
|
2020-06-08 20:45:41 +03:00
|
|
|
res & \case
|
|
|
|
Nothing -> pure (Right $ fromIntegral numEvs)
|
|
|
|
Just er -> pure (Left er)
|
2020-06-07 03:26:59 +03:00
|
|
|
|
|
|
|
logStderr :: HasStderrLogFunc e => RIO LogFunc a -> RIO e a
|
|
|
|
logStderr action = do
|
|
|
|
logFunc <- view stderrLogFuncL
|
|
|
|
runRIO logFunc action
|
|
|
|
|
|
|
|
trackProgress
|
|
|
|
:: HasLogFunc e
|
|
|
|
=> Word64
|
|
|
|
-> RIO e (Int -> IO ())
|
|
|
|
trackProgress = \case
|
|
|
|
0 -> pure $ const $ pure ()
|
|
|
|
num -> do
|
|
|
|
let style = PB.defStyle { PB.stylePostfix = PB.exact }
|
|
|
|
let refresh = 10
|
|
|
|
let init = PB.Progress 0 (fromIntegral num) ()
|
|
|
|
bar <- PB.newProgressBar style refresh init
|
|
|
|
env <- ask
|
|
|
|
let incr = PB.incProgress bar
|
|
|
|
pure (runRIO env . incr)
|
2020-06-02 00:31:24 +03:00
|
|
|
|
|
|
|
|
|
|
|
-- Collect FX ------------------------------------------------------------------
|
|
|
|
|
|
|
|
collectFX :: HasLogFunc e => Serf -> Log.EventLog -> RIO e ()
|
|
|
|
collectFX serf log = do
|
|
|
|
lastEv <- io (serfLastEventBlocking serf)
|
2020-06-05 00:10:33 +03:00
|
|
|
runResourceT
|
|
|
|
$ runConduit
|
2020-06-02 00:31:24 +03:00
|
|
|
$ Log.streamEvents log (lastEv + 1)
|
|
|
|
.| CC.mapM (parseLogRow >=> fromNounExn . snd)
|
|
|
|
.| swim serf
|
2020-06-05 00:10:33 +03:00
|
|
|
.| persistFX log
|
|
|
|
|
|
|
|
persistFX :: MonadIO m => Log.EventLog -> ConduitT (EventId, FX) Void m ()
|
|
|
|
persistFX log = CC.mapM_ $ \(eId, fx) -> do
|
|
|
|
Log.writeEffectsRow log eId $ jamBS $ toNoun fx
|