/
Types.hs
155 lines (127 loc) · 5.33 KB
/
Types.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
module Ouroboros.Storage.VolatileDB.Types
(
module Ouroboros.Storage.VolatileDB.Types
, module Ouroboros.Network.Block
) where
import Control.Exception (Exception (..))
import Data.Map.Strict (Map)
import Data.Set (Set)
import Data.Typeable
import Data.Word (Word16, Word64)
import GHC.Generics (Generic)
import Cardano.Prelude (NoUnexpectedThunks)
import Ouroboros.Network.Block hiding (Tip, decodeTip, encodeTip)
import Ouroboros.Network.Point (WithOrigin)
import Ouroboros.Consensus.Block (IsEBB)
import Ouroboros.Storage.FS.API.Types
-- | The 'FileId' is the unique identifier of each file found in the db.
-- For example, the file @blocks-42.dat@ has 'FileId' @42@.
type FileId = Int
-- | For each @blockId@, we store the file in which we can find the block,
-- the offset, its size in bytes and its predecessor.
type ReverseIndex blockId = Map blockId (InternalBlockInfo blockId)
-- | For each block, we store the set of all blocks which have this block as
-- a predecessor (set of successors).
type SuccessorsIndex blockId = Map (WithOrigin blockId) (Set blockId)
-- | Errors which might arise when working with this database.
data VolatileDBError =
UserError UserError
-- ^ An error thrown because of incorrect usage of the VolatileDB
-- by the user.
| UnexpectedError UnexpectedError
-- ^ An unexpected error thrown because something went wrong on a lower
-- layer.
deriving Show
data UserError =
InvalidArgumentsError String
| ClosedDBError
deriving (Show, Eq)
data UnexpectedError =
FileSystemError FsError
| ParserError ParserError
deriving (Show)
instance Eq VolatileDBError where
(==) = sameVolatileDBError
instance Exception VolatileDBError where
displayException = show
data ParserError =
forall blockId. (Typeable blockId, Eq blockId, Show blockId) =>
DuplicatedSlot blockId FsPath FsPath
| InvalidFilename FsPath
deriving instance Show ParserError
instance Eq ParserError where
(==) = sameParseError
sameVolatileDBError :: VolatileDBError
-> VolatileDBError
-> Bool
sameVolatileDBError e1 e2 = case (e1, e2) of
(UserError ue1, UserError ue2) -> ue1 == ue2
(UnexpectedError ue1, UnexpectedError ue2) -> sameUnexpectedError ue1 ue2
_ -> False
sameUnexpectedError :: UnexpectedError
-> UnexpectedError
-> Bool
sameUnexpectedError e1 e2 = case (e1, e2) of
(FileSystemError fs1, FileSystemError fs2) -> sameFsError fs1 fs2
(ParserError p1, ParserError p2) -> p1 == p2
_ -> False
-- | This is not comparing the arguments of 'DuplicatedSlot', because it's not
-- deterministic which duplication we find. In other words, it's possible that
-- there are multiple pairs of duplicate blocks and our algorithm does not
-- guarantee we always find the same.
sameParseError :: ParserError -> ParserError -> Bool
sameParseError e1 e2 = case (e1, e2) of
(DuplicatedSlot {}, DuplicatedSlot {}) -> True
(InvalidFilename str1, InvalidFilename str2) -> str1 == str2
_ -> False
newtype FileSize = FileSize {unFileSize :: Word64}
deriving (Show, Generic, NoUnexpectedThunks)
newtype BlockSize = BlockSize {unBlockSize :: Word64}
deriving (Show, Generic, NoUnexpectedThunks)
newtype Parser e m blockId = Parser {
-- | Parse block storage at the given path.
parse :: FsPath -> m (ParsedInfo blockId, Maybe e)
}
-- | The offset of a slot in a file.
type SlotOffset = Word64
-- | Information returned by the parser about a single file.
--
-- The parser returns for each block, its size its blockId, its slot and its
-- predecessor's blockId.
type ParsedInfo blockId = [(SlotOffset, (BlockSize, BlockInfo blockId))]
-- | The information that the user has to provide for each new block.
data BlockInfo blockId = BlockInfo {
bbid :: !blockId
, bslot :: !SlotNo
, bpreBid :: !(WithOrigin blockId)
, bisEBB :: !IsEBB
, bheaderOffset :: !Word16
, bheaderSize :: !Word16
} deriving (Show, Generic, NoUnexpectedThunks)
-- | The internal information the db keeps for each block.
data InternalBlockInfo blockId = InternalBlockInfo {
ibFile :: !FsPath
, ibSlotOffset :: !SlotOffset
, ibBlockSize :: !BlockSize
, ibSlot :: !SlotNo
, ibPreBid :: !(WithOrigin blockId)
, ibIsEBB :: !IsEBB
, ibHeaderOffset :: !Word16
, ibHeaderSize :: !Word16
} deriving (Show, Generic, NoUnexpectedThunks)
{------------------------------------------------------------------------------
Tracing
------------------------------------------------------------------------------}
data TraceEvent e hash
= DBAlreadyClosed
| DBAlreadyOpen
| BlockAlreadyHere hash
| TruncateCurrentFile FsPath
| Truncate e FsPath SlotOffset
deriving (Eq, Generic, Show)