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
module Log = Dream__server.Log
module Message = Dream_pure.Message
let log =
Log.sub_log "dream.sql"
let pool_field : (_, Caqti.Error.t) Caqti_lwt_unix.Pool.t Message.field =
Message.new_field ()
let sql_pool ?size ?post_connect uri =
let pool_cell = ref None in
fun inner_handler request ->
begin match !pool_cell with
| Some pool ->
Message.set_field request pool_field pool;
inner_handler request
| None ->
let parsed_uri = Uri.of_string uri in
if Uri.scheme parsed_uri = Some "sqlite" then
log.warning (fun log -> log ~request
"Dream.sql_pool: \
'sqlite' is not a valid scheme; did you mean 'sqlite3'?");
let post_connect =
Option.map
(fun post_connect db -> Lwt.map Result.ok (post_connect db))
post_connect
in
let pool =
let pool_config = Caqti.Pool.Config.create ?max_size:size () in
Caqti_lwt_unix.connect_pool ~pool_config ?post_connect parsed_uri
in
match pool with
| Ok pool ->
pool_cell := Some pool;
Message.set_field request pool_field pool;
inner_handler request
| Error error ->
let message =
Printf.sprintf "Dream.sql_pool: cannot create pool for '%s': %s"
uri (Caqti.Error.show error) in
log.error (fun log -> log ~request "%s" message);
failwith message
end
let acquired_sql_connection : bool Lwt.key =
Lwt.new_key ()
let sql request callback =
match Message.field request pool_field with
| None ->
let message = "Dream.sql: no pool; did you apply Dream.sql_pool?" in
log.error (fun log -> log ~request "%s" message);
failwith message
| Some pool ->
begin match Lwt.get acquired_sql_connection with
| None | Some false -> ()
| Some true ->
let message =
"Re-entrant call to Dream.sql, perhaps through " ^
"Dream.set_session_field; could cause deadlock"
in
log.warning (fun log -> log ~request "%s" message)
end;
let%lwt result =
pool |> Caqti_lwt_unix.Pool.use (fun db ->
Lwt.with_value acquired_sql_connection (Some true) @@ fun () ->
match%lwt callback db with
| result -> Lwt.return (Ok result)
| exception exn -> raise exn)
in
Caqti_lwt.or_fail result