···2525 "at://%s"
2626 (fun h -> h)
2727 in
2828- let%lwt repo = Repository.load ~write:false did in
2828+ let%lwt repo = Repository.load did in
2929 let%lwt collections = Repository.list_collections repo in
3030 Dream.json @@ Yojson.Safe.to_string
3131 @@ response_to_yojson
+1-3
pegasus/lib/api/repo/importRepo.ml
···1313 let did = Auth.get_authed_did_exn ctx.auth in
1414 let bytes_stream = Dream.body_stream ctx.req in
1515 let car_stream = stream_to_seq bytes_stream in
1616- let%lwt repo =
1717- Repository.load did ~ds:ctx.db ~ensure_active:true ~write:true
1818- in
1616+ let%lwt repo = Repository.load did ~ds:ctx.db ~ensure_active:true in
1917 let%lwt result = Repository.import_car repo car_stream in
2018 match result with
2119 | Ok _ ->
+1-1
pegasus/lib/api/server/checkAccountStatus.ml
···1818 Errors.internal_error ~msg:"actor not found" ()
1919 | Some actor -> (
2020 let%lwt {db= us; commit; _} =
2121- Repository.load ~write:false ~ds:db did
2121+ Repository.load ~ds:db did
2222 in
2323 let%lwt cid, commit =
2424 match commit with
+1-1
pegasus/lib/api/server/createAccount.ml
···120120 ~perm:0o644
121121 in
122122 let%lwt repo =
123123- Repository.load ~write:true ~create:true ~ds:db did
123123+ Repository.load ~create:true ~ds:db did
124124 in
125125 let%lwt _ = Repository.put_initial_commit repo in
126126 let%lwt _ = Sequencer.sequence_identity db ~did ~handle () in
+1-1
pegasus/lib/api/sync/getBlob.ml
···55 let {did; cid} = Xrpc.parse_query ctx.req query_of_yojson in
66 let cid_parsed = Cid.as_cid cid in
77 let%lwt {db; _} =
88- Repository.load did ~ensure_active:true ~write:false ~ds:ctx.db
88+ Repository.load did ~ensure_active:true ~ds:ctx.db
99 in
1010 let%lwt blob_meta = User_store.get_blob_metadata db cid_parsed in
1111 match blob_meta with
+1-1
pegasus/lib/api/sync/getBlocks.ml
···55 Xrpc.handler (fun ctx ->
66 let {did; cids} : query = Xrpc.parse_query ctx.req query_of_yojson in
77 let%lwt {db; commit; _} =
88- Repository.load did ~ensure_active:true ~write:false ~ds:ctx.db
88+ Repository.load did ~ensure_active:true ~ds:ctx.db
99 in
1010 let commit_cid, commit_signed = Option.get commit in
1111 let commit_block =
+1-1
pegasus/lib/api/sync/getLatestCommit.ml
···66 Xrpc.handler (fun ctx ->
77 let {did} : query = Xrpc.parse_query ctx.req query_of_yojson in
88 match%lwt
99- Repository.load did ~ensure_active:true ~write:false ~ds:ctx.db
99+ Repository.load did ~ensure_active:true ~ds:ctx.db
1010 with
1111 | {commit= Some (cid, {rev; _}); _} ->
1212 let cid = Cid.to_string cid in
+1-1
pegasus/lib/api/sync/getRecord.ml
···1010 in
1111 let path = collection ^ "/" ^ rkey in
1212 let%lwt repo =
1313- Repository.load did ~ensure_active:true ~write:false ~ds:ctx.db
1313+ Repository.load did ~ensure_active:true ~ds:ctx.db
1414 in
1515 match%lwt Repository.get_record repo path with
1616 | None ->
+1-1
pegasus/lib/api/sync/getRepo.ml
···33let handler =
44 Xrpc.handler (fun ctx ->
55 let {did} : query = Xrpc.parse_query ctx.req query_of_yojson in
66- let%lwt repo = Repository.load did ~ensure_active:true ~write:false in
66+ let%lwt repo = Repository.load did ~ensure_active:true in
77 let%lwt car_stream = Repository.export_car repo in
88 Dream.stream
99 ~headers:[("Content-Type", "application/vnd.ipld.car")]
+1-1
pegasus/lib/api/sync/getRepoStatus.ml
···1515 Errors.invalid_request ~name:"RepoNotFound"
1616 "couldn't find a repo with that did"
1717 in
1818- let%lwt {db= user_db; _} = Repository.load did ~write:false ~ds:ctx.db in
1818+ let%lwt {db= user_db; _} = Repository.load did ~ds:ctx.db in
1919 let%lwt _, commit =
2020 match%lwt User_store.get_commit user_db with
2121 | Some c ->
+1-1
pegasus/lib/api/sync/listBlobs.ml
···2222 1000
2323 in
2424 let%lwt {db; _} =
2525- Repository.load did ~ensure_active:true ~write:false ~ds:ctx.db
2525+ Repository.load did ~ensure_active:true ~ds:ctx.db
2626 in
2727 let%lwt cids = User_store.list_blobs db ~limit ~cursor ?since in
2828 let cids = List.map Cid.to_string cids in
+19-8
pegasus/lib/data_store.ml
···318318319319type t = Util.caqti_pool
320320321321-let connect ?create ?write () : t Lwt.t =
322322- if create = Some true then
323323- Util.mkfile_p Util.Constants.pegasus_db_filepath ~perm:0o644 ;
324324- let%lwt db =
325325- Util.connect_sqlite ?create ?write Util.Constants.pegasus_db_location
326326- in
327327- let%lwt () = Migrations.run_migrations Data_store db in
328328- Lwt.return db
321321+let pool : t option ref = ref None
322322+323323+let pool_mutex = Lwt_mutex.create ()
324324+325325+let connect ?create () : t Lwt.t =
326326+ Lwt_mutex.with_lock pool_mutex (fun () ->
327327+ match !pool with
328328+ | Some pool ->
329329+ Lwt.return pool
330330+ | None ->
331331+ if create = Some true then
332332+ Util.mkfile_p Util.Constants.pegasus_db_filepath ~perm:0o644 ;
333333+ let%lwt db =
334334+ Util.connect_sqlite ?create ~write:true
335335+ Util.Constants.pegasus_db_location
336336+ in
337337+ let%lwt () = Migrations.run_migrations Data_store db in
338338+ pool := Some db ;
339339+ Lwt.return db )
329340330341let create_actor ~did ~handle ~email ~password ~signing_key conn =
331342 let password_hash = Bcrypt.hash password |> Bcrypt.string_of_hash in
+242-194
pegasus/lib/repository.ml
···88module String_map = Lex.String_map
99module Tid = Mist.Tid
10101111+let write_locks : (string, Lwt_mutex.t) Hashtbl.t = Hashtbl.create 100
1212+1313+let write_lock_mutex = Lwt_mutex.create ()
1414+1515+let with_write_lock did f =
1616+ let%lwt lock =
1717+ Lwt_mutex.with_lock write_lock_mutex (fun () ->
1818+ match Hashtbl.find_opt write_locks did with
1919+ | Some l ->
2020+ Lwt.return l
2121+ | None ->
2222+ let l = Lwt_mutex.create () in
2323+ Hashtbl.add write_locks did l ;
2424+ Lwt.return l )
2525+ in
2626+ Lwt_mutex.with_lock lock f
2727+1128module Write_op = struct
1229 let create = "com.atproto.repo.applyWrites#create"
1330···244261245262let apply_writes (t : t) (writes : repo_write list) (swap_commit : Cid.t option)
246263 : write_result Lwt.t =
247247- let open Sequencer.Types in
248248- let%lwt prev_commit =
249249- match%lwt User_store.get_commit t.db with
250250- | Some (_, commit) ->
251251- Lwt.return commit
252252- | None ->
253253- failwith ("failed to retrieve commit for " ^ t.did)
254254- in
255255- if swap_commit <> None && swap_commit <> Option.map fst t.commit then
256256- Errors.invalid_request ~name:"InvalidSwap"
257257- (Format.sprintf "swapCommit cid %s did not match last commit cid %s"
258258- (Cid.to_string (Option.get swap_commit))
259259- (match t.commit with Some (c, _) -> Cid.to_string c | None -> "null") ) ;
260260- let cached_store = Cached_store.create t.db in
261261- let mst : Cached_mst.t ref =
262262- ref (Cached_mst.create cached_store prev_commit.data)
263263- in
264264- t.block_map <- None ;
265265- (* ops to emit, built in loop because prev_data (previous cid) is otherwise inaccessible *)
266266- let commit_ops : commit_evt_op list ref = ref [] in
267267- let added_leaves = ref Block_map.empty in
268268- let%lwt results =
269269- Lwt_list.map_s
270270- (fun (w : repo_write) ->
271271- match w with
272272- | Create {collection; rkey; value; _} ->
273273- let rkey = Option.value rkey ~default:(Tid.now ()) in
274274- let path = Format.sprintf "%s/%s" collection rkey in
275275- let uri = Format.sprintf "at://%s/%s" t.did path in
276276- let%lwt () =
277277- match%lwt User_store.get_record_cid t.db path with
278278- | Some cid ->
279279- Errors.invalid_request ~name:"InvalidSwap"
280280- (Format.sprintf
281281- "attempted to write record %s that already exists \
282282- with cid %s"
283283- path (Cid.to_string cid) )
284284- | None ->
285285- Lwt.return ()
286286- in
287287- let record_with_type : Lex.repo_record =
288288- if String_map.mem "$type" value then value
289289- else String_map.add "$type" (`String collection) value
290290- in
291291- let%lwt cid, block =
292292- User_store.put_record t.db (`LexMap record_with_type) path
293293- in
294294- added_leaves := Block_map.set cid block !added_leaves ;
295295- commit_ops :=
296296- !commit_ops @ [{action= `Create; path; cid= Some cid; prev= None}] ;
297297- let%lwt new_mst = Cached_mst.add !mst path cid in
298298- mst := new_mst ;
299299- let refs =
300300- Util.find_blob_refs value
301301- |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
302302- in
303303- let%lwt () =
304304- match%lwt User_store.put_blob_refs t.db path refs with
305305- | Ok () ->
306306- Lwt.return ()
307307- | Error err ->
308308- raise err
309309- in
310310- Lwt.return
311311- (Create
312312- { type'= "com.atproto.repo.applyWrites#createResult"
313313- ; uri
314314- ; cid } )
315315- | Update {collection; rkey; value; swap_record; _} ->
316316- let path = Format.sprintf "%s/%s" collection rkey in
317317- let uri = Format.sprintf "at://%s/%s" t.did path in
318318- let%lwt old_cid = User_store.get_record_cid t.db path in
319319- ( if
320320- (swap_record <> None && swap_record <> old_cid)
321321- || (swap_record = None && old_cid = None)
322322- then
323323- let cid_str =
264264+ with_write_lock t.did (fun () ->
265265+ Dream.debug (fun l -> l "lock acquired") ;
266266+ let open Sequencer.Types in
267267+ let module Inductive = Mist.Mst.Inductive (Mst) in
268268+ let%lwt prev_commit =
269269+ match%lwt User_store.get_commit t.db with
270270+ | Some (_, commit) ->
271271+ Lwt.return commit
272272+ | None ->
273273+ failwith ("failed to retrieve commit for " ^ t.did)
274274+ in
275275+ Dream.debug (fun l -> l "commit retrieved") ;
276276+ if swap_commit <> None && swap_commit <> Option.map fst t.commit then
277277+ Errors.invalid_request ~name:"InvalidSwap"
278278+ (Format.sprintf "swapCommit cid %s did not match last commit cid %s"
279279+ (Cid.to_string (Option.get swap_commit))
280280+ ( match t.commit with
281281+ | Some (c, _) ->
282282+ Cid.to_string c
283283+ | None ->
284284+ "null" ) ) ;
285285+ let%lwt block_map = Lwt.map ref (get_map t) in
286286+ let cached_store = Cached_store.create t.db in
287287+ let mst : Cached_mst.t ref =
288288+ ref (Cached_mst.create cached_store prev_commit.data)
289289+ in
290290+ (* ops to emit, built in loop because prev_data (previous cid) is otherwise inaccessible *)
291291+ let commit_ops : commit_evt_op list ref = ref [] in
292292+ let added_leaves = ref Block_map.empty in
293293+ let%lwt results =
294294+ Lwt_list.map_s
295295+ (fun (w : repo_write) ->
296296+ match w with
297297+ | Create {collection; rkey; value; _} ->
298298+ let rkey = Option.value rkey ~default:(Tid.now ()) in
299299+ let path = Format.sprintf "%s/%s" collection rkey in
300300+ let uri = Format.sprintf "at://%s/%s" t.did path in
301301+ let%lwt () =
302302+ match String_map.find_opt path !block_map with
303303+ | Some cid ->
304304+ Errors.invalid_request ~name:"InvalidSwap"
305305+ (Format.sprintf
306306+ "attempted to write record %s that already exists \
307307+ with cid %s"
308308+ path (Cid.to_string cid) )
309309+ | None ->
310310+ Lwt.return ()
311311+ in
312312+ let record_with_type : Lex.repo_record =
313313+ if String_map.mem "$type" value then value
314314+ else String_map.add "$type" (`String collection) value
315315+ in
316316+ let%lwt cid, block =
317317+ User_store.put_record t.db (`LexMap record_with_type) path
318318+ in
319319+ block_map := String_map.add path cid !block_map ;
320320+ added_leaves := Block_map.set cid block !added_leaves ;
321321+ commit_ops :=
322322+ !commit_ops
323323+ @ [{action= `Create; path; cid= Some cid; prev= None}] ;
324324+ let%lwt new_mst = Cached_mst.add !mst path cid in
325325+ mst := new_mst ;
326326+ let refs =
327327+ Util.find_blob_refs value
328328+ |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
329329+ in
330330+ let%lwt () =
331331+ match%lwt User_store.put_blob_refs t.db path refs with
332332+ | Ok () ->
333333+ Lwt.return ()
334334+ | Error err ->
335335+ raise err
336336+ in
337337+ Lwt.return
338338+ (Create
339339+ { type'= "com.atproto.repo.applyWrites#createResult"
340340+ ; uri
341341+ ; cid } )
342342+ | Update {collection; rkey; value; swap_record; _} ->
343343+ let path = Format.sprintf "%s/%s" collection rkey in
344344+ let uri = Format.sprintf "at://%s/%s" t.did path in
345345+ let old_cid = String_map.find_opt path !block_map in
346346+ ( if
347347+ (swap_record <> None && swap_record <> old_cid)
348348+ || (swap_record = None && old_cid = None)
349349+ then
350350+ let cid_str =
351351+ match old_cid with
352352+ | Some cid ->
353353+ Cid.to_string cid
354354+ | None ->
355355+ "null"
356356+ in
357357+ Errors.invalid_request ~name:"InvalidSwap"
358358+ (Format.sprintf
359359+ "attempted to update record %s with cid %s" path
360360+ cid_str ) ) ;
361361+ let%lwt () =
324362 match old_cid with
325325- | Some cid ->
326326- Cid.to_string cid
363363+ | Some _ -> (
364364+ match%lwt User_store.get_record t.db path with
365365+ | Some record ->
366366+ let refs =
367367+ Util.find_blob_refs record.value
368368+ |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
369369+ in
370370+ if not (List.is_empty refs) then
371371+ let%lwt _ =
372372+ User_store.delete_orphaned_blobs_by_record_path t.db
373373+ path
374374+ in
375375+ Lwt.return_unit
376376+ else Lwt.return_unit
377377+ | None ->
378378+ Lwt.return_unit )
327379 | None ->
328328- "null"
380380+ Lwt.return_unit
329381 in
330330- Errors.invalid_request ~name:"InvalidSwap"
331331- (Format.sprintf "attempted to update record %s with cid %s"
332332- path cid_str ) ) ;
333333- let%lwt () =
334334- match old_cid with
335335- | Some _ -> (
382382+ let record_with_type : Lex.repo_record =
383383+ if String_map.mem "$type" value then value
384384+ else String_map.add "$type" (`String collection) value
385385+ in
386386+ let%lwt new_cid, new_block =
387387+ User_store.put_record t.db (`LexMap record_with_type) path
388388+ in
389389+ added_leaves := Block_map.set new_cid new_block !added_leaves ;
390390+ block_map := String_map.add path new_cid !block_map ;
391391+ commit_ops :=
392392+ !commit_ops
393393+ @ [{action= `Update; path; cid= Some new_cid; prev= old_cid}] ;
394394+ let%lwt new_mst = Cached_mst.add !mst path new_cid in
395395+ mst := new_mst ;
396396+ let refs =
397397+ Util.find_blob_refs value
398398+ |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
399399+ in
400400+ let%lwt () =
401401+ match%lwt User_store.put_blob_refs t.db path refs with
402402+ | Ok () ->
403403+ Lwt.return ()
404404+ | Error err ->
405405+ raise err
406406+ in
407407+ Lwt.return
408408+ (Update
409409+ { type'= "com.atproto.repo.applyWrites#updateResult"
410410+ ; uri
411411+ ; cid= new_cid } )
412412+ | Delete {collection; rkey; swap_record; _} ->
413413+ let path = Format.sprintf "%s/%s" collection rkey in
414414+ let cid = String_map.find_opt path !block_map in
415415+ ( if cid = None || (swap_record <> None && swap_record <> cid)
416416+ then
417417+ let cid_str =
418418+ match cid with
419419+ | Some cid ->
420420+ Cid.to_string cid
421421+ | None ->
422422+ "null"
423423+ in
424424+ Errors.invalid_request ~name:"InvalidSwap"
425425+ (Format.sprintf
426426+ "attempted to delete record %s with cid %s" path
427427+ cid_str ) ) ;
428428+ let%lwt () =
336429 match%lwt User_store.get_record t.db path with
337430 | Some record ->
338431 let refs =
···347440 Lwt.return_unit
348441 else Lwt.return_unit
349442 | None ->
350350- Lwt.return_unit )
351351- | None ->
352352- Lwt.return_unit
353353- in
354354- let record_with_type : Lex.repo_record =
355355- if String_map.mem "$type" value then value
356356- else String_map.add "$type" (`String collection) value
357357- in
358358- let%lwt new_cid, new_block =
359359- User_store.put_record t.db (`LexMap record_with_type) path
360360- in
361361- added_leaves := Block_map.set new_cid new_block !added_leaves ;
362362- commit_ops :=
363363- !commit_ops
364364- @ [{action= `Update; path; cid= Some new_cid; prev= old_cid}] ;
365365- let%lwt new_mst = Cached_mst.add !mst path new_cid in
366366- mst := new_mst ;
367367- let refs =
368368- Util.find_blob_refs value
369369- |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
370370- in
371371- let%lwt () =
372372- match%lwt User_store.put_blob_refs t.db path refs with
373373- | Ok () ->
374374- Lwt.return ()
375375- | Error err ->
376376- raise err
377377- in
378378- Lwt.return
379379- (Update
380380- { type'= "com.atproto.repo.applyWrites#updateResult"
381381- ; uri
382382- ; cid= new_cid } )
383383- | Delete {collection; rkey; swap_record; _} ->
384384- let path = Format.sprintf "%s/%s" collection rkey in
385385- let%lwt cid = User_store.get_record_cid t.db path in
386386- ( if cid = None || (swap_record <> None && swap_record <> cid) then
387387- let cid_str =
388388- match cid with
389389- | Some cid ->
390390- Cid.to_string cid
391391- | None ->
392392- "null"
443443+ Lwt.return_unit
393444 in
394394- Errors.invalid_request ~name:"InvalidSwap"
395395- (Format.sprintf "attempted to delete record %s with cid %s"
396396- path cid_str ) ) ;
397397- let%lwt () =
398398- match%lwt User_store.get_record t.db path with
399399- | Some record ->
400400- let refs =
401401- Util.find_blob_refs record.value
402402- |> List.map (fun (r : Mist.Blob_ref.t) -> r.ref)
403403- in
404404- if not (List.is_empty refs) then
405405- let%lwt _ =
406406- User_store.delete_orphaned_blobs_by_record_path t.db path
407407- in
408408- Lwt.return_unit
409409- else Lwt.return_unit
410410- | None ->
411411- Lwt.return_unit
412412- in
413413- let%lwt () = User_store.delete_record t.db path in
414414- commit_ops :=
415415- !commit_ops @ [{action= `Delete; path; cid= None; prev= cid}] ;
416416- let%lwt new_mst = Cached_mst.delete !mst path in
417417- mst := new_mst ;
418418- Lwt.return
419419- (Delete {type'= "com.atproto.repo.applyWrites#deleteResult"}) )
420420- writes
421421- in
422422- let new_mst = !mst in
423423- let%lwt new_commit = put_commit t new_mst.root ~previous:(Some prev_commit) in
424424- let new_commit_cid, new_commit_signed = new_commit in
425425- let commit_block =
426426- new_commit_signed |> signed_commit_to_yojson |> Dag_cbor.encode_yojson
427427- in
428428- let%lwt proof_blocks =
429429- Lwt_list.fold_left_s
430430- (fun acc ({path; _} : commit_evt_op) ->
431431- let%lwt key_proof =
432432- Cached_mst.proof_for_key new_mst new_mst.root path
433433- in
434434- Lwt.return (Block_map.merge acc key_proof) )
435435- Block_map.empty !commit_ops
436436- in
437437- let proof_blocks = Block_map.merge proof_blocks !added_leaves in
438438- let block_stream =
439439- proof_blocks |> Block_map.entries |> Lwt_seq.of_list
440440- |> Lwt_seq.cons (new_commit_cid, commit_block)
441441- in
442442- let%lwt blocks =
443443- Car.blocks_to_stream new_commit_cid block_stream |> Car.collect_stream
444444- in
445445- let%lwt ds = Data_store.connect () in
446446- let%lwt _ =
447447- Sequencer.sequence_commit ds ~did:t.did ~commit:new_commit_cid
448448- ~rev:new_commit_signed.rev ~blocks ~ops:!commit_ops
449449- ~since:prev_commit.rev ~prev_data:prev_commit.data ()
450450- in
451451- Lwt.return {commit= new_commit; results}
445445+ let%lwt () = User_store.delete_record t.db path in
446446+ block_map := String_map.remove path !block_map ;
447447+ commit_ops :=
448448+ !commit_ops @ [{action= `Delete; path; cid= None; prev= cid}] ;
449449+ let%lwt new_mst = Cached_mst.delete !mst path in
450450+ mst := new_mst ;
451451+ Lwt.return
452452+ (Delete {type'= "com.atproto.repo.applyWrites#deleteResult"}) )
453453+ writes
454454+ in
455455+ Dream.debug (fun l -> l "writes processed") ;
456456+ let new_mst = !mst in
457457+ let%lwt new_commit =
458458+ put_commit t new_mst.root ~previous:(Some prev_commit)
459459+ in
460460+ Dream.debug (fun l -> l "commit inserted") ;
461461+ let new_commit_cid, new_commit_signed = new_commit in
462462+ let commit_block =
463463+ new_commit_signed |> signed_commit_to_yojson |> Dag_cbor.encode_yojson
464464+ in
465465+ let diff : Inductive.diff list =
466466+ List.fold_left
467467+ (fun (acc : Inductive.diff list)
468468+ ({action; path; cid; prev} : commit_evt_op) ->
469469+ match action with
470470+ | `Create ->
471471+ acc @ [Add {key= path; cid= Option.get cid}]
472472+ | `Update ->
473473+ acc @ [Update {key= path; cid= Option.get cid; prev}]
474474+ | `Delete ->
475475+ acc @ [Delete {key= path; prev= Option.get prev}] )
476476+ [] !commit_ops
477477+ in
478478+ let%lwt proof_blocks =
479479+ match%lwt
480480+ Inductive.generate_proof !block_map diff ~new_root:new_mst.root
481481+ ~prev_root:prev_commit.data
482482+ with
483483+ | Ok blocks ->
484484+ Lwt.return (Block_map.merge blocks !added_leaves)
485485+ | Error err ->
486486+ raise err
487487+ in
488488+ Dream.debug (fun l -> l "proof generated") ;
489489+ let block_stream =
490490+ proof_blocks |> Block_map.entries |> Lwt_seq.of_list
491491+ |> Lwt_seq.cons (new_commit_cid, commit_block)
492492+ in
493493+ let%lwt blocks =
494494+ Car.blocks_to_stream new_commit_cid block_stream |> Car.collect_stream
495495+ in
496496+ let%lwt ds = Data_store.connect () in
497497+ let%lwt _ =
498498+ Sequencer.sequence_commit ds ~did:t.did ~commit:new_commit_cid
499499+ ~rev:new_commit_signed.rev ~blocks ~ops:!commit_ops
500500+ ~since:prev_commit.rev ~prev_data:prev_commit.data ()
501501+ in
502502+ Dream.debug (fun l -> l "commit sequenced") ;
503503+ Lwt.return {commit= new_commit; results} )
452504453453-let load ?write ?create ?(ensure_active = false) ?ds did : t Lwt.t =
505505+let load ?create ?(ensure_active = false) ?ds did : t Lwt.t =
454506 let%lwt data_store_conn =
455455- match ds with
456456- | Some ds ->
457457- Lwt.return ds
458458- | None ->
459459- Data_store.connect ?write ()
507507+ match ds with Some ds -> Lwt.return ds | None -> Data_store.connect ()
460508 in
461509 let%lwt user_db =
462462- try%lwt User_store.connect ?create ~write:true did
510510+ try%lwt User_store.connect ?create did
463511 with _ ->
464512 Errors.invalid_request ~name:"RepoNotFound"
465513 "your princess is in another castle"
+18-6
pegasus/lib/user_store.ml
···310310311311type t = {did: string; db: Util.caqti_pool}
312312313313-let connect ?create ?write did : t Lwt.t =
314314- let%lwt db =
315315- Util.connect_sqlite ?create ?write (Util.Constants.user_db_location did)
316316- in
317317- let%lwt () = Migrations.run_migrations User_store db in
318318- Lwt.return {did; db}
313313+let pool_cache : (string, t) Hashtbl.t = Hashtbl.create 64
314314+315315+let pool_cache_mutex = Lwt_mutex.create ()
316316+317317+let connect ?create did : t Lwt.t =
318318+ Lwt_mutex.with_lock pool_cache_mutex (fun () ->
319319+ match Hashtbl.find_opt pool_cache did with
320320+ | Some cached ->
321321+ Lwt.return cached
322322+ | None ->
323323+ let%lwt db =
324324+ Util.connect_sqlite ?create ~write:true
325325+ (Util.Constants.user_db_location did)
326326+ in
327327+ let%lwt () = Migrations.run_migrations User_store db in
328328+ let t = {did; db} in
329329+ Hashtbl.replace pool_cache did t ;
330330+ Lwt.return t )
319331320332(* mst blocks; implements Writable_blockstore *)
321333
+24-22
pegasus/lib/util.ml
···183183 | Error caqti_err ->
184184 Error (Caqti_error.Exn caqti_err)
185185186186-let _init_connection conn =
187187- match%lwt
188188- [%rapper
189189- execute
190190- {sql|
191191- PRAGMA journal_mode=WAL;
192192- PRAGMA foreign_keys=ON;
193193- PRAGMA synchronous=NORMAL;
194194- PRAGMA busy_timeout=5000;
195195- |sql}
196196- syntax_off]
197197- () conn
198198- with
199199- | Ok conn ->
200200- Lwt.return conn
201201- | Error e ->
202202- raise (Caqti_error.Exn e)
186186+let _init_connection (module Db : Rapper_helper.CONNECTION) :
187187+ (unit, Caqti_error.t) Lwt_result.t =
188188+ let open Lwt_result.Syntax in
189189+ let open Caqti_request.Infix in
190190+ let open Caqti_type in
191191+ let* _ =
192192+ Db.find (((unit ->! string) ~oneshot:true) "PRAGMA journal_mode=WAL") ()
193193+ in
194194+ let* _ =
195195+ Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA foreign_keys=ON") ()
196196+ in
197197+ let* _ =
198198+ Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA synchronous=NORMAL") ()
199199+ in
200200+ let* _ =
201201+ Db.find (((unit ->! int) ~oneshot:true) "PRAGMA busy_timeout=5000") ()
202202+ in
203203+ Lwt.return_ok ()
203204204205(* creates an sqlite pool *)
205206let connect_sqlite ?(create = false) ?(write = true) db_uri : caqti_pool Lwt.t =
···209210 in
210211 let pool_config = Caqti_pool_config.create ~max_size:16 ~max_idle_size:4 () in
211212 match
212212- Caqti_lwt_unix.connect_pool ~pool_config
213213- ~post_connect:(fun conn -> Lwt_result.ok @@ _init_connection conn)
214214- uri
213213+ Caqti_lwt_unix.connect_pool ~pool_config ~post_connect:_init_connection uri
215214 with
216215 | Ok pool ->
217216 Lwt.return pool
···221220let with_connection db_uri f =
222221 match%lwt
223222 Caqti_lwt_unix.with_connection db_uri (fun conn ->
224224- let%lwt _ = _init_connection conn in
225225- f conn )
223223+ match%lwt _init_connection conn with
224224+ | Ok () ->
225225+ f conn
226226+ | Error e ->
227227+ Lwt.return_error e )
226228 with
227229 | Ok result ->
228230 Lwt.return result