From 39012da6ad162869d004ac24c3378d6cbcdb1d6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulysse=20G=C3=A9rard?= Date: Mon, 19 Aug 2024 22:12:24 +0200 Subject: [PATCH] wip: clear view cache on server update --- bin/db_worker/db_worker.ml | 120 +++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/bin/db_worker/db_worker.ml b/bin/db_worker/db_worker.ml index c7ef045..8839b27 100644 --- a/bin/db_worker/db_worker.ml +++ b/bin/db_worker/db_worker.ml @@ -23,9 +23,19 @@ let fut_of_array (fs : 'a Fut.t array) : 'a array Fut.t = Obj.magic @@ fut @@ Jv.Promise.bind all to_array module Worker () = struct + let view_memo : + ( string Db.View.selection * Db.View.Sort.t, + IS.Content.Key.t array ) + Hashtbl.t = + Hashtbl.create 64 + + let last_view : (int * IS.Content.Key.t array) ref = ref (-1, [||]) + let check_db idb source = let server_id, source = source in let report status = + Hashtbl.clear view_memo; + last_view := (-1, [||]); dispatch_event Servers_status_update (server_id, status) in Db.Sync.check_and_sync ~report ~source idb @@ -44,66 +54,58 @@ module Worker () = struct IDB.Database.transaction [ (module Db.I) ] ~mode:Readonly idb |> IDB.Transaction.object_store (module Db.I) - let get_view_keys = - let view_memo : - ( string Db.View.selection * Db.View.Sort.t, - IS.Content.Key.t array ) - Hashtbl.t = - Hashtbl.create 64 - in - let last_view : (int * IS.Content.Key.t array) ref = ref (-1, [||]) in - fun store { Db.View.kind = _; src_views; sort; filters } -> - (* todo: staged memoization + specialized queries using indexes *) - let open Fut.Result_syntax in - let hash = Hashtbl.hash (src_views, sort, filters) in - if Int.equal (fst !last_view) hash then Fut.ok (snd !last_view) - else - let+ keys = - try Fut.ok @@ Hashtbl.find view_memo (src_views, sort) - with Not_found -> - let+ all_keys = - let lower = Jv.of_array Jv.of_string [| "Audio" |] in - let upper = Jv.of_array Jv.of_string [| "Audio\u{0}" |] in - let query = - IDB.Key_range.bound ~lower ~upper ~lower_open:true - ~upper_open:false () - in - let idx = IS.index (module IS.Index.Kind_View) store in - IS.Index.Kind_View.get_all_keys ~query idx |> as_fut - in - let keys = - match src_views with - | All -> all_keys - | Only src_views -> - Array.filter all_keys - ~f:(fun { Db.Stores.Items.Key.views; _ } -> - List.exists views ~f:(fun v -> List.memq v ~set:src_views)) + let get_view_keys store { Db.View.kind = _; src_views; sort; filters } = + (* todo: staged memoization + specialized queries using indexes *) + let open Fut.Result_syntax in + let hash = Hashtbl.hash (src_views, sort, filters) in + if Int.equal (fst !last_view) hash then Fut.ok (snd !last_view) + else + let+ keys = + try Fut.ok @@ Hashtbl.find view_memo (src_views, sort) + with Not_found -> + let+ all_keys = + let lower = Jv.of_array Jv.of_string [| "Audio" |] in + let upper = Jv.of_array Jv.of_string [| "Audio\u{0}" |] in + let query = + IDB.Key_range.bound ~lower ~upper ~lower_open:true + ~upper_open:false () in - Hashtbl.add view_memo (src_views, sort) keys; - keys - in - let keys = - match filters with - | [ Search sub ] when not (String.is_empty sub) -> - let sub = String.lowercase_ascii sub in - Array.filter keys ~f:(fun { Db.Stores.Items.Key.sort_name; _ } -> - let sort_name = String.lowercase_ascii sort_name in - let pattern = String.Find.compile (Printf.sprintf "%s" sub) in - String.Find.find ~pattern sort_name >= 0) - | _ -> keys - in - let () = - match sort with - | Name -> - Array.sort keys - ~cmp:(fun - { Db.Stores.Items.Key.sort_name = sna; _ } - { Db.Stores.Items.Key.sort_name = snb; _ } - -> String.compare sna snb) - | _ -> () - in - last_view := (hash, keys); - keys + let idx = IS.index (module IS.Index.Kind_View) store in + IS.Index.Kind_View.get_all_keys ~query idx |> as_fut + in + let keys = + match src_views with + | All -> all_keys + | Only src_views -> + Array.filter all_keys + ~f:(fun { Db.Stores.Items.Key.views; _ } -> + List.exists views ~f:(fun v -> List.memq v ~set:src_views)) + in + Hashtbl.add view_memo (src_views, sort) keys; + keys + in + let keys = + match filters with + | [ Search sub ] when not (String.is_empty sub) -> + let sub = String.lowercase_ascii sub in + Array.filter keys ~f:(fun { Db.Stores.Items.Key.sort_name; _ } -> + let sort_name = String.lowercase_ascii sort_name in + let pattern = String.Find.compile (Printf.sprintf "%s" sub) in + String.Find.find ~pattern sort_name >= 0) + | _ -> keys + in + let () = + match sort with + | Name -> + Array.sort keys + ~cmp:(fun + { Db.Stores.Items.Key.sort_name = sna; _ } + { Db.Stores.Items.Key.sort_name = snb; _ } + -> String.compare sna snb) + | _ -> () + in + last_view := (hash, keys); + keys let on_query (type a) (q : a query) : (a, error) Fut.result = let open Fut.Result_syntax in