Skip to content

Commit b7f2f56

Browse files
authored
Merge pull request #529 from IntersectMBO/jdral/display-exception
Display action registry exceptions in human-readable format
2 parents a10f188 + d18f9e1 commit b7f2f56

File tree

4 files changed

+125
-19
lines changed

4 files changed

+125
-19
lines changed

src-control/Control/ActionRegistry.hs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ module Control.ActionRegistry (
2121
, withActionRegistry
2222
, unsafeNewActionRegistry
2323
, unsafeFinaliseActionRegistry
24-
, CommitActionRegistryError
25-
, AbortActionRegistryError
24+
, CommitActionRegistryError (..)
25+
, AbortActionRegistryError (..)
2626
, AbortActionRegistryReason
2727
-- * Registering actions #registeringActions#
2828
-- $registering-actions
@@ -61,6 +61,23 @@ import GHC.Stack
6161
#define HasCallStackIfDebug ()
6262
#endif
6363

64+
{-------------------------------------------------------------------------------
65+
Printing utilities
66+
-------------------------------------------------------------------------------}
67+
68+
tabLines1 :: String -> String
69+
tabLines1 = tabLinesN 1
70+
71+
#ifdef NO_IGNORE_ASSERTS
72+
tabLines2 :: String -> String
73+
tabLines2 = tabLinesN 2
74+
#endif
75+
76+
tabLinesN :: Int -> String -> String
77+
tabLinesN n = unlines . fmap (ts++) . lines
78+
where
79+
ts = concat $ replicate n " "
80+
6481
{-------------------------------------------------------------------------------
6582
Modify mutable state
6683
-------------------------------------------------------------------------------}
@@ -216,7 +233,15 @@ data Action m = Action {
216233

217234
data ActionError = ActionError SomeException CallStack
218235
deriving stock Show
219-
deriving anyclass Exception
236+
237+
instance Exception ActionError where
238+
displayException (ActionError err registerSite) = unlines [
239+
"A registered action threw an error: "
240+
, tabLines1 "The error:"
241+
, tabLines2 (displayException err)
242+
, tabLines1 "Registration site:"
243+
, tabLines2 (prettyCallStack registerSite)
244+
]
220245

221246
mkAction a = Action a callStack
222247

@@ -305,7 +330,13 @@ unsafeCommitActionRegistry reg = do
305330

306331
data CommitActionRegistryError = CommitActionRegistryError (NonEmpty ActionError)
307332
deriving stock Show
308-
deriving anyclass Exception
333+
334+
instance Exception CommitActionRegistryError where
335+
displayException (CommitActionRegistryError es) = unlines $ [
336+
"Exceptions thrown while committing an action registry."
337+
] <> NE.toList (fmap displayOne es)
338+
where
339+
displayOne e = tabLines1 (displayException e)
309340

310341
{-# SPECIALISE unsafeAbortActionRegistry ::
311342
ActionRegistry IO
@@ -338,7 +369,14 @@ data AbortActionRegistryReason =
338369
data AbortActionRegistryError =
339370
AbortActionRegistryError AbortActionRegistryReason (NonEmpty ActionError)
340371
deriving stock Show
341-
deriving anyclass Exception
372+
373+
instance Exception AbortActionRegistryError where
374+
displayException (AbortActionRegistryError reason es) = unlines $ [
375+
"Exceptions thrown while aborting an action registry."
376+
, ("Reason for aborting the registry: " ++ show reason)
377+
] <> NE.toList (fmap displayOne es)
378+
where
379+
displayOne e = tabLines1 (displayException e)
342380

343381
{-# SPECIALISE runActions :: [Action IO] -> IO [ActionError] #-}
344382
-- | Run all actions even if previous actions threw exceptions.

test-control/Test/Control/ActionRegistry.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ prop_commitActionRegistryError = once $ ioProperty $ do
2121
delayedCommit reg
2222
(throwIO (userError "delayed action failed"))
2323
pure $ case eith of
24-
Left e -> tabulate "Printed error" [show e] $ property True
24+
Left e ->
25+
tabulate "displayException" [displayExceptionNewline e] $ property True
2526
Right () -> property False
2627

2728
-- | An example where an exception happens while an action registry is being
@@ -36,5 +37,9 @@ prop_abortActionRegistryError = once $ ioProperty $ do
3637
(\_ -> throwIO (userError "rollback action failed"))
3738
throwIO (userError "error in withActionRegistry scope")
3839
pure $ case eith of
39-
Left e -> tabulate "Printed error" [show e] $ property True
40+
Left e ->
41+
tabulate "displayException" [displayExceptionNewline e] $ property True
4042
Right () -> property False
43+
44+
displayExceptionNewline :: Exception e => e -> String
45+
displayExceptionNewline e = '\n':displayException e

test/Database/LSMTree/Model/Session.hs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import Database.LSMTree.Model.Table (LookupResult (..),
9898
QueryResult (..), Range (..), ResolveSerialisedValue (..),
9999
Update (..), getResolve, noResolve)
100100
import qualified Database.LSMTree.Model.Table as Model
101+
import GHC.Show (appPrec)
101102

102103
{-------------------------------------------------------------------------------
103104
Model
@@ -232,7 +233,7 @@ runModelMWithInjectedErrors ::
232233
runModelMWithInjectedErrors Nothing onNoErrors _ st =
233234
runModelM onNoErrors st
234235
runModelMWithInjectedErrors (Just _) _ onErrors st =
235-
runModelM (onErrors >> throwError ErrFsError) st
236+
runModelM (onErrors >> throwError (ErrFsError "modelled FsError")) st
236237

237238
--
238239
-- Errors
@@ -245,11 +246,47 @@ data Err =
245246
| ErrSnapshotWrongType
246247
| ErrBlobRefInvalidated
247248
| ErrCursorClosed
248-
-- | Passed zero tables to 'unions'
249-
| ErrUnionsZeroTables
250249
-- | Some file system error occurred
251-
| ErrFsError
252-
deriving stock (Show, Eq)
250+
| ErrFsError String
251+
252+
instance Show Err where
253+
showsPrec d = \case
254+
ErrTableClosed ->
255+
showString "ErrTableClosed"
256+
ErrSnapshotExists ->
257+
showString "ErrSnapshotExists"
258+
ErrSnapshotDoesNotExist ->
259+
showString "ErrSnapshotDoesNotExist"
260+
ErrSnapshotWrongType ->
261+
showString "ErrSnapshotWrongType"
262+
ErrBlobRefInvalidated ->
263+
showString "ErrBlobRefInvalidated"
264+
ErrCursorClosed ->
265+
showString "ErrCursorCosed"
266+
ErrFsError s ->
267+
showParen (d > appPrec) $
268+
showString "ErrFsError " .
269+
showParen True (showString s)
270+
271+
instance Eq Err where
272+
(==) ErrTableClosed ErrTableClosed = True
273+
(==) ErrSnapshotExists ErrSnapshotExists = True
274+
(==) ErrSnapshotDoesNotExist ErrSnapshotDoesNotExist = True
275+
(==) ErrSnapshotWrongType ErrSnapshotWrongType = True
276+
(==) ErrBlobRefInvalidated ErrBlobRefInvalidated = True
277+
(==) ErrCursorClosed ErrCursorClosed = True
278+
(==) (ErrFsError _) (ErrFsError _) = True
279+
(==) _ _ = False
280+
where
281+
_coveredAllCases x = case x of
282+
ErrTableClosed{} -> ()
283+
ErrSnapshotExists{} -> ()
284+
ErrSnapshotDoesNotExist{} -> ()
285+
ErrSnapshotWrongType{} -> ()
286+
ErrBlobRefInvalidated{} -> ()
287+
ErrCursorClosed{} -> ()
288+
ErrFsError{} -> ()
289+
253290

254291
{-------------------------------------------------------------------------------
255292
Tables

test/Test/Database/LSMTree/StateMachine.hs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
{-# LANGUAGE InstanceSigs #-}
1010
{-# LANGUAGE LambdaCase #-}
1111
{-# LANGUAGE MultiParamTypeClasses #-}
12+
{-# LANGUAGE MultiWayIf #-}
1213
{-# LANGUAGE NamedFieldPuns #-}
1314
{-# LANGUAGE OverloadedStrings #-}
1415
{-# LANGUAGE QuantifiedConstraints #-}
@@ -64,11 +65,14 @@ module Test.Database.LSMTree.StateMachine (
6465
, Action (..)
6566
) where
6667

68+
import Control.ActionRegistry (AbortActionRegistryError (..),
69+
CommitActionRegistryError (..))
6770
import Control.Concurrent.Class.MonadMVar.Strict
6871
import Control.Concurrent.Class.MonadSTM.Strict
6972
import Control.Monad (forM_, void, (<=<))
70-
import Control.Monad.Class.MonadThrow (Handler (..), MonadCatch (..),
71-
MonadThrow (..), catches)
73+
import Control.Monad.Class.MonadThrow (Exception (..), Handler (..),
74+
MonadCatch (..), MonadThrow (..), catches,
75+
displayException)
7276
import Control.Monad.IOSim
7377
import Control.Monad.Primitive
7478
import Control.Monad.Reader (ReaderT (..))
@@ -160,7 +164,7 @@ tests = testGroup "Test.Database.LSMTree.StateMachine" [
160164
Handler f -> do
161165
throwIO (dummyFsError s) `catch` \e -> do
162166
e' <- f e
163-
pure (e' QC.=== Just Model.ErrFsError)
167+
pure (e' QC.=== Just (Model.ErrFsError ("dummy: " ++ s)))
164168
]
165169

166170
labelledExamples :: IO ()
@@ -284,7 +288,11 @@ propLockstep_RealImpl_RealFS_IO tr =
284288
env :: RealEnv R.Table IO
285289
env = RealEnv {
286290
envSession = session
287-
, envHandlers = [realHandler @IO, fsErrorHandler]
291+
, envHandlers = [
292+
realHandler @IO
293+
, fsErrorHandler
294+
, actionRegistryErrorHandler
295+
]
288296
, envErrors = errsVar
289297
, envInjectFaultResults = faultsVar
290298
}
@@ -321,7 +329,11 @@ propLockstep_RealImpl_MockFS_IO tr =
321329
env :: RealEnv R.Table IO
322330
env = RealEnv {
323331
envSession = session
324-
, envHandlers = [realHandler @IO, fsErrorHandler]
332+
, envHandlers = [
333+
realHandler @IO
334+
, fsErrorHandler
335+
, actionRegistryErrorHandler
336+
]
325337
, envErrors = errsVar
326338
, envInjectFaultResults = faultsVar
327339
}
@@ -346,7 +358,11 @@ propLockstep_RealImpl_MockFS_IOSim tr actions =
346358
env :: RealEnv R.Table (IOSim s)
347359
env = RealEnv {
348360
envSession = session
349-
, envHandlers = [realHandler @(IOSim s), fsErrorHandler]
361+
, envHandlers = [
362+
realHandler @(IOSim s)
363+
, fsErrorHandler
364+
, actionRegistryErrorHandler
365+
]
350366
, envErrors = errsVar
351367
, envInjectFaultResults = faultsVar
352368
}
@@ -423,7 +439,17 @@ fsErrorHandler :: Monad m => Handler m (Maybe Model.Err)
423439
fsErrorHandler = Handler $ pure . handler'
424440
where
425441
handler' :: FsError -> Maybe Model.Err
426-
handler' _ = Just Model.ErrFsError
442+
handler' e = Just (Model.ErrFsError (displayException e))
443+
444+
actionRegistryErrorHandler :: Monad m => Handler m (Maybe Model.Err)
445+
actionRegistryErrorHandler = Handler $ \e -> pure $
446+
if
447+
| Just AbortActionRegistryError{} <- fromException e
448+
-> Just (Model.ErrFsError (displayException e))
449+
| Just CommitActionRegistryError{} <- fromException e
450+
-> Just (Model.ErrFsError (displayException e))
451+
| otherwise
452+
-> Nothing
427453

428454
createSystemTempDirectory :: [Char] -> IO (FilePath, HasFS IO HandleIO, HasBlockIO IO HandleIO)
429455
createSystemTempDirectory prefix = do

0 commit comments

Comments
 (0)