src/ByteManifestIo.bend
mylsm-lsm-store@0.6.0.1 · 155 lines · 16 definitions
1import Base
2import mylsm-lsm-store@0.6.0.1/src/ByteManifest.bend as Manifest
3import mylsm-lsm-store@0.6.0.1/src/Fs.bend as Fs
4import bend-kit-bytes@0.3.2.0/bytes.bend as Bytes
5
6
7type Error is Data:
8 Invalid{error: Manifest.Error}
9 Host{code: U32, message: String}
10
11def path.reverse(path: String, reversed: String) -> String:
12 match path:
13 case SNil{}: reversed
14 case SCon{character, rest}: path.reverse(rest, SCon{character, reversed})
15
16def path.clone(path: String) -> String:
17 path.reverse(path.reverse(path, SNil{}), SNil{})
18
19def read.result(
20 result: Result<&1, &1, Manifest.Error, Manifest.ManifestValue>
21) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
22 match result:
23 case Fail{error}:
24 IO.pure(Result<&1, &1, Error, Manifest.ManifestValue>, Fail{Invalid{error}})
25 case Done{value}:
26 IO.pure(Result<&1, &1, Error, Manifest.ManifestValue>, Done{value})
27
28def read.host(error: U32 & String) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
29 match error:
30 case (code, message):
31 IO.pure(Result<&1, &1, Error, Manifest.ManifestValue>, Fail{Host{code, message}})
32
33def read.decoded(
34 pair: File & Result<&1, &1, U32 & String, Bytes.Bytes>
35) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
36 match pair:
37 case (file, Fail{error}):
38 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
39 _closed : Unit <- File.close(file)
40 read.host(error)
41 case (file, Done{bytes}):
42 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
43 _closed : Unit <- File.close(file)
44 read.result(Manifest.decode(bytes))
45
46def read.sized(file: File, size: Nat) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
47 match size:
48 case 56n:
49 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
50 pair : File & Result<&1, &1, U32 & String, Bytes.Bytes> <- Fs.read_at(file, 0, 56)
51 read.decoded(pair)
52 case 63n:
53 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
54 pair : File & Result<&1, &1, U32 & String, Bytes.Bytes> <- Fs.read_at(file, 0, 63)
55 read.decoded(pair)
56 case 60n:
57 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
58 pair : File & Result<&1, &1, U32 & String, Bytes.Bytes> <- Fs.read_at(file, 0, 60)
59 read.decoded(pair)
60 case _:
61 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
62 _closed : Unit <- File.close(file)
63 read.result(Fail{Manifest.Malformed{}})
64
65def read.size.result(
66 file: File,
67 result: Result<&1, &1, U32 & String, Nat>
68) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
69 match result:
70 case Done{size}: read.sized(file, size)
71 case Fail{error}:
72 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
73 _closed : Unit <- File.close(file)
74 read.host(error)
75
76def read.path.opened(
77 path: String,
78 opened: Result<&1, &1, U32 & String, File>
79) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
80 match opened:
81 case Fail{error}:
82 read.host(error)
83 case Done{file}:
84 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
85 size : Result<&1, &1, U32 & String, Nat> <- Fs.file_size(path)
86 read.size.result(file, size)
87
88
89def read(
90 +path: String
91) -> IO(Result<&1, &1, Error, Manifest.ManifestValue>):
92 do IO<Result<&1, &1, Error, Manifest.ManifestValue>>:
93 opened : Result<&1, &1, U32 & String, File> <- File.open(path, "r")
94 read.path.opened(path, opened)
95
96def write.directory.synced(
97 directory: String,
98 result: Result<&1, &1, U32 & String, Unit>
99) -> IO(Result<&1, &1, U32 & String, Unit>):
100 match result:
101 case Fail{error}: IO.pure(Result<&1, &1, U32 & String, Unit>, Fail{error})
102 case Done{Unit{}}: Fs.fsync(directory)
103
104def write.renamed(
105 +directory: String,
106 result: Result<&1, &1, U32 & String, Unit>
107) -> IO(Result<&1, &1, U32 & String, Unit>):
108 match result:
109 case Fail{error}: IO.pure(Result<&1, &1, U32 & String, Unit>, Fail{error})
110 case Done{Unit{}}:
111 do IO<Result<&1, &1, U32 & String, Unit>>:
112 renamed : Result<&1, &1, U32 & String, Unit> <- Fs.rename(directory ++ "/MANIFEST.tmp", directory ++ "/MANIFEST")
113 write.directory.synced(directory, renamed)
114
115def write.closed(
116 +directory: String,
117 result: Result<&1, &1, U32 & String, Unit>
118) -> IO(Result<&1, &1, U32 & String, Unit>):
119 match result:
120 case Fail{error}: IO.pure(Result<&1, &1, U32 & String, Unit>, Fail{error})
121 case Done{Unit{}}:
122 do IO<Result<&1, &1, U32 & String, Unit>>:
123 synced : Result<&1, &1, U32 & String, Unit> <- Fs.fsync(directory ++ "/MANIFEST.tmp")
124 write.renamed(directory, synced)
125
126def write.file.synced(
127 directory: String,
128 result: File & Result<&1, &1, U32 & String, Unit>
129) -> IO(Result<&1, &1, U32 & String, Unit>):
130 match result:
131 case (file, result):
132 do IO<Result<&1, &1, U32 & String, Unit>>:
133 _closed : Unit <- File.close(file)
134 write.closed(directory, result)
135
136def write.bytes(
137 directory: String,
138 bytes: Bytes.Bytes,
139 opened: Result<&1, &1, U32 & String, File>
140) -> IO(Result<&1, &1, U32 & String, Unit>):
141 match opened:
142 case Fail{error}: IO.pure(Result<&1, &1, U32 & String, Unit>, Fail{error})
143 case Done{file}:
144 do IO<Result<&1, &1, U32 & String, Unit>>:
145 result : File & Result<&1, &1, U32 & String, Unit> <- Fs.write_bytes(file, bytes)
146 write.file.synced(directory, result)
147
148
149def write_atomic(
150 +directory: String,
151 value: Manifest.ManifestValue
152) -> IO(Result<&1, &1, U32 & String, Unit>):
153 do IO<Result<&1, &1, U32 & String, Unit>>:
154 opened : Result<&1, &1, U32 & String, File> <- File.open(directory ++ "/MANIFEST.tmp", "w")
155 write.bytes(directory, Manifest.encode(value), opened)