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
156
157
158
159
160
161
162
163
164
165
166
167
open! Import
let src = Logs.Src.create "irmin.mem" ~doc:"Irmin in-memory store"
module Log = (val Logs.src_log src : Logs.LOG)
module Conf = struct
include Irmin.Backend.Conf
let spec = Spec.v "mem"
let root config = find_root config |> Option.value ~default:"."
end
module Read_only (K : Irmin.Type.S) (V : Irmin.Type.S) = struct
module KMap = Map.Make (struct
type t = K.t
let compare = Irmin.Type.(unstage (compare K.t))
end)
type key = K.t
type value = V.t
type 'a t = { mutable t : value KMap.t; root : string }
let new_instance root = { t = KMap.empty; root }
let v =
let cache : (string, 'a t) Hashtbl.t = Hashtbl.create 0 in
fun config ->
let root = Conf.root config in
let t =
match Hashtbl.find_opt cache root with
| None ->
let t = new_instance root in
Hashtbl.add cache root t;
t
| Some t -> t
in
Lwt.return t
let clear t =
[%log.debug "clear"];
t.t <- KMap.empty;
Lwt.return_unit
let close _ =
[%log.debug "close"];
Lwt.return_unit
let cast t = (t :> read_write t)
let batch t f = f (cast t)
let pp_key = Irmin.Type.pp K.t
let find { t; _ } key =
[%log.debug "find %a" pp_key key];
try Lwt.return_some (KMap.find key t) with Not_found -> Lwt.return_none
let mem { t; _ } key =
[%log.debug "mem %a" pp_key key];
Lwt.return (KMap.mem key t)
end
module Append_only (K : Irmin.Type.S) (V : Irmin.Type.S) = struct
include Read_only (K) (V)
let add t key value =
[%log.debug "add -> %a" pp_key key];
t.t <- KMap.add key value t.t;
Lwt.return_unit
end
module Atomic_write (K : Irmin.Type.S) (V : Irmin.Type.S) = struct
module RO = Read_only (K) (V)
module W = Irmin.Backend.Watch.Make (K) (V)
module L = Irmin.Backend.Lock.Make (K)
type t = { t : unit RO.t; w : W.t; lock : L.t }
type key = RO.key
type value = RO.value
type watch = W.watch
let watches = W.v ()
let lock = L.v ()
let v config =
let* t = RO.v config in
Lwt.return { t; w = watches; lock }
let close t = W.clear t.w >>= fun () -> RO.close t.t
let find t = RO.find t.t
let mem t = RO.mem t.t
let watch_key t = W.watch_key t.w
let watch t = W.watch t.w
let unwatch t = W.unwatch t.w
let list t =
[%log.debug "list"];
RO.KMap.fold (fun k _ acc -> k :: acc) t.t.RO.t [] |> Lwt.return
let set t key value =
[%log.debug "update"];
let* () =
L.with_lock t.lock key (fun () ->
t.t.RO.t <- RO.KMap.add key value t.t.RO.t;
Lwt.return_unit)
in
W.notify t.w key (Some value)
let remove t key =
[%log.debug "remove"];
let* () =
L.with_lock t.lock key (fun () ->
t.t.RO.t <- RO.KMap.remove key t.t.RO.t;
Lwt.return_unit)
in
W.notify t.w key None
let equal_v_opt = Irmin.Type.(unstage (equal (option V.t)))
let test_and_set t key ~test ~set =
[%log.debug "test_and_set"];
let* updated =
L.with_lock t.lock key (fun () ->
let+ v = find t key in
if equal_v_opt test v then
let () =
match set with
| None -> t.t.RO.t <- RO.KMap.remove key t.t.RO.t
| Some v -> t.t.RO.t <- RO.KMap.add key v t.t.RO.t
in
true
else false)
in
let+ () = if updated then W.notify t.w key set else Lwt.return_unit in
updated
let clear t = W.clear t.w >>= fun () -> RO.clear t.t
end
let config () = Conf.empty Conf.spec
module Content_addressable = Irmin.Content_addressable.Make (Append_only)
module S = Irmin.Maker (Content_addressable) (Atomic_write)
module KV = Irmin.KV_maker (Content_addressable) (Atomic_write)
include S
module Maker_is_a_maker : Irmin.Maker = S
module KV_is_a_KV : Irmin.KV_maker = KV