Skip to content

Commit cf25b00

Browse files
authored
CP-310612: optimize get_by_uuid (#6757)
I was profiling XAPI recently and noticed this: <img width="1202" height="834" alt="Screenshot 2025-11-13 at 18 41 38" src="https://github.com/user-attachments/assets/c4828554-d364-459b-9a34-070414d3b146" /> I was fairly sure I fixed it already, and indeed I did back in January, but the commit got lost in my branches and never made it to master. Needs some testing, might've bitrotted, hence the draft PR.
2 parents c4c04e2 + bcf9f19 commit cf25b00

File tree

4 files changed

+85
-24
lines changed

4 files changed

+85
-24
lines changed

ocaml/database/database_test.ml

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ functor
463463
(* reference which we create *)
464464
let valid_ref = "ref1" in
465465
let valid_uuid = "uuid1" in
466+
let new_uuid = "uuid2" in
466467
let invalid_ref = "foo" in
467468
let invalid_uuid = "bar" in
468469
let t =
@@ -626,6 +627,32 @@ functor
626627
"read_field_where <valid table> <valid return> <valid field> <valid \
627628
value>" ;
628629
test_invalid_where_record "read_field_where" (Client.read_field_where t) ;
630+
631+
(* before changing the UUID, the new UUID should be missing *)
632+
expect_missing_uuid "VM" new_uuid (fun () ->
633+
let (_ : string) = Client.db_get_by_uuid t "VM" new_uuid in
634+
()
635+
) ;
636+
(* change UUID, can happen during VM import *)
637+
Client.write_field t "VM" valid_ref Db_names.uuid new_uuid ;
638+
let old_uuid = valid_uuid in
639+
(* new UUID should be found *)
640+
let r = Client.db_get_by_uuid t "VM" new_uuid in
641+
if r <> valid_ref then
642+
failwith_fmt "db_get_by_uuid <new uuid>: got %s; expected %s" r
643+
valid_ref ;
644+
let r = Client.db_get_by_uuid_opt t "VM" new_uuid in
645+
( if r <> Some valid_ref then
646+
let rs = Option.value ~default:"None" r in
647+
failwith_fmt "db_get_by_uuid_opt <new uuid>: got %s; expected %s" rs
648+
valid_ref
649+
) ;
650+
(* old UUID should not be found anymore *)
651+
expect_missing_uuid "VM" old_uuid (fun () ->
652+
let (_ : string) = Client.db_get_by_uuid t "VM" old_uuid in
653+
()
654+
) ;
655+
629656
Printf.printf "write_field <invalid table>\n" ;
630657
expect_missing_tbl "Vm" (fun () ->
631658
let (_ : unit) = Client.write_field t "Vm" "" "" "" in
@@ -842,5 +869,23 @@ functor
842869
)
843870
in
844871
Printf.printf "bad sequence: %.2f calls/sec\n%!" malign_time
845-
)
872+
) ;
873+
Client.delete_row t "VM" valid_ref ;
874+
(* after deleting the row, both old and new uuid must be missing *)
875+
expect_missing_uuid "VM" new_uuid (fun () ->
876+
let (_ : string) = Client.db_get_by_uuid t "VM" new_uuid in
877+
()
878+
) ;
879+
expect_missing_uuid "VM" old_uuid (fun () ->
880+
let (_ : string) = Client.db_get_by_uuid t "VM" old_uuid in
881+
()
882+
) ;
883+
let r = Client.db_get_by_uuid_opt t "VM" old_uuid in
884+
if not (Option.is_none r) then
885+
failwith_fmt "db_get_by_uuid_opt <old uuid>: got %s; expected None"
886+
valid_ref ;
887+
let r = Client.db_get_by_uuid_opt t "VM" new_uuid in
888+
if not (Option.is_none r) then
889+
failwith_fmt "db_get_by_uuid_opt <old uuid>: got %s; expected None"
890+
valid_ref
846891
end

ocaml/database/db_cache_impl.ml

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -277,21 +277,13 @@ let read_field_where' conv t rcd =
277277
let read_field_where t rcd = read_field_where' Fun.id t rcd
278278

279279
let db_get_by_uuid t tbl uuid_val =
280-
match
281-
read_field_where' Schema.CachedValue.string_of t
282-
{
283-
table= tbl
284-
; return= Db_names.ref
285-
; where_field= Db_names.uuid
286-
; where_value= uuid_val
287-
}
288-
with
289-
| [] ->
290-
raise (Read_missing_uuid (tbl, "", uuid_val))
291-
| [r] ->
280+
let db = get_database t in
281+
match Database.lookup_uuid uuid_val db with
282+
| Some (tbl', r) when String.equal tbl tbl' ->
292283
r
293284
| _ ->
294-
raise (Too_many_values (tbl, "", uuid_val))
285+
(* we didn't find the UUID, or it belonged to another table *)
286+
raise (Read_missing_uuid (tbl, "", uuid_val))
295287

296288
let db_get_by_uuid_opt t tbl uuid_val =
297289
match

ocaml/database/db_cache_types.ml

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ module Database = struct
508508

509509
let lookup_key key db = KeyMap.find_opt (Ref key) db.keymap
510510

511+
let lookup_uuid key db = KeyMap.find_opt (Uuid key) db.keymap
512+
511513
let make schema =
512514
{
513515
tables= TableSet.empty
@@ -615,6 +617,33 @@ let update_many_to_many g tblname objref f db =
615617
db
616618
(Schema.many_to_many tblname (Database.schema db))
617619

620+
let uuid_of ~tblname ~objref db =
621+
try
622+
Some
623+
(Schema.Value.Unsafe_cast.string
624+
(Row.find Db_names.uuid
625+
(Table.find objref (TableSet.find tblname (Database.tableset db)))
626+
)
627+
)
628+
with _ -> None
629+
630+
let maybe_update_uuid_keymap ~tblname ~objref ~fldname ~newval db =
631+
if fldname = Db_names.uuid then
632+
db
633+
|> Database.update_keymap @@ fun keymap ->
634+
let keymap =
635+
match uuid_of ~tblname ~objref db with
636+
| None ->
637+
keymap
638+
| Some uuid ->
639+
KeyMap.remove (Uuid uuid) keymap
640+
in
641+
KeyMap.add_unique tblname Db_names.uuid
642+
(Uuid (Schema.Value.Unsafe_cast.string newval))
643+
(tblname, objref) keymap
644+
else
645+
db
646+
618647
let set_field tblname objref fldname newval db =
619648
if fldname = Db_names.ref then
620649
failwith (Printf.sprintf "Cannot safely update field: %s" fldname) ;
@@ -632,6 +661,7 @@ let set_field tblname objref fldname newval db =
632661
if need_other_table_update then
633662
let g = Manifest.generation (Database.manifest db) in
634663
db
664+
|> maybe_update_uuid_keymap ~tblname ~objref ~fldname ~newval
635665
|> update_many_to_many g tblname objref remove_from_set
636666
|> update_one_to_many g tblname objref remove_from_set
637667
|> Database.update
@@ -646,6 +676,7 @@ let set_field tblname objref fldname newval db =
646676
else
647677
let g = Manifest.generation (Database.manifest db) in
648678
db
679+
|> maybe_update_uuid_keymap ~tblname ~objref ~fldname ~newval
649680
|> ((fun _ -> newval)
650681
|> Row.update g fldname empty
651682
|> Table.update g objref Row.empty
@@ -696,16 +727,7 @@ let add_row tblname objref newval db =
696727
|> Database.increment
697728

698729
let remove_row tblname objref db =
699-
let uuid =
700-
try
701-
Some
702-
(Schema.Value.Unsafe_cast.string
703-
(Row.find Db_names.uuid
704-
(Table.find objref (TableSet.find tblname (Database.tableset db)))
705-
)
706-
)
707-
with _ -> None
708-
in
730+
let uuid = uuid_of ~tblname ~objref db in
709731
let g = db.Database.manifest.Manifest.generation_count in
710732
db
711733
|> Database.update_keymap (fun m ->

ocaml/database/db_cache_types.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ module Database : sig
195195

196196
val lookup_key : string -> t -> (string * string) option
197197

198+
val lookup_uuid : string -> t -> (string * string) option
199+
198200
val reindex : t -> t
199201

200202
val register_callback : string -> (update -> t -> unit) -> t -> t

0 commit comments

Comments
 (0)