]> xenbits.xensource.com Git - xcp/xen-api.git/commitdiff
Always regenerate the 'many' side of a 'one-to-many' relationship at indexing time...
authorDavid Scott <dave.scott@eu.citrix.com>
Wed, 26 Jan 2011 17:39:05 +0000 (17:39 +0000)
committerDavid Scott <dave.scott@eu.citrix.com>
Wed, 26 Jan 2011 17:39:05 +0000 (17:39 +0000)
Signed-off-by: David Scott <dave.scott@eu.citrix.com>
ocaml/database/database_test.ml
ocaml/database/db_backend.ml
ocaml/database/db_cache_types.ml
ocaml/database/schema.ml

index c73dddd9c6a797923c3c76937581446637e365e6..3a35073a40e4cd5e9c9d643ca8d42cfdf4b90514 100644 (file)
@@ -361,8 +361,10 @@ module Tests = functor(Client: Db_interface.DB_ACCESS) -> struct
                Printf.printf "read_record <valid table> <valid ref> foreign key\n";
                Client.create_row "VBD" (make_vbd valid_ref vbd_ref vbd_uuid) vbd_ref;
                let fv_list, fvs_list = Client.read_record "VM" valid_ref in
-               if List.assoc "VBDs" fvs_list <> [ vbd_ref ]
-               then failwith "read_record <valid table> <valid ref> 3";
+               if List.assoc "VBDs" fvs_list <> [ vbd_ref ] then begin
+                       Printf.printf "fv_list = [ %s ] fvs_list = [ %s ]\n%!" (String.concat "; " (List.map (fun (k, v) -> k ^":" ^ v) fv_list))  (String.concat "; " (List.map (fun (k, v) -> k ^ ":" ^ (String.concat ", " v)) fvs_list));
+                       failwith "read_record <valid table> <valid ref> 3"
+               end;
                Printf.printf "read_record <valid table> <valid ref> deleted foreign key\n";
                Client.delete_row "VBD" vbd_ref;
                let fv_list, fvs_list = Client.read_record "VM" valid_ref in
index ea71000e654138139e2140a7cd825e820c3e943a..46262df33fbc876d2eb83c546c872a95244f7ff9 100644 (file)
@@ -42,7 +42,6 @@ let get_database () = !database
 (* non-persistent fields will have been flushed to disk anyway [since non-persistent just means dont trigger a flush
    if I change]. Hence we blank non-persistent fields with a suitable empty value, depending on their type *)
 let blow_away_non_persistent_fields (schema: Schema.t) db =
-       Printf.printf "blow_away\n%!";
        (* Generate a new row given a table schema *)
        let row schema row : Row.t =
                Row.fold 
index 28c37989cfa2a8b2d714700f6033cd7200e89024..197812b73b8c9e9909326035682c181b11364c41 100644 (file)
@@ -222,8 +222,47 @@ module Database = struct
                                                ) 
                                                tbl acc)
                                x.tables KeyMap.empty in
+               (* For each of the one-to-many relationships, recompute the many end *)
+               let tables = 
+                       Schema.StringMap.fold
+                               (fun one_tblname rels tables ->
+                                       List.fold_left (fun tables (one_fldname, many_tblname, many_fldname) ->
+                                               (* VBD.VM : Ref(VM) -> VM.VBDs : Set(Ref(VBD)) *)
+                                               let one_tbl = TableSet.find one_tblname tables in
+                                               let many_tbl = TableSet.find many_tblname tables in
+                                               (* Initialise all VM.VBDs = [] (otherwise VMs with no 
+                                                  VBDs may be missing a VBDs field altogether on
+                                                  upgrade) *)
+                                               let many_tbl' = Table.fold
+                                                       (fun vm row acc ->
+                                                               let row' = Row.add many_fldname (SExpr.string_of (SExpr.Node [])) row in
+                                                               Table.add vm row' acc)
+                                                       many_tbl Table.empty in
+
+                                               (* Build up a table of VM -> VBDs *)
+
+                                               let vm_to_vbds = Table.fold
+                                                       (fun vbd row acc ->
+                                                               let vm = Row.find one_fldname row in
+                                                               let existing = if Schema.StringMap.mem vm acc then Schema.StringMap.find vm acc else [] in
+                                                               Schema.StringMap.add vm (vbd :: existing) acc)
+                                                       one_tbl Schema.StringMap.empty in
+                                               let many_tbl'' = Schema.StringMap.fold
+                                                       (fun vm vbds acc ->
+                                                               if not(Table.mem vm acc)
+                                                               then acc
+                                                               else
+                                                                       let row = Table.find vm acc in
+                                                                       let vbds' = SExpr.string_of (SExpr.Node (List.map (fun x -> SExpr.String x) vbds)) in
+                                                                       let row' = Row.add many_fldname vbds' row in
+                                                                       Table.add vm row' acc)
+                                                       vm_to_vbds many_tbl' in
+                                               TableSet.add many_tblname many_tbl'' tables)
+                                               tables rels)
+                               x.schema.Schema.one_to_many
+                               x.tables in
                
-               { x with keymap = keymap }
+               { x with keymap = keymap; tables = tables }
 
 
        let table_of_ref rf db = fst (KeyMap.find (Ref rf) db.keymap)
index 5e8df5dc3958bcdf104ad5a64436e0b101fc7c26..2818e3f179d05a60912c6c3c7eda8eaa27b05ecc 100644 (file)
@@ -84,20 +84,22 @@ let of_datamodel () =
                                [] -> acc
                        | (Datamodel_types.Field f)::fs -> flatten_fields fs (f::acc)
                        | (Datamodel_types.Namespace (_,internal_fs))::fs -> flatten_fields fs (flatten_fields internal_fs acc) in
-       let column f = {
-               Column.name = Escaping.escape_id f.Datamodel_types.full_name;
-               persistent = f.Datamodel_types.field_persist;
-               empty = Datamodel_values.gen_empty_db_val f.Datamodel_types.ty;
-               (* NB Set(Ref _) fields aren't allowed to have a default value specified so we hardcode one here *)
-               default = begin match f.Datamodel_types.ty with
-                       | Datamodel_types.Set (Datamodel_types.Ref _) -> Some (SExpr.string_of (SExpr.Node []))
-                       | _ -> Opt.map Datamodel_values.to_db_string f.Datamodel_types.default_value
-               end ;
-               issetref = begin match f.Datamodel_types.ty with
+       let column f = 
+               let issetref = match f.Datamodel_types.ty with
                        | Datamodel_types.Set (Datamodel_types.Ref _) -> true
-                       | _ -> false
-               end ;
-       } in
+                       | _ -> false in 
+               {
+                       Column.name = Escaping.escape_id f.Datamodel_types.full_name;
+                       (* NB we always regenerate Set(Ref _) fields *)
+                       persistent = f.Datamodel_types.field_persist && not issetref;
+                       empty = Datamodel_values.gen_empty_db_val f.Datamodel_types.ty;
+                       (* NB Set(Ref _) fields aren't allowed to have a default value specified so we hardcode one here *)
+                       default = 
+                               if issetref 
+                               then Some (SExpr.string_of (SExpr.Node []))
+                               else Opt.map Datamodel_values.to_db_string f.Datamodel_types.default_value ;
+                       issetref = issetref;
+               } in
 
        (* We store the reference in two places for no good reason still: *)
        let _ref = {