src/DurableError.bend
mylsm-lsm-store@0.5.0.0 · 123 lines · 0 definitions
1import Base
2import mylsm-lsm-store@0.5.0.0/src/Manifest.bend as Manifest
3
4# Lists the structured durable error categories.
5type ErrorKind is Data:
6 NotFound{}
7 AlreadyExists{}
8 Busy{}
9 InvalidArgument{}
10 UnsupportedFormat{}
11 Corruption{}
12 ResourceLimit{}
13 Io{}
14 CommitUnknown{}
15
16# Carries operation, path, and host details with its category.
17type Error is Data:
18 Error{kind: ErrorKind, operation: String, path: String, host_code: U32, host_message: String}
19
20# Records the failure that ended a database open.
21type OpenCause is Data:
22 MissingPath{}
23 ExistingPath{}
24 Locked{}
25 InvalidInput{}
26 UnknownFormat{}
27 CorruptData{}
28 LimitReached{}
29 OpenHostFailure{code: U32, message: String}
30
31# Identifies whether a write failed before or after append.
32type WritePhase is Data:
33 BeforeAppend{}
34 AppendStarted{}
35
36# Records the codec or host failure behind a write result.
37type WriteCause is Data:
38 ValidationFailure{}
39 WriteLimitReached{}
40 WriteHostFailure{code: U32, message: String}
41
42# Builds an error with its structured host and operation details.
43def error(kind: ErrorKind, operation: String, path: String, code: U32, message: String) -> Error:
44 Error{kind, operation, path, code, message}
45
46# Maps open causes to their public error categories.
47def classify_open(cause: OpenCause, operation: String, path: String) -> Error:
48 match cause:
49 case MissingPath{}:
50 error(NotFound{}, operation, path, 0, "")
51 case ExistingPath{}:
52 error(AlreadyExists{}, operation, path, 0, "")
53 case Locked{}:
54 error(Busy{}, operation, path, 0, "")
55 case InvalidInput{}:
56 error(InvalidArgument{}, operation, path, 0, "")
57 case UnknownFormat{}:
58 error(UnsupportedFormat{}, operation, path, 0, "")
59 case CorruptData{}:
60 error(Corruption{}, operation, path, 0, "")
61 case LimitReached{}:
62 error(ResourceLimit{}, operation, path, 0, "")
63 case OpenHostFailure{code, message}:
64 error(Io{}, operation, path, code, message)
65
66def classify_recovery.limit(+code: U32, +message: String, +operation: String, +path: String) -> Error:
67 Bool.pick(Error, U32.is_eq(code, Manifest.parse_limit_error_code()),
68 error(ResourceLimit{}, operation, path, 0, "manifest size limit exceeded"),
69 classify_open(OpenHostFailure{code, message}, operation, path))
70
71def classify_recovery.corruption(+code: U32, +message: String, +operation: String, +path: String) -> Error:
72 Bool.pick(Error, U32.is_eq(code, Manifest.malformed_error_code()),
73 error(Corruption{}, operation, path, 0, "malformed manifest"),
74 classify_recovery.limit(code, message, operation, path))
75
76def classify_recovery.sst(+code: U32, +message: String, +operation: String, +path: String) -> Error:
77 Bool.pick(Error, U32.is_eq(code, 4294967292),
78 error(Corruption{}, operation, path, 0, "malformed SST"),
79 classify_recovery.corruption(code, message, operation, path))
80
81def classify_recovery.levels(+code: U32, +message: String, +operation: String, +path: String) -> Error:
82 Bool.pick(Error, U32.is_eq(code, 5),
83 error(Corruption{}, operation, path, 0, "invalid manifest names"),
84 classify_recovery.sst(code, message, operation, path))
85
86def classify_recovery.wal(+code: U32, +message: String, +operation: String, +path: String) -> Error:
87 Bool.pick(Error, U32.is_eq(code, 4294967290),
88 error(Corruption{}, operation, path, 0, "malformed WAL"),
89 classify_recovery.levels(code, message, operation, path))
90
91# Maps recovery failures to typed public errors.
92def classify_recovery(+code: U32, +message: String, +operation: String, +path: String) -> Error:
93 Bool.pick(Error, U32.is_eq(code, Manifest.unsupported_version_error_code()),
94 error(UnsupportedFormat{}, operation, path, 0, "unsupported manifest version"),
95 classify_recovery.wal(code, message, operation, path))
96
97# Classifies failures that occur before WAL append begins.
98def classify_write_before(cause: WriteCause, operation: String, path: String) -> Error:
99 match cause:
100 case ValidationFailure{}:
101 error(InvalidArgument{}, operation, path, 0, "")
102 case WriteLimitReached{}:
103 error(ResourceLimit{}, operation, path, 0, "")
104 case WriteHostFailure{code, message}:
105 error(Io{}, operation, path, code, message)
106
107# Classifies failures after append begins as CommitUnknown.
108def classify_write_after(cause: WriteCause, operation: String, path: String) -> Error:
109 match cause:
110 case ValidationFailure{}:
111 error(InvalidArgument{}, operation, path, 0, "")
112 case WriteLimitReached{}:
113 error(ResourceLimit{}, operation, path, 0, "")
114 case WriteHostFailure{code, message}:
115 error(CommitUnknown{}, operation, path, code, message)
116
117# Selects the write error category from its append stage.
118def classify_write(phase: WritePhase, cause: WriteCause, operation: String, path: String) -> Error:
119 match phase:
120 case BeforeAppend{}:
121 classify_write_before(cause, operation, path)
122 case AppendStarted{}:
123 classify_write_after(cause, operation, path)