Skip to content

Commit 2df35d3

Browse files
committed
fix(token_index): mutex issue
* Make IndexRW.read use the mutex argument; * Use Lwt_mutex.with_lock (and Lwt_io.with_file) that behave better than Lwt_mutex.lock when a failure occurs => the mutex is unlocked.
1 parent dfe64ae commit 2df35d3

File tree

2 files changed

+26
-24
lines changed

2 files changed

+26
-24
lines changed

src/state/token_index.ml

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ module type IndexRW = sig
4141
type t
4242

4343
val init : unit -> t
44-
val read : string -> (string -> 'a) -> 'a Lwt.t
44+
val read : t -> string -> (string -> 'a) -> 'a Lwt.t
4545
val write : t -> string -> ('a -> string) -> 'a -> unit Lwt.t
4646
end
4747

@@ -51,19 +51,21 @@ module IndexFile: IndexRW = struct
5151
(* Unlocked by default *)
5252
let init = Lwt_mutex.create
5353

54-
let read filename parse =
55-
Lwt_io.open_file ~mode:Lwt_io.Input filename >>= fun channel ->
56-
Lwt_io.read channel >>= fun data ->
57-
Lwt_io.close channel >>= fun () ->
58-
Lwt.return @@ parse data
54+
let read mutex filename parse =
55+
Lwt_mutex.with_lock mutex @@
56+
fun () ->
57+
Lwt_io.with_file ~mode:Lwt_io.Input filename @@
58+
fun channel ->
59+
Lwt_io.read channel >>= fun data ->
60+
Lwt.return @@ parse data
5961

6062
let write mutex filename serialise data =
61-
Lwt_mutex.lock mutex >>= fun () ->
62-
Lwt_utils.mkdir_p ~perm:0o700 (Filename.dirname filename) >>= fun () ->
63-
Lwt_io.open_file ~mode:Lwt_io.Output filename >>= fun channel ->
64-
Lwt_io.write channel (serialise data) >>= fun () ->
65-
Lwt_io.close channel >>= fun () ->
66-
Lwt.return @@ Lwt_mutex.unlock mutex
63+
Lwt_mutex.with_lock mutex @@
64+
fun () ->
65+
Lwt_utils.mkdir_p ~perm:0o700 (Filename.dirname filename) >>= fun () ->
66+
Lwt_io.with_file ~mode:Lwt_io.Output filename @@
67+
fun channel ->
68+
Lwt_io.write channel (serialise data)
6769
end
6870

6971
(* inspired from learnocaml_data.ml *)
@@ -127,10 +129,10 @@ module BaseTokenIndex (RW: IndexRW) = struct
127129
let filename = (sync_dir / indexes_subdir / name) in
128130
let create () =
129131
create_index sync_dir >>= fun () ->
130-
RW.read filename parse in
132+
RW.read rw filename parse in
131133
if Sys.file_exists filename then
132134
Lwt.catch
133-
(fun () -> RW.read filename parse)
135+
(fun () -> RW.read rw filename parse)
134136
(fun _exn ->
135137
(* Note: this error handler may be adapted later to be more conservative?
136138
it does not matter now as sync/data/token.json is not a critical file, and
@@ -166,7 +168,7 @@ module BaseMoodleIndex (RW: IndexRW) = struct
166168

167169
let get_users sync_dir =
168170
Lwt.catch
169-
(fun () -> RW.read (sync_dir / indexes_subdir / file) parse)
171+
(fun () -> RW.read rw (sync_dir / indexes_subdir / file) parse)
170172
(fun _exn -> Lwt.return [])
171173

172174
let user_exists sync_dir id =
@@ -213,7 +215,7 @@ module BaseOauthIndex (RW: IndexRW) = struct
213215
(secret, []) in
214216
Lwt.catch
215217
(fun () ->
216-
RW.read (sync_dir / indexes_subdir / file) parse >>= function
218+
RW.read rw (sync_dir / indexes_subdir / file) parse >>= function
217219
| oauth :: _ -> Lwt.return oauth
218220
| [] -> create ())
219221
(fun _exn -> create ())
@@ -227,7 +229,7 @@ module BaseOauthIndex (RW: IndexRW) = struct
227229
RW.write rw (sync_dir / indexes_subdir / file) serialise [oauth]
228230

229231
let add_nonce sync_dir nonce =
230-
RW.read (sync_dir / indexes_subdir / file) parse >>= fun oauth ->
232+
RW.read rw (sync_dir / indexes_subdir / file) parse >>= fun oauth ->
231233
let oauth =
232234
match oauth with
233235
| (secret, nonces) :: r -> (secret, nonce :: nonces) :: r
@@ -369,7 +371,7 @@ module BaseUserIndex (RW: IndexRW) = struct
369371

370372
let get_data sync_dir =
371373
Lwt.catch
372-
(fun () -> RW.read (sync_dir / indexes_subdir / file) parse)
374+
(fun () -> RW.read rw (sync_dir / indexes_subdir / file) parse)
373375
(fun _exn -> create_index sync_dir)
374376

375377
let authenticate sync_dir auth =
@@ -473,14 +475,14 @@ module BaseUserIndex (RW: IndexRW) = struct
473475
found_token = token && not use_passwd) users <> None
474476

475477
let token_of_email sync_dir email =
476-
RW.read (sync_dir / indexes_subdir / file) parse >|=
478+
RW.read rw (sync_dir / indexes_subdir / file) parse >|=
477479
List.fold_left (fun res elt ->
478480
match res, elt with
479481
| None, Password (token, found_email, _, _) when found_email = email -> Some token
480482
| _ -> res) None
481483

482484
let emails_of_token sync_dir token =
483-
RW.read (sync_dir / indexes_subdir / file) parse >|=
485+
RW.read rw (sync_dir / indexes_subdir / file) parse >|=
484486
List.fold_left (fun res elt ->
485487
match res, elt with
486488
| None, Password (found_token, email, _, pending) when found_token = token ->
@@ -492,15 +494,15 @@ module BaseUserIndex (RW: IndexRW) = struct
492494
if exists then
493495
logfailwith "BaseUserIndex.change_email: duplicate email" new_email)
494496
>>= fun () ->
495-
RW.read (sync_dir / indexes_subdir / file) parse >|=
497+
RW.read rw (sync_dir / indexes_subdir / file) parse >|=
496498
List.map (function
497499
| Password (found_token, email, passwd, _) when found_token = token ->
498500
Password (found_token, email, passwd, Some new_email)
499501
| elt -> elt) >>=
500502
RW.write rw (sync_dir / indexes_subdir / file) serialise
501503

502504
let abort_email_change sync_dir token =
503-
RW.read (sync_dir / indexes_subdir / file) parse >|=
505+
RW.read rw (sync_dir / indexes_subdir / file) parse >|=
504506
List.map (function
505507
| Password (found_token, email, passwd, Some pending)
506508
when found_token = token && email <> pending ->
@@ -537,7 +539,7 @@ module BaseUpgradeIndex (RW: IndexRW) = struct
537539

538540
let get_data sync_dir =
539541
Lwt.catch
540-
(fun () -> RW.read (sync_dir / indexes_subdir / file) parse)
542+
(fun () -> RW.read rw (sync_dir / indexes_subdir / file) parse)
541543
(fun _exn -> create_index sync_dir)
542544

543545
let create_upgrade_operation kind sync_dir token =

src/state/token_index.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module type IndexRW = sig
1313
type t
1414

1515
val init : unit -> t
16-
val read : string -> (string -> 'a) -> 'a Lwt.t
16+
val read : t -> string -> (string -> 'a) -> 'a Lwt.t
1717
val write : t -> string -> ('a -> string) -> 'a -> unit Lwt.t
1818
end
1919

0 commit comments

Comments
 (0)