Skip to content

Commit 4912c21

Browse files
committed
CP-307933: [prepare]: introduce DB_ACCESS2 implementation
No functional change, we still use the Compat module Signed-off-by: Edwin Török <[email protected]>
1 parent 2e86a9b commit 4912c21

10 files changed

+158
-65
lines changed

ocaml/database/database_server_main.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ let remote_database_access_handler_v2 req bio =
3333
flush stdout ;
3434
raise e
3535

36+
open Xapi_database
3637
module Local_tests =
37-
Xapi_database.Database_test.Tests (Xapi_database.Db_cache_impl)
38+
Database_test.Tests (Db_interface_compat.OfCached (Db_cache_impl))
3839

3940
let schema = Test_schemas.schema
4041

ocaml/database/db_cache.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module D = Debug.Make (struct let name = "db_cache" end)
1919
open D
2020

2121
(** Masters will use this to modify the in-memory cache directly *)
22-
module Local_db : DB_ACCESS = Db_cache_impl
22+
module Local_db : DB_ACCESS = Db_interface_compat.OfCached (Db_cache_impl)
2323

2424
(** Slaves will use this to call the master by XMLRPC *)
2525
module Remote_db : DB_ACCESS = Db_rpc_client_v1.Make (struct

ocaml/database/db_cache_impl.ml

+102-51
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ open Db_ref
3636

3737
let fist_delay_read_records_where = ref false
3838

39-
type field_in = string
39+
type field_in = Schema.Value.t
4040

41-
type field_out = string
41+
type field_out = Schema.maybe_cached_value
4242

4343
(* Only needed by the DB_ACCESS signature *)
4444
let initialise () = ()
@@ -53,14 +53,13 @@ let is_valid_ref t objref =
5353

5454
let read_field_internal _ tblname fldname objref db =
5555
try
56-
Row.find fldname
56+
Row.find' fldname
5757
(Table.find objref (TableSet.find tblname (Database.tableset db)))
5858
with Not_found -> raise (DBCache_NotFound ("missing row", tblname, objref))
5959

6060
(* Read field from cache *)
6161
let read_field t tblname fldname objref =
62-
Schema.Value.marshal
63-
(read_field_internal t tblname fldname objref (get_database t))
62+
read_field_internal t tblname fldname objref (get_database t)
6463

6564
(** Finds the longest XML-compatible UTF-8 prefix of the given
6665
string, by truncating the string at the first incompatible
@@ -75,6 +74,8 @@ let ensure_utf8_xml string =
7574
warn "string truncated to: '%s'." prefix ;
7675
prefix
7776

77+
let ensure_utf8_xml_and_share string = string |> ensure_utf8_xml |> Share.merge
78+
7879
(* Write field in cache *)
7980
let write_field_locked t tblname objref fldname newval =
8081
let current_val = get_field tblname objref fldname (get_database t) in
@@ -86,10 +87,6 @@ let write_field_locked t tblname objref fldname newval =
8687
)
8788

8889
let write_field t tblname objref fldname newval =
89-
let schema = Database.schema (get_database t) in
90-
let schema = Schema.table tblname schema in
91-
let column = Schema.Table.find fldname schema in
92-
let newval = Schema.Value.unmarshal column.Schema.Column.ty newval in
9390
let newval =
9491
match newval with
9592
| Schema.Value.String s ->
@@ -114,7 +111,7 @@ let touch_row t tblname objref =
114111
and iterates through set-refs [returning (fieldname, ref list) list; where fieldname is the
115112
name of the Set Ref field in tbl; and ref list is the list of foreign keys from related
116113
table with remote-fieldname=objref] *)
117-
let read_record_internal db tblname objref =
114+
let read_record_internal conv db tblname objref =
118115
try
119116
let tbl = TableSet.find tblname (Database.tableset db) in
120117
let row = Table.find objref tbl in
@@ -138,15 +135,14 @@ let read_record_internal db tblname objref =
138135
| None ->
139136
accum_setref
140137
in
141-
let accum_fvlist =
142-
(k, Schema.CachedValue.string_of cached) :: accum_fvlist
143-
in
138+
let accum_fvlist = (k, conv cached) :: accum_fvlist in
144139
(accum_fvlist, accum_setref)
145140
)
146141
row ([], [])
147142
with Not_found -> raise (DBCache_NotFound ("missing row", tblname, objref))
148143

149-
let read_record t = read_record_internal (get_database t)
144+
let read_record t =
145+
read_record_internal Schema.CachedValue.open_present (get_database t)
150146

151147
(* Delete row from tbl *)
152148
let delete_row_locked t tblname objref =
@@ -177,7 +173,7 @@ let create_row_locked t tblname kvs' new_objref =
177173
let db = get_database t in
178174
let g = Manifest.generation (Database.manifest db) in
179175
let row =
180-
List.fold_left (fun row (k, v) -> Row.add g k v row) Row.empty kvs'
176+
List.fold_left (fun row (k, v) -> Row.add' g k v row) Row.empty kvs'
181177
in
182178
let schema = Schema.table tblname (Database.schema db) in
183179
(* fill in default values if kv pairs for these are not supplied already *)
@@ -195,31 +191,13 @@ let create_row_locked t tblname kvs' new_objref =
195191
(get_database t)
196192

197193
let fld_check t tblname objref (fldname, value) =
198-
let v = read_field_internal t tblname fldname objref (get_database t) in
199-
(v = value, fldname, v)
200-
201-
let create_row t tblname kvs' new_objref =
202-
let schema = Database.schema (get_database t) in
203-
let schema = Schema.table tblname schema in
204-
let kvs' =
205-
List.map
206-
(fun (key, value) ->
207-
let value = ensure_utf8_xml value in
208-
let column = Schema.Table.find key schema in
209-
let newval =
210-
match Schema.Value.unmarshal column.Schema.Column.ty value with
211-
| Schema.Value.String x ->
212-
Schema.Value.String (Share.merge x)
213-
| Schema.Value.Pairs ps ->
214-
Schema.Value.Pairs
215-
(List.map (fun (x, y) -> (Share.merge x, Share.merge y)) ps)
216-
| Schema.Value.Set xs ->
217-
Schema.Value.Set (List.map Share.merge xs)
218-
in
219-
(key, newval)
220-
)
221-
kvs'
194+
let v =
195+
Schema.CachedValue.string_of
196+
(read_field_internal t tblname fldname objref (get_database t))
222197
in
198+
(v = Schema.CachedValue.string_of value, fldname, v)
199+
200+
let create_row' t tblname kvs' new_objref =
223201
with_lock (fun () ->
224202
if is_valid_ref t new_objref then
225203
let uniq_check_list = List.map (fld_check t tblname new_objref) kvs' in
@@ -228,37 +206,69 @@ let create_row t tblname kvs' new_objref =
228206
in
229207
match failure_opt with
230208
| Some (_, f, v) ->
231-
raise (Integrity_violation (tblname, f, Schema.Value.marshal v))
209+
raise (Integrity_violation (tblname, f, v))
232210
| _ ->
233211
()
234212
else
235213
(* we add the reference to the row itself so callers can use read_field_where to
236214
return the reference: awkward if it is just the key *)
237-
let kvs' = (Db_names.ref, Schema.Value.string new_objref) :: kvs' in
215+
let kvs' =
216+
(Db_names.ref, Schema.Value.string new_objref |> Schema.CachedValue.v)
217+
:: kvs'
218+
in
238219
W.debug "create_row %s (%s) [%s]" tblname new_objref
239220
(String.concat ","
240221
(List.map (fun (k, _) -> Printf.sprintf "(%s,v)" k) kvs')
241222
) ;
242223
create_row_locked t tblname kvs' new_objref
243224
)
244225

226+
let create_row t tblname kvs' new_objref =
227+
let kvs' =
228+
List.map
229+
(fun (key, value) ->
230+
let value =
231+
match value with
232+
| Schema.Value.String x ->
233+
Schema.Value.String (ensure_utf8_xml_and_share x)
234+
| Schema.Value.Pairs ps ->
235+
Schema.Value.Pairs
236+
(List.map
237+
(fun (x, y) ->
238+
(ensure_utf8_xml_and_share x, ensure_utf8_xml_and_share y)
239+
)
240+
ps
241+
)
242+
| Schema.Value.Set xs ->
243+
Schema.Value.Set (List.map ensure_utf8_xml_and_share xs)
244+
in
245+
(key, Schema.CachedValue.v value)
246+
)
247+
kvs'
248+
in
249+
create_row' t tblname kvs' new_objref
250+
245251
(* Do linear scan to find field values which match where clause *)
246-
let read_field_where t rcd =
252+
let read_field_where' conv t rcd =
247253
let db = get_database t in
248254
let tbl = TableSet.find rcd.table (Database.tableset db) in
249255
Table.fold
250256
(fun _ _ row acc ->
251-
let field = Schema.Value.marshal (Row.find rcd.where_field row) in
257+
let field =
258+
Schema.CachedValue.string_of (Row.find' rcd.where_field row)
259+
in
252260
if field = rcd.where_value then
253-
Schema.Value.marshal (Row.find rcd.return row) :: acc
261+
conv (Row.find' rcd.return row) :: acc
254262
else
255263
acc
256264
)
257265
tbl []
258266

267+
let read_field_where t rcd = read_field_where' Fun.id t rcd
268+
259269
let db_get_by_uuid t tbl uuid_val =
260270
match
261-
read_field_where t
271+
read_field_where' Schema.CachedValue.string_of t
262272
{
263273
table= tbl
264274
; return= Db_names.ref
@@ -275,7 +285,7 @@ let db_get_by_uuid t tbl uuid_val =
275285

276286
let db_get_by_uuid_opt t tbl uuid_val =
277287
match
278-
read_field_where t
288+
read_field_where' Schema.CachedValue.string_of t
279289
{
280290
table= tbl
281291
; return= Db_names.ref
@@ -290,7 +300,7 @@ let db_get_by_uuid_opt t tbl uuid_val =
290300

291301
(** Return reference fields from tbl that matches specified name_label field *)
292302
let db_get_by_name_label t tbl label =
293-
read_field_where t
303+
read_field_where' Schema.CachedValue.string_of t
294304
{
295305
table= tbl
296306
; return= Db_names.ref
@@ -324,11 +334,14 @@ let find_refs_with_filter_internal db (tblname : Db_interface.table)
324334

325335
let find_refs_with_filter t = find_refs_with_filter_internal (get_database t)
326336

327-
let read_records_where t tbl expr =
337+
let read_records_where' conv t tbl expr =
328338
let db = get_database t in
329339
let reqd_refs = find_refs_with_filter_internal db tbl expr in
330340
if !fist_delay_read_records_where then Thread.delay 0.5 ;
331-
List.map (fun ref -> (ref, read_record_internal db tbl ref)) reqd_refs
341+
List.map (fun ref -> (ref, read_record_internal conv db tbl ref)) reqd_refs
342+
343+
let read_records_where t tbl expr =
344+
read_records_where' Schema.CachedValue.open_present t tbl expr
332345

333346
let process_structured_field_locked t (key, value) tblname fld objref
334347
proc_fn_selector =
@@ -369,8 +382,8 @@ let process_structured_field_locked t (key, value) tblname fld objref
369382
let process_structured_field t (key, value) tblname fld objref proc_fn_selector
370383
=
371384
(* Ensure that both keys and values are valid for UTF-8-encoded XML. *)
372-
let key = ensure_utf8_xml key |> Share.merge in
373-
let value = ensure_utf8_xml value |> Share.merge in
385+
let key = ensure_utf8_xml_and_share key in
386+
let value = ensure_utf8_xml_and_share value in
374387
with_lock (fun () ->
375388
process_structured_field_locked t (key, value) tblname fld objref
376389
proc_fn_selector
@@ -530,3 +543,41 @@ let stats t =
530543
)
531544
(Database.tableset (get_database t))
532545
[]
546+
547+
module Compat = struct
548+
type field_in = string
549+
550+
type field_out = string
551+
552+
let read_field_where t rcd =
553+
read_field_where' Schema.CachedValue.string_of t rcd
554+
555+
let read_field t tblname fldname objref =
556+
read_field t tblname fldname objref |> Schema.CachedValue.string_of
557+
558+
let write_field t tblname objref fldname newval =
559+
let db = get_database t in
560+
let schema = Schema.table tblname (Database.schema db) in
561+
let column = Schema.Table.find fldname schema in
562+
let newval = Schema.Value.unmarshal column.Schema.Column.ty newval in
563+
write_field t tblname objref fldname newval
564+
565+
let read_record t =
566+
read_record_internal Schema.CachedValue.string_of (get_database t)
567+
568+
let read_records_where t tbl expr =
569+
read_records_where' Schema.CachedValue.string_of t tbl expr
570+
571+
let create_row t tblname kvs' new_objref =
572+
let db = get_database t in
573+
let schema = Schema.table tblname (Database.schema db) in
574+
let kvs' =
575+
List.map
576+
(fun (key, value) ->
577+
let column = Schema.Table.find key schema in
578+
(key, Schema.CachedValue.of_typed_string column.Schema.Column.ty value)
579+
)
580+
kvs'
581+
in
582+
create_row' t tblname kvs' new_objref
583+
end

ocaml/database/db_cache_impl.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
include Db_interface.DB_ACCESS
1+
include Db_interface.DB_ACCESS2
22

33
val make : Db_ref.t -> Parse_db_conf.db_connection list -> Schema.t -> unit
44
(** [make t connections default_schema] initialises the in-memory cache *)

ocaml/database/db_cache_types.ml

+4-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ module Row = struct
166166

167167
include Make (CachedValue)
168168

169-
let add gen key v = add gen key @@ CachedValue.v v
169+
let add' = add
170+
171+
let add gen key v = add' gen key @@ CachedValue.v v
170172

171173
type t = map_t
172174

@@ -182,7 +184,7 @@ module Row = struct
182184
update gen key (CachedValue.v default) f row
183185

184186
let find' key t =
185-
try find key t
187+
try find key t |> Schema.CachedValue.open_present
186188
with Not_found -> raise (DBCache_NotFound ("missing field", key, ""))
187189

188190
let find key t = find' key t |> Schema.CachedValue.value_of

ocaml/database/db_cache_types.mli

+8
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@ end
9393
module Row : sig
9494
include MAP with type value = Schema.Value.t
9595

96+
val add' : Time.t -> string -> Schema.cached_value -> t -> t
97+
(** [add now key value map] returns a new map with [key] associated with [value],
98+
with creation time [now] *)
99+
100+
val find' : string -> t -> [> Schema.present] Schema.CachedValue.t
101+
(** [find key t] returns the value associated with [key] in [t] or raises
102+
[DBCache_NotFound] *)
103+
96104
val fold :
97105
(string -> Stat.t -> Schema.cached_value -> 'b -> 'b) -> t -> 'b -> 'b
98106
(** [fold f t initial] folds [f key stats value acc] over the items in [t] *)

ocaml/database/db_remote_cache_access_v1.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ module DBCacheRemoteListener = struct
2828
(* update_lengths xml resp; *)
2929
resp
3030

31-
module DBCache : Db_interface.DB_ACCESS = Db_cache_impl
31+
module DBCache : Db_interface.DB_ACCESS =
32+
Db_interface_compat.OfCached (Db_cache_impl)
3233

3334
(** Unmarshals the request, calls the DBCache function and marshals the result.
3435
Note that, although the messages still contain the pool_secret for historical reasons,

ocaml/database/db_remote_cache_access_v2.ml

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ open Db_exn
1919

2020
(** Convert a marshalled Request Rpc.t into a marshalled Response Rpc.t *)
2121
let process_rpc (req : Rpc.t) =
22-
let module DB : Db_interface.DB_ACCESS = Db_cache_impl in
22+
let module DB : Db_interface.DB_ACCESS =
23+
Db_interface_compat.OfCached (Db_cache_impl) in
2324
let t = Db_backend.make () in
2425
Response.rpc_of_t
2526
( try

ocaml/database/schema.ml

+12
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ module CachedValue = struct
115115
v
116116
| `Absent ->
117117
Value.unmarshal ty t.marshalled
118+
119+
let of_typed_string ty marshalled =
120+
let v = Value.unmarshal ty marshalled in
121+
{v= `Present v; marshalled}
122+
123+
let maybe_unmarshal ty = function
124+
| {v= `Present _; _} as p ->
125+
p
126+
| {v= `Absent; marshalled} ->
127+
of_typed_string ty marshalled
128+
129+
let open_present ({v= `Present _; _} as t) = t
118130
end
119131

120132
type cached_value = present CachedValue.t

0 commit comments

Comments
 (0)