diff --git a/.depend b/.depend
index 1cc0c9b..6dffdb0 100644
--- a/.depend
+++ b/.depend
@@ -1,65 +1,71 @@
-./coinst_common.cmi: repository.cmi quotient.cmi api.cmi
-./conflicts.cmo: repository.cmi quotient.cmi
-./conflicts.cmx: repository.cmx quotient.cmx
+./upgrade.cmo: util.cmi upgrade_common.cmi quotient.cmi graph.cmi file.cmi \
+ deb_lib.cmi
+./upgrade.cmx: util.cmx upgrade_common.cmx quotient.cmx graph.cmx file.cmx \
+ deb_lib.cmx
+./quotient.cmi: repository.cmi
+./common.cmo: util.cmi ./common.cmi
+./common.cmx: util.cmx ./common.cmi
+./upgrade_common.cmi: repository.cmi deb_lib.cmi
./cudf_lib.cmi: api.cmi
-./rpm_lib.cmo: util.cmi solver.cmi common.cmi ./rpm_lib.cmi
-./rpm_lib.cmx: util.cmx solver.cmx common.cmx ./rpm_lib.cmi
-./task.cmo:
-./task.cmx:
+./bytearray.cmi:
./file.cmo: ./file.cmi
./file.cmx: ./file.cmi
-./debug.cmo: ./debug.cmi
-./debug.cmx: ./debug.cmi
-./comp.cmo: deb_lib.cmi
-./comp.cmx: deb_lib.cmx
-./upgrade_common.cmi: repository.cmi deb_lib.cmi
-./solver.cmi:
-./dgraph.cmo: ./dgraph.cmi
-./dgraph.cmx: ./dgraph.cmi
-./file.cmi:
-./util.cmo: ./util.cmi
-./util.cmx: ./util.cmi
-./debug.cmi:
-./graph.cmo: repository.cmi quotient.cmi conflicts.cmo ./graph.cmi
-./graph.cmx: repository.cmx quotient.cmx conflicts.cmx ./graph.cmi
-./api.cmi: solver.cmi
-./quotient.cmi: repository.cmi
-./rpm_lib.cmi: api.cmi
-./util.cmi:
+./coinst_common.cmi: repository.cmi quotient.cmi api.cmi
./main.cmo: util.cmi rpm_lib.cmi repository.cmi quotient.cmi graph.cmi \
file.cmi deb_lib.cmi api.cmi
./main.cmx: util.cmx rpm_lib.cmx repository.cmx quotient.cmx graph.cmx \
file.cmx deb_lib.cmx api.cmx
-./upgrade.cmo: util.cmi upgrade_common.cmi quotient.cmi graph.cmi file.cmi \
- deb_lib.cmi
-./upgrade.cmx: util.cmx upgrade_common.cmx quotient.cmx graph.cmx file.cmx \
- deb_lib.cmx
-./coinst_common.cmo: repository.cmi quotient.cmi api.cmi ./coinst_common.cmi
-./coinst_common.cmx: repository.cmx quotient.cmx api.cmx ./coinst_common.cmi
-./quotient.cmo: util.cmi repository.cmi ./quotient.cmi
-./quotient.cmx: util.cmx repository.cmx ./quotient.cmi
-./api.cmo: solver.cmi ./api.cmi
-./api.cmx: solver.cmx ./api.cmi
-./upgrade_common.cmo: util.cmi graph.cmi deb_lib.cmi coinst_common.cmi \
- ./upgrade_common.cmi
-./upgrade_common.cmx: util.cmx graph.cmx deb_lib.cmx coinst_common.cmx \
- ./upgrade_common.cmi
+./debug.cmo: ./debug.cmi
+./debug.cmx: ./debug.cmi
+./repository.cmi: util.cmi api.cmi
./deb_lib.cmo: util.cmi solver.cmi common.cmi ./deb_lib.cmi
./deb_lib.cmx: util.cmx solver.cmx common.cmx ./deb_lib.cmi
-./common.cmi:
-./repository.cmo: util.cmi api.cmi ./repository.cmi
-./repository.cmx: util.cmx api.cmx ./repository.cmi
+./rpm_lib.cmi: api.cmi
+./util.cmi:
+./dgraph.cmi:
./solver.cmo: ./solver.cmi
./solver.cmx: ./solver.cmi
+./rpm_lib.cmo: util.cmi solver.cmi common.cmi ./rpm_lib.cmi
+./rpm_lib.cmx: util.cmx solver.cmx common.cmx ./rpm_lib.cmi
+./quotient.cmo: util.cmi repository.cmi ./quotient.cmi
+./quotient.cmx: util.cmx repository.cmx ./quotient.cmi
+./debug.cmi:
+./bytearray.cmo: ./bytearray.cmi
+./bytearray.cmx: ./bytearray.cmi
+./parallel.cmo: task.cmi file.cmi deb_lib.cmi
+./parallel.cmx: task.cmx file.cmx deb_lib.cmx
+./file.cmi:
+./api.cmo: solver.cmi ./api.cmi
+./api.cmx: solver.cmx ./api.cmi
+./conflicts.cmo: repository.cmi quotient.cmi
+./conflicts.cmx: repository.cmx quotient.cmx
+./coinst_common.cmo: repository.cmi quotient.cmi debug.cmi api.cmi \
+ ./coinst_common.cmi
+./coinst_common.cmx: repository.cmx quotient.cmx debug.cmx api.cmx \
+ ./coinst_common.cmi
+./graph.cmi: repository.cmi quotient.cmi
./cudf_lib.cmo: solver.cmi common.cmi ./cudf_lib.cmi
./cudf_lib.cmx: solver.cmx common.cmx ./cudf_lib.cmi
-./common.cmo: util.cmi ./common.cmi
-./common.cmx: util.cmx ./common.cmi
-./transition.cmo: util.cmi upgrade_common.cmi repository.cmi file.cmi \
- debug.cmi deb_lib.cmi
-./transition.cmx: util.cmx upgrade_common.cmx repository.cmx file.cmx \
- debug.cmx deb_lib.cmx
+./task.cmi:
+./api.cmi: solver.cmi
+./upgrade_common.cmo: util.cmi graph.cmi debug.cmi deb_lib.cmi \
+ coinst_common.cmi ./upgrade_common.cmi
+./upgrade_common.cmx: util.cmx graph.cmx debug.cmx deb_lib.cmx \
+ coinst_common.cmx ./upgrade_common.cmi
+./task.cmo: util.cmi debug.cmi bytearray.cmi ./task.cmi
+./task.cmx: util.cmx debug.cmx bytearray.cmx ./task.cmi
./deb_lib.cmi: util.cmi solver.cmi api.cmi
-./graph.cmi: repository.cmi quotient.cmi
-./repository.cmi: util.cmi api.cmi
-./dgraph.cmi:
+./repository.cmo: util.cmi api.cmi ./repository.cmi
+./repository.cmx: util.cmx api.cmx ./repository.cmi
+./dgraph.cmo: ./dgraph.cmi
+./dgraph.cmx: ./dgraph.cmi
+./util.cmo: ./util.cmi
+./util.cmx: ./util.cmi
+./common.cmi:
+./graph.cmo: repository.cmi quotient.cmi conflicts.cmo ./graph.cmi
+./graph.cmx: repository.cmx quotient.cmx conflicts.cmx ./graph.cmi
+./solver.cmi:
+./transition.cmo: util.cmi upgrade_common.cmi task.cmi repository.cmi \
+ file.cmi debug.cmi deb_lib.cmi
+./transition.cmx: util.cmx upgrade_common.cmx task.cmx repository.cmx \
+ file.cmx debug.cmx deb_lib.cmx
diff --git a/Makefile b/Makefile
index 529f3b2..05b67d2 100644
--- a/Makefile
+++ b/Makefile
@@ -3,13 +3,13 @@ COINST=coinst
UPGRADE=upgrade
TRANS=transition
-
OCAMLC=ocamlfind ocamlc
OCAMLOPT=ocamlfind ocamlopt
OCAMLDEP=ocamldep
-OBJS = util.cmx file.cmx debug.cmx common.cmx dgraph.cmx solver.cmx api.cmx deb_lib.cmx rpm_lib.cmx repository.cmx quotient.cmx conflicts.cmx graph.cmx coinst_common.cmx
-COMPFLAGS=-package unix,str
+TASK = bytearray_stubs.o bytearray.cmx task_stubs.o task.cmx
+OBJS = util.cmx file.cmx debug.cmx common.cmx solver.cmx api.cmx deb_lib.cmx rpm_lib.cmx repository.cmx quotient.cmx conflicts.cmx graph.cmx coinst_common.cmx
+COMPFLAGS=-package unix,str,bigarray -g
OPTLINKFLAGS=$(COMPFLAGS) -linkpkg
all: $(COINST) $(UPGRADE) $(TRANS)
@@ -23,7 +23,7 @@ $(COINST).byte: $(OBJS:.cmx=.cmo) main.cmo
$(UPGRADE): $(OBJS) upgrade_common.cmx upgrade.cmx
$(OCAMLOPT) -o $@ $(OPTLINKFLAGS) $^ $(LINKFLAGS)
-$(TRANS): $(OBJS) upgrade_common.cmx transition.cmx
+$(TRANS): $(OBJS) $(TASK) upgrade_common.cmx transition.cmx
$(OCAMLOPT) -o $@ $(OPTLINKFLAGS) $^ $(LINKFLAGS)
clean::
diff --git a/bytearray.ml b/bytearray.ml
new file mode 100644
index 0000000..3a01ead
--- /dev/null
+++ b/bytearray.ml
@@ -0,0 +1,97 @@
+(* Unison file synchronizer: src/bytearray.ml *)
+(* Copyright 1999-2010, Benjamin C. Pierce
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*)
+
+open Bigarray
+
+type t = (char, int8_unsigned_elt, c_layout) Array1.t
+
+let length = Bigarray.Array1.dim
+
+let create l = Bigarray.Array1.create Bigarray.char Bigarray.c_layout l
+
+(*
+let unsafe_blit_from_string s i a j l =
+ for k = 0 to l - 1 do
+ a.{j + k} <- s.[i + k]
+ done
+
+let unsafe_blit_to_string a i s j l =
+ for k = 0 to l - 1 do
+ s.[j + k] <- a.{i + k}
+ done
+*)
+
+external unsafe_blit_from_string : string -> int -> t -> int -> int -> unit
+ = "ml_blit_string_to_bigarray" "noalloc"
+
+external unsafe_blit_to_string : t -> int -> string -> int -> int -> unit
+ = "ml_blit_bigarray_to_string" "noalloc"
+
+let to_string a =
+ let l = length a in
+ if l > Sys.max_string_length then invalid_arg "Bytearray.to_string" else
+ let s = String.create l in
+ unsafe_blit_to_string a 0 s 0 l;
+ s
+
+let of_string s =
+ let l = String.length s in
+ let a = create l in
+ unsafe_blit_from_string s 0 a 0 l;
+ a
+
+let sub a ofs len =
+ if
+ ofs < 0 || len < 0 || ofs > length a - len || len > Sys.max_string_length
+ then
+ invalid_arg "Bytearray.sub"
+ else begin
+ let s = String.create len in
+ unsafe_blit_to_string a ofs s 0 len;
+ s
+ end
+
+let rec prefix_rec a i a' i' l =
+ l = 0 ||
+ (a.{i} = a'.{i'} && prefix_rec a (i + 1) a' (i' + 1) (l - 1))
+
+let prefix a a' i =
+ let l = length a in
+ let l' = length a' in
+ i <= l' - l &&
+ prefix_rec a 0 a' i l
+
+let blit_from_string s i a j l =
+ if l < 0 || i < 0 || i > String.length s - l
+ || j < 0 || j > length a - l
+ then invalid_arg "Bytearray.blit_from_string"
+ else unsafe_blit_from_string s i a j l
+
+let blit_to_string a i s j l =
+ if l < 0 || i < 0 || i > length a - l
+ || j < 0 || j > String.length s - l
+ then invalid_arg "Bytearray.blit_to_string"
+ else unsafe_blit_to_string a i s j l
+
+external marshal : 'a -> Marshal.extern_flags list -> t
+ = "ml_marshal_to_bigarray"
+
+external marshal_to_buffer : t -> int -> 'a -> Marshal.extern_flags list -> int
+ = "ml_marshal_to_bigarray_buffer"
+
+external unmarshal : t -> int -> 'a
+ = "ml_unmarshal_from_bigarray"
diff --git a/bytearray.mli b/bytearray.mli
new file mode 100644
index 0000000..74532b2
--- /dev/null
+++ b/bytearray.mli
@@ -0,0 +1,27 @@
+(* Unison file synchronizer: src/bytearray.mli *)
+(* Copyright 1999-2010, Benjamin C. Pierce (see COPYING for details) *)
+
+type t =
+ (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
+
+val create : int -> t
+
+val length : t -> int
+
+val to_string : t -> string
+
+val of_string : string -> t
+
+val sub : t -> int -> int -> string
+
+val blit_from_string : string -> int -> t -> int -> int -> unit
+
+val blit_to_string : t -> int -> string -> int -> int -> unit
+
+val prefix : t -> t -> int -> bool
+
+val marshal : 'a -> Marshal.extern_flags list -> t
+
+val unmarshal : t -> int -> 'a
+
+val marshal_to_buffer : t -> int -> 'a -> Marshal.extern_flags list -> int
diff --git a/bytearray_stubs.c b/bytearray_stubs.c
new file mode 100644
index 0000000..5cb8930
--- /dev/null
+++ b/bytearray_stubs.c
@@ -0,0 +1,52 @@
+/* Unison file synchronizer: src/bytearray_stubs.c */
+/* Copyright 1999-2010 (see COPYING for details) */
+
+#include
+
+#include "caml/intext.h"
+#include "caml/bigarray.h"
+
+#define Array_data(a, i) (((char *) a->data) + Long_val(i))
+
+CAMLprim value ml_marshal_to_bigarray(value v, value flags)
+{
+ char *buf;
+ long len;
+ output_value_to_malloc(v, flags, &buf, &len);
+ return alloc_bigarray(BIGARRAY_UINT8 | BIGARRAY_C_LAYOUT | BIGARRAY_MANAGED,
+ 1, buf, &len);
+}
+
+CAMLprim value ml_marshal_to_bigarray_buffer(value b, value ofs,
+ value v, value flags)
+{
+ struct caml_bigarray *b_arr = Bigarray_val(b);
+ return Val_long(caml_output_value_to_block(v, flags, Array_data (b_arr, ofs),
+ b_arr->dim[0] - Long_val(ofs)));
+}
+
+
+CAMLprim value ml_unmarshal_from_bigarray(value b, value ofs)
+{
+ struct caml_bigarray *b_arr = Bigarray_val(b);
+ return input_value_from_block (Array_data (b_arr, ofs),
+ b_arr->dim[0] - Long_val(ofs));
+}
+
+CAMLprim value ml_blit_string_to_bigarray
+(value s, value i, value a, value j, value l)
+{
+ char *src = String_val(s) + Int_val(i);
+ char *dest = Array_data(Bigarray_val(a), j);
+ memcpy(dest, src, Long_val(l));
+ return Val_unit;
+}
+
+CAMLprim value ml_blit_bigarray_to_string
+(value a, value i, value s, value j, value l)
+{
+ char *src = Array_data(Bigarray_val(a), i);
+ char *dest = String_val(s) + Long_val(j);
+ memcpy(dest, src, Long_val(l));
+ return Val_unit;
+}
diff --git a/deb_lib.ml b/deb_lib.ml
index a46dd9f..d30ea27 100644
--- a/deb_lib.ml
+++ b/deb_lib.ml
@@ -981,6 +981,13 @@ let only_latest pool' =
pool'.packages_by_name;
pool
+let copy pool =
+ { size = pool.size;
+ packages = Hashtbl.copy pool.packages;
+ packages_by_name = ListTbl.copy pool.packages_by_name;
+ packages_by_num = Hashtbl.copy pool.packages_by_num;
+ provided_packages = ListTbl.copy pool.provided_packages }
+
let merge pool filter pool' =
Hashtbl.iter
(fun _ p ->
diff --git a/deb_lib.mli b/deb_lib.mli
index ae12b32..ed625fc 100644
--- a/deb_lib.mli
+++ b/deb_lib.mli
@@ -61,6 +61,7 @@ val resolve_package_dep_raw :
val only_latest : pool -> pool
+val copy : pool -> pool
val merge : pool -> (int -> bool) -> pool -> unit
val merge2 : pool -> (p -> bool) -> pool -> unit
val add_package : pool -> p -> int
diff --git a/task.ml b/task.ml
new file mode 100644
index 0000000..cddb6d8
--- /dev/null
+++ b/task.ml
@@ -0,0 +1,225 @@
+(* Co-installability tools
+ * http://coinst.irill.org/
+ * Copyright (C) 2011 Jérôme Vouillon
+ * Laboratoire PPS - CNRS Université Paris Diderot
+ *
+ * These programs are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *)
+
+(*
+TODO:
+- error handling
+- clear marshalled when large
+*)
+
+let debug_task = Debug.make "tasks" "debug client/server communication" []
+
+module Utimer = Util.Utimer
+
+type stats =
+ { mutable marshal_time : float;
+ mutable unmarshal_time : float }
+
+let stats = { marshal_time = 0.; unmarshal_time = 0. }
+let side = ref "SRV"
+
+type indirect =
+ { pipe_in : Unix.file_descr;
+ pipe_out : Unix.file_descr;
+ mem : Bytearray.t;
+ pid : int }
+
+type 'a t = Local of 'a | Remote of indirect
+
+type 'a future_state = Running of indirect | Finished of 'a
+
+type 'a future = 'a future_state ref
+
+let mem_size = 1 lsl 24
+
+external processor_count : unit -> int = "task_processor_count"
+
+let proc_count = ref (processor_count ())
+
+let get_processor_count () = !proc_count
+let set_processor_count n = proc_count := if n < 1 then 1 else n
+
+let function_count = ref 0
+let functions = Hashtbl.create 17
+
+let send pipe i l =
+ let s = Printf.sprintf "%d %d\n" i l in
+ ignore (Unix.write pipe s 0 (String.length s))
+
+let receive pipe =
+ let s = String.create 50 in
+ let len = Unix.read pipe s 0 (String.length s) in
+ if len = 0 then exit 0;
+ Scanf.sscanf s "%d %d" (fun i l -> (i, l))
+
+let read mem l =
+ let t = Utimer.start () in
+ let res = Bytearray.unmarshal mem 0 in (*XXX Clear the data if large*)
+ let dt = Utimer.stop t in
+ stats.unmarshal_time <- stats.unmarshal_time +. dt;
+ if debug_task () then Format.eprintf "Unmarshal: %s %f (%d)@." !side dt l;
+ res
+
+let write mem v =
+ let t = Utimer.start () in
+ let res = Bytearray.marshal_to_buffer mem 0 v [] in
+ let dt = Utimer.stop t in
+ stats.marshal_time <- stats.marshal_time +. dt;
+ if debug_task () then Format.eprintf "Marshal: %s %f (%d)@." !side dt res;
+ res
+
+let funct f =
+ let i = !function_count in
+ incr function_count;
+ Hashtbl.add functions i
+ (fun st mem l -> write mem (f (Obj.obj st) (read mem l)));
+ fun st x ->
+ match st with
+ Local st ->
+ ref (Finished (f st x))
+ | Remote st ->
+ send st.pipe_out i (write st.mem x);
+ ref (Running st)
+
+let _ =
+at_exit (fun _ ->
+if debug_task () then
+ Format.eprintf "===>> marshal: %f / unmarshal: %f@."
+ stats.marshal_time stats.unmarshal_time)
+
+let spawn f =
+ if !proc_count <= 1 then
+ Local (f ())
+ else begin
+ let (cr, sw) = Unix.pipe () in
+ let (sr, cw) = Unix.pipe () in
+ let fd = Unix.openfile "/dev/zero" [Unix.O_RDWR] 0 in
+ let mem =
+ Bigarray.Array1.map_file
+ fd Bigarray.char Bigarray.c_layout true mem_size
+ in
+ Unix.close fd;
+ match Unix.fork () with
+ 0 ->
+ Unix.close sr; Unix.close sw;
+ stats.marshal_time <- 0.; stats.unmarshal_time <- 0.;
+ side := "CLI";
+ let st = Obj.repr (f ()) in
+ let rec loop () =
+ let (i, l) = receive cr in
+ if i < 0 then
+ exit 0
+ else begin
+ let f = Hashtbl.find functions i in
+ let l = f st mem l in
+ send cw 0 l;
+ loop ()
+ end
+ in
+ loop ()
+ | pid ->
+ Unix.close cr; Unix.close cw;
+ Remote { pipe_in = sr; pipe_out = sw; mem = mem; pid = pid }
+ end
+
+let kill st =
+ match st with
+ Local _ ->
+ ()
+ | Remote st ->
+ send st.pipe_out (-1) 0;
+ Unix.close st.pipe_in; Unix.close st.pipe_out;
+ (*XXX Clear mmapped memory *)
+ ignore (Unix.waitpid [] st.pid)
+
+let wait fut =
+ match !fut with
+ Finished v ->
+ v
+ | Running st ->
+ let t = Unix.gettimeofday () in
+ let (i, l) = receive st.pipe_in in
+ if debug_task () then
+ Format.eprintf "Wait: %f@." (Unix.gettimeofday () -. t);
+ let v = read st.mem l in
+ fut := Finished v;
+ v
+
+type scheduler =
+ { mutable fds : Unix.file_descr list;
+ conts : (Unix.file_descr, int -> unit) Hashtbl.t }
+
+let scheduler () = { fds = []; conts = Hashtbl.create 11 }
+
+let async sched fut f =
+ match !fut with
+ Finished v ->
+ f v
+ | Running st ->
+ let g l =
+ let v = read st.mem l in
+ fut := Finished v;
+ f v
+ in
+ sched.fds <- st.pipe_in :: sched.fds;
+ Hashtbl.add sched.conts st.pipe_in g
+
+let run sched =
+ while sched.fds <> [] do
+ let t = Unix.gettimeofday () in
+ let (avail, _, _) = Unix.select sched.fds [] [] (-1.) in
+ if debug_task () then
+ Format.eprintf "Wait: %f@." (Unix.gettimeofday () -. t);
+ sched.fds <- List.filter (fun fd -> not (List.mem fd avail)) sched.fds;
+ List.iter
+ (fun fd ->
+ let cont = Hashtbl.find sched.conts fd in
+ Hashtbl.remove sched.conts fd;
+ let (i, l) = receive fd in
+ cont l)
+ avail
+ done
+
+let map l pre post =
+ List.map (fun x -> post (wait x)) (List.map pre l)
+
+let iter l pre post =
+ List.iter (fun x -> post (wait x)) (List.map pre l)
+
+let iteri l pre post =
+ List.iter (fun (x, y) -> post x (wait y)) (List.map pre l)
+
+(*
+
+#ifdef MADV_REMOVE
+ if (madvise(ptr, size, MADV_REMOVE) >= 0)
+ return;
+#endif
+
+#ifdef MADV_FREE
+ if (madvise(ptr, size, MADV_FREE) >= 0)
+ return;
+#endif
+
+#ifdef MADV_DONTNEED
+ madvise(ptr, size, MADV_DONTNEED);
+#endif
+}
+
+*)
diff --git a/task.mli b/task.mli
new file mode 100644
index 0000000..2aa60d8
--- /dev/null
+++ b/task.mli
@@ -0,0 +1,39 @@
+(* Co-installability tools
+ * http://coinst.irill.org/
+ * Copyright (C) 2011 Jérôme Vouillon
+ * Laboratoire PPS - CNRS Université Paris Diderot
+ *
+ * These programs are free software; you can redistribute them and/or
+ * modify them under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *)
+
+type 'a t
+type 'a future
+
+val spawn : (unit -> 'a) -> 'a t
+val funct : ('a -> 'b -> 'c) -> 'a t -> 'b -> 'c future
+val wait : 'a future -> 'a
+val kill : 'a t -> unit
+
+val map : 'a list -> ('a -> 'b future) -> ('b -> 'c) -> 'c list
+val iter : 'a list -> ('a -> 'b future) -> ('b -> unit) -> unit
+val iteri : 'a list -> ('a -> ('b * 'c future)) -> ('b -> 'c -> unit) -> unit
+
+type scheduler
+
+val scheduler : unit -> scheduler
+val async : scheduler -> 'a future -> ('a -> unit) -> unit
+val run : scheduler -> unit
+
+val get_processor_count : unit -> int
+val set_processor_count : int -> unit
diff --git a/task_stubs.c b/task_stubs.c
new file mode 100644
index 0000000..65ba21b
--- /dev/null
+++ b/task_stubs.c
@@ -0,0 +1,12 @@
+#include
+#include "caml/mlvalues.h"
+
+CAMLprim value task_processor_count (value unit) {
+ long v;
+ #ifdef _SC_NPROCESSORS_ONLN
+ v = sysconf (_SC_NPROCESSORS_ONLN);
+ #else
+ v = 1;
+ #endif
+ return Val_long ((v<=0)?1:v);
+}
diff --git a/transition.ml b/transition.ml
index 68658d1..504208f 100644
--- a/transition.ml
+++ b/transition.ml
@@ -18,36 +18,43 @@
*)
(*
+- option to disable caching
+- option to set the number of processors available
+- should start finding conflicts while reducing repositories
+ ==> if not yet available when finding conflucts, compute
+ ==> if threads available, use them to reduce the repository
+
PRIORITIES
-==> save learnt clauses
-==> graphs for reporting co-installability issues
-==> explain what it takes to migrate a package
-==> find a way to indicate what corresponds to each new
- co-installability issue
- ==> if I upgrade, these packages will be broken
- if I don't, these other packages will be broken (?)
-==> how do we ignore co-installability issues?
-==> allow package removal
-==> indicate which packages would be propagated by britney but not by
- this tool
-
-
- Generate explanations
+ ==> graphs for reporting co-installability issues:
+ should include "problematic packages" in the graph,
+ and illustrate how the issue changes between testing and unstable
+ - packages may be in testing, sid, or both; in the latter case,
+ they may have different version between the two
+ - dependencies can be in testing, sid, or both
+ - dependency targets may be in testing, sid, or both
+ - same thing for each side of a conflict (!)
+ indicate which set of packages are made non-coinstallable
+
+ ==> option to indicate which packages would be propagated by britney
+ but not by this tool
+ ==> find what it takes to install a package:
+ iterative (relax the problem until we can install the package);
+ with clause learning
+ ==> add possibility to migrate packages with co-installability issues
+ (find out the right kind of hints)
+
+PERFORMANCE
+ ==> parallelise the program: one process per architecture
+
+EXPLANATIONS
==> link to build logs / merge packages
==> link to http://packages.qa.debian.org (for source files)
==> link to bugs
==> show source and binary versions
==> three step: no age/bug constraints, bugs added, all
- ==> show packages that only wait for age, for bugs
-
- Find what it takes to install a package
- ==> iterative: relax the problem until we can install the package
- ==> with clause learning
- ==> we could save learnt rules...
-
- - parallelise the program: one process per architecture
-
- - associate a nice graph to each co-installability issue found
+ ==> summaries; in particular, show packages that only wait for age,
+ for bugs
+ ==> explanation of co-installability issues
*)
let dir = ref (Filename.concat (Sys.getenv "HOME") "debian-dists/britney")
@@ -114,6 +121,8 @@ let make_uid () =
(Int64.mul magic1 (Int64.of_float (1e6 *. Unix.gettimeofday ())))
(Int64.mul magic2 (Int64.of_int (Unix.getpid ()))))
+let cache_disabled = ref false
+
let cached ?(force=false) files cache magic f =
let magic =
Format.sprintf
@@ -122,7 +131,7 @@ let cached ?(force=false) files cache magic f =
in
let ch = try Some (open_in cache) with Sys_error _ -> None in
let should_compute =
- force ||
+ !cache_disabled || force ||
match ch with
None ->
true
@@ -147,15 +156,17 @@ let cached ?(force=false) files cache magic f =
if should_compute then begin
begin match ch with Some ch -> close_in ch | None -> () end;
let res = f () in
- let tmp = cache ^ ".tmp" in
- Util.make_directories tmp;
- let ch = open_out tmp in
- output_string ch magic;
let uid = make_uid () in
- output_string ch uid;
- Marshal.to_channel ch res [];
- close_out ch;
- Sys.rename tmp cache;
+ if not !cache_disabled then begin
+ let tmp = cache ^ ".tmp" in
+ Util.make_directories tmp;
+ let ch = open_out tmp in
+ output_string ch magic;
+ output_string ch uid;
+ Marshal.to_channel ch res [];
+ close_out ch;
+ Sys.rename tmp cache
+ end;
(res, uid)
end else begin
match ch with
@@ -175,7 +186,7 @@ let _ =
Printexc.record_backtrace true;
Gc.set { (Gc.get ())
with Gc.space_overhead = 200; max_overhead = 1000000;
- major_heap_increment = 20 * 1024 * 1024 }
+ major_heap_increment = 5 * 1024 * 1024 }
module Timer = Util.Timer
module ListTbl = Util.ListTbl
@@ -317,10 +328,13 @@ let read_hints dir =
let read_extra_info () =
let dates = read_dates (Filename.concat (testing ()) "Dates") in
let urgencies = read_urgencies (Filename.concat (testing ()) "Urgency") in
+ let hints = read_hints (Filename.concat (unstable ()) "Hints") in
+ (dates, urgencies, hints)
+
+let read_bugs () =
let testing_bugs = read_bugs (Filename.concat (testing ()) "BugsV") in
let unstable_bugs = read_bugs (Filename.concat (unstable ()) "BugsV") in
- let hints = read_hints (Filename.concat (unstable ()) "Hints") in
- (dates, urgencies, testing_bugs, unstable_bugs, hints)
+ (testing_bugs, unstable_bugs)
(****)
@@ -406,26 +420,32 @@ let print_reason f reason =
l;
Format.fprintf f " cannot be propagated all at once"
-let unchanged = ListTbl.create 101
+let unchanged_reasons = ListTbl.create 101
+let unchanged = Hashtbl.create 17
let propagation_rules = Hashtbl.create 101
+let init_changes () =
+ List.iter (fun arch -> Hashtbl.add unchanged arch (Hashtbl.create 1001))
+ ("source" :: !archs)
+
let rec no_change pkg reason =
+ ListTbl.add unchanged_reasons pkg reason;
let (nm, arch) = pkg in
- let already = ListTbl.mem unchanged (nm, arch) in
- ListTbl.add unchanged (nm, arch) reason;
- if not already then begin
- if reason <> Unchanged && verbose () then
- Format.eprintf "Skipping %s (%s): %a@."
- nm arch print_reason reason;
- let l = Hashtbl.find_all propagation_rules (nm, arch) in
+ let unchanged' = Hashtbl.find unchanged arch in
+ if not (Hashtbl.mem unchanged' nm) then begin
+ Hashtbl.add unchanged' nm ();
+ if reason <> Unchanged && verbose () then begin
+ Format.eprintf "Skipping %s (%s): %a@." nm arch print_reason reason
+ end;
+ let l = Hashtbl.find_all propagation_rules pkg in
List.iter (fun (pkg', reason') -> no_change pkg' reason') l
end
(* if pkg2 is unchanged, then pkg1 should be unchanged as well. *)
let associates pkg1 pkg2 reason =
let (nm, arch) = pkg2 in
- if ListTbl.mem unchanged (nm, arch) then
+ if Hashtbl.mem (Hashtbl.find unchanged arch) nm then
no_change pkg1 reason
else
Hashtbl.add propagation_rules (nm, arch) (pkg1, reason)
@@ -443,14 +463,15 @@ let all_or_none pkgs reason =
let learnt_rules = ref []
-let learn_rule nm version arch neg s =
- learnt_rules := (nm, version, arch, neg, s) :: !learnt_rules
+let learn_rule nm arch neg s =
+ learnt_rules := (nm, arch, neg, s) :: !learnt_rules
-let load_rules uid =
+let load_rules uids =
let cache = Filename.concat cache_dir "Rules" in
- let (rules, _) = cached [] cache ("version 1\n" ^ uid) (fun () -> []) in
+ let uids = String.concat "\n" uids in
+ let (rules, _) = cached [] cache ("version 2\n" ^ uids) (fun () -> []) in
List.iter
- (fun (nm, version, arch, neg, s) ->
+ (fun (nm, arch, neg, s) ->
if StringSet.is_empty neg then
no_change (nm, arch) (Conflict (neg, s))
else if StringSet.cardinal neg = 1 then
@@ -459,9 +480,10 @@ let load_rules uid =
rules;
learnt_rules := rules
-let save_rules uid =
+let save_rules uids =
let cache = Filename.concat cache_dir "Rules" in
- ignore (cached ~force:true [] cache ("version 1\n" ^ uid)
+ let uids = String.concat "\n" uids in
+ ignore (cached ~force:true [] cache ("version 2\n" ^ uids)
(fun () -> List.rev !learnt_rules))
(****)
@@ -499,12 +521,27 @@ let group compare l =
(****)
+type st =
+ { arch : string;
+ testing : M.pool;
+ unstable : M.pool;
+ testing_srcs : (string, M.s) Hashtbl.t;
+ unstable_srcs : (string, M.s) Hashtbl.t;
+ unstable_bugs : (string, StringSet.t) Hashtbl.t;
+ testing_bugs : (string, StringSet.t) Hashtbl.t;
+ mutable upgrade_state :
+ (Upgrade_common.state * Upgrade_common.state) option;
+ uid : string }
+
+(****)
+
let rec interesting_reason r =
match r with
Unchanged ->
false
| Binary_not_propagated (bin, arch) ->
- List.exists interesting_reason (ListTbl.find unchanged (bin, arch))
+ List.exists interesting_reason
+ (ListTbl.find unchanged_reasons (bin, arch))
| Source_not_propagated _ ->
false
| Atomic _ ->
@@ -512,29 +549,55 @@ let rec interesting_reason r =
| _ ->
true
+let binary_sources st l =
+ List.map
+ (fun nm ->
+ let source =
+ match ListTbl.find st.unstable.M.packages_by_name nm with
+ p :: _ -> fst p.M.source
+ | [] -> match ListTbl.find st.testing.M.packages_by_name nm with
+ p :: _ -> fst p.M.source
+ | [] -> assert false
+ in
+ (nm, source))
+ l
+
+let binary_sources = Task.funct binary_sources
+
let output_reasons l filename =
+ let t = Timer.start () in
let ch = open_out filename in
let f = Format.formatter_of_out_channel ch in
+ let blocked_source = Hashtbl.create 1024 in
let sources = ref [] in
+ let binaries = ListTbl.create 17 in
+ let add_binaries arch s =
+ StringSet.iter (fun p -> ListTbl.add binaries arch p) s in
ListTbl.iter
(fun (nm, arch) reasons ->
- if arch = "source" && List.exists interesting_reason reasons then
- sources := (nm, reasons) :: !sources)
- unchanged;
-
- let print_binary f (nm, (arch : string)) =
- let (t, u) = List.assoc arch l in
- let source =
- match ListTbl.find u.M.packages_by_name nm with
- p :: _ ->
- fst p.M.source
- | [] ->
- match ListTbl.find t.M.packages_by_name nm with
- p :: _ -> fst p.M.source
- | [] -> assert false
- in
- if not (List.mem_assoc source !sources) then begin
+ if arch = "source" && List.exists interesting_reason reasons then begin
+ sources := (nm, reasons) :: !sources;
+ Hashtbl.add blocked_source nm ()
+ end;
+ List.iter
+ (fun r ->
+ match r with
+ Conflict (s, s') -> add_binaries arch s; add_binaries arch s'
+ | _ -> ())
+ reasons)
+ unchanged_reasons;
+
+ let source_of_binary = Hashtbl.create 101 in
+ Task.iteri l
+ (fun (arch, st) -> (arch, binary_sources st (ListTbl.find binaries arch)))
+ (fun arch l ->
+ List.iter
+ (fun (nm, src) -> Hashtbl.add source_of_binary (nm, arch) src) l);
+
+ let print_binary f (nm, arch) =
+ let source = Hashtbl.find source_of_binary (nm, arch) in
+ if not (Hashtbl.mem blocked_source source) then begin
if source = nm then
Format.fprintf f "%s" nm
else
@@ -581,7 +644,7 @@ let output_reasons l filename =
(fun bin ->
List.exists
(fun r -> match r with Not_yet_built _ -> true | _ -> false)
- (ListTbl.find unchanged bin))
+ (ListTbl.find unchanged_reasons bin))
binaries)
in
List.iter
@@ -598,7 +661,7 @@ let output_reasons l filename =
(fun bin ->
List.exists
(fun r -> match r with More_bugs -> true | _ -> false)
- (ListTbl.find unchanged bin))
+ (ListTbl.find unchanged_reasons bin))
binaries)
in
List.iter
@@ -615,7 +678,7 @@ let output_reasons l filename =
match r with
Not_yet_built _ | More_bugs -> false
| _ -> true)
- (ListTbl.find unchanged bin))
+ (ListTbl.find unchanged_reasons bin))
binaries
in
List.iter
@@ -649,7 +712,7 @@ let output_reasons l filename =
": would break binary package %a.@."
print_binary (StringSet.choose s', arch)
end
- end else begin
+ end else begin
Format.fprintf f ": would break binary packages";
StringSet.iter
(fun nm ->
@@ -663,14 +726,16 @@ let output_reasons l filename =
()
| _ ->
assert false)
- (ListTbl.find unchanged (nm', arch));
+ (ListTbl.find unchanged_reasons (nm', arch));
Format.fprintf f "@.")
binaries;
Format.fprintf f "@.")
(List.sort (fun (nm1, _) (nm2, _) -> compare nm1 nm2) !sources);
Format.fprintf f "@."
end;
- close_out ch
+ close_out ch;
+ if debug_time () then
+ Format.eprintf "Writing excuse file: %f@." (Timer.stop t)
(****)
@@ -733,13 +798,15 @@ let compute_conflicts t u =
compute_package_conflicts u t; compute_package_conflicts u u;
conflicts
-let reduce_repository_pair (arch, (t, u)) =
+let prepare_repository st unchanged =
+ let t = st.testing in
+ let u = st.unstable in
let conflicts = compute_conflicts t u in
let changed_packages = Hashtbl.create 101 in
let consider_package _ p =
let nm = p.M.package in
- if not (ListTbl.mem unchanged (nm, arch)) then
+ if not (Hashtbl.mem unchanged nm) then
Hashtbl.replace changed_packages nm ()
in
Hashtbl.iter consider_package t.M.packages_by_num;
@@ -751,7 +818,7 @@ let reduce_repository_pair (arch, (t, u)) =
Hashtbl.add pkgs p ();
List.iter add_package (ListTbl.find conflicts p);
List.iter follow_deps (ListTbl.find t.M.packages_by_name p);
- if Hashtbl.mem changed_packages p then
+ if not (Hashtbl.mem unchanged p) then
List.iter follow_deps (ListTbl.find u.M.packages_by_name p)
end
and follow_deps p =
@@ -820,21 +887,326 @@ let reduce_repository_pair (arch, (t, u)) =
let u' = M.new_pool () in
M.merge2 u' filter u;
if debug_reduction () then Format.eprintf "==> %d/%d@." !n !m;
- (arch, (t', u'))
+ st.upgrade_state <-
+ Some (Upgrade_common.prepare_analyze t',
+ Upgrade_common.prepare_analyze u')
+
+let reduce_repository_pair = Task.funct prepare_repository
let reduce_repositories l =
let t = Timer.start () in
- let l = List.map reduce_repository_pair l in
+ Task.iter l
+ (fun (arch, st) -> reduce_repository_pair st (Hashtbl.find unchanged arch))
+ (fun () -> ());
if debug_time () then
- Format.eprintf "Reducing repositories: %f@." (Timer.stop t);
- l
+ Format.eprintf "Reducing repositories: %f@." (Timer.stop t)
+
+let rec get_upgrade_state st unchanged =
+ match st.upgrade_state with
+ Some st ->
+ st
+ | None ->
+ prepare_repository st unchanged;
+ get_upgrade_state st unchanged
(****)
-type 'a easy_hint =
- { mutable h_names : 'a list;
- mutable h_pkgs : (string * string) list;
- mutable h_live : bool }
+let share_packages (t, u) =
+ let unchanged dist p =
+ match ListTbl.find dist.M.packages_by_name p.M.package with
+ [] -> false
+ | [q] -> M.compare_version p.M.version q.M.version = 0
+ | _ -> assert false
+ in
+ let common = M.new_pool () in
+ M.merge2 common (fun p -> unchanged u p) t;
+ let t' = M.copy common in
+ M.merge2 t' (fun p -> not (unchanged u p)) t;
+ let u' = common in
+ M.merge2 u' (fun p -> not (unchanged t p)) u;
+ assert (t'.M.size = t.M.size && u'.M.size = u.M.size);
+ (t', u')
+
+let init_arch arch testing_srcs testing_bugs unstable_srcs unstable_bugs () =
+ let files =
+ [bin_package_file (testing ()) arch;
+ bin_package_file (unstable ()) arch]
+ in
+ let cache = bin_package_file cache_dir arch in
+ let ((t, u), uid) =
+ cached files cache "version 1"
+ (fun () ->
+ share_packages
+ (load_bin_packages (testing ()) arch,
+ load_bin_packages (unstable ()) arch))
+ in
+(*
+let n1 = ref 0 in
+let n2 = ref 0 in
+Hashtbl.iter (fun _ p ->
+ incr n1;
+if ListTbl.mem t.M.packages_by_name p.M.package then begin
+ let q = List.hd (ListTbl.find t.M.packages_by_name p.M.package) in
+ if M.compare_version p.M.version q.M.version = 0 then incr n2
+end
+) u.M.packages_by_num;
+Format.eprintf "====> %d/%d" !n2 !n1;
+*)
+ { arch = arch;
+ testing = t;
+ testing_srcs = testing_srcs; testing_bugs = testing_bugs;
+ unstable = u;
+ unstable_srcs = unstable_srcs; unstable_bugs = unstable_bugs;
+ upgrade_state = None;
+ uid = uid }
+
+type cstr =
+ No_change of int * (string * string) * reason
+ | Associates of (string * string) * (string * string) * reason
+ | All_or_none of (string * string) list * reason
+
+let arch_constraints st (produce_excuses, compute_hints) =
+ let t = st.testing_srcs in
+ let u = st.unstable_srcs in
+ let t' = st.testing in
+ let u' = st.unstable in
+ let fake_srcs = ref [] in
+ let is_fake = Hashtbl.create 17 in
+ let sources_with_binaries = ref [] in
+ let source_has_binaries = Hashtbl.create 8192 in
+ let l = ref [] in
+ let no_change pkg reason = l := No_change (0, pkg, reason) :: !l in
+ let no_change_deferred pkg reason = l := No_change (1, pkg, reason) :: !l in
+ let associates pkg1 pkg2 reason =
+ l := Associates (pkg1, pkg2, reason):: !l
+ in
+ let all_or_none pkgl reason = l := All_or_none (pkgl, reason) :: !l in
+ let get_bugs src bugs p =
+ try Hashtbl.find bugs p with Not_found -> StringSet.empty
+ in
+ let no_new_bugs is_new p =
+ if is_new then
+ StringSet.is_empty (get_bugs u st.unstable_bugs p)
+ else
+ StringSet.subset
+ (get_bugs u st.unstable_bugs p)
+ (get_bugs t st.testing_bugs p)
+ in
+ let arch = st.arch in
+ let bin_nmus = ListTbl.create 101 in
+ Hashtbl.iter
+ (fun _ p ->
+ let pkg = (p.M.package, arch) in
+ let (nm, v) = p.M.source in
+ (* Faux packages *)
+ if not (Hashtbl.mem u nm) then begin
+ Hashtbl.add u nm
+ { M.s_name = nm; s_version = v; s_section = "" };
+ fake_srcs := (nm, v) :: !fake_srcs;
+ Hashtbl.add is_fake nm ();
+ no_change (nm, "source") Unchanged
+ end;
+ let v' = (Hashtbl.find u nm).M.s_version in
+ (* Do not add a binary package if its source is not
+ the most up to date source file. *)
+ if M.compare_version v v' <> 0 then
+ no_change pkg (Not_yet_built (nm, v, v'))
+ else if not (Hashtbl.mem source_has_binaries nm) then begin
+ sources_with_binaries := nm :: !sources_with_binaries;
+ Hashtbl.add source_has_binaries nm ()
+ end;
+ let source_changed =
+ not (same_source_version t u (fst p.M.source)) in
+ (* We only propagate binary packages with a larger version.
+ Faux packages are not propagated. *)
+ if no_new_bin t' u' p.M.package || Hashtbl.mem is_fake nm then
+ no_change pkg Unchanged
+ else begin
+ (* Do not upgrade a package if it has new bugs *)
+ let is_new = bin_version t' p.M.package = None in
+ if not (no_new_bugs is_new p.M.package) then
+ no_change_deferred pkg More_bugs;
+ if source_changed then
+ (* We cannot add a binary package without also adding
+ its source. *)
+ associates pkg (fst p.M.source, "source")
+ (Source_not_propagated p.M.source)
+ else
+ ListTbl.add bin_nmus p.M.source pkg;
+
+ end;
+ (* If a source is propagated, all its binaries should
+ be propagated as well *)
+ if source_changed || produce_excuses then
+ associates (fst p.M.source, "source") pkg
+ (Binary_not_propagated pkg))
+ u'.M.packages_by_num;
+ (* All binaries packages from a same source are propagated
+ atomically on any given architecture. *)
+ ListTbl.iter
+ (fun _ pkgs -> all_or_none pkgs (Atomic pkgs)) bin_nmus;
+ Hashtbl.iter
+ (fun _ p ->
+ let pkg = (p.M.package, arch) in
+ let (nm, v) = p.M.source in
+ (* Faux packages *)
+ if not (Hashtbl.mem t nm) then begin
+ (* The source should be fake in unstable as well. *)
+ assert (not (Hashtbl.mem u nm) || Hashtbl.mem is_fake nm);
+ Hashtbl.add t nm
+ { M.s_name = nm; s_version = v; s_section = "" };
+ fake_srcs := (nm, v) :: !fake_srcs;
+ Hashtbl.add is_fake nm ();
+ no_change (nm, "source") Unchanged
+ end;
+ let v' = (Hashtbl.find t nm).M.s_version in
+ let source_changed =
+ not (same_source_version t u (fst p.M.source)) in
+ (* We only propagate binary packages with a larger version.
+ Faux packages are not propagated. *)
+ if no_new_bin t' u' p.M.package || Hashtbl.mem is_fake nm then
+ no_change pkg Unchanged
+ else begin
+ (* Binary packages without source of the same version can
+ be removed freely when not needed anymore (these are
+ binaries left for smooth update).
+ However, when producing hints, we do not allow this, as
+ we have no way to communicate the change to britney... *)
+ if not compute_hints && M.compare_version v v' <> 0 then
+ ()
+ (* We cannot remove a binary without removing its source. *)
+ else if source_changed then
+ associates pkg (fst p.M.source, "source")
+ (Source_not_propagated p.M.source)
+ else
+ ListTbl.add bin_nmus p.M.source pkg
+ end;
+ (* We cannot remove or upgrade a source package if a
+ corresponding binary package still exists.
+ We relax this constraint for libraries when upgrading
+ a source package. *)
+ if
+ (source_changed || produce_excuses)
+ &&
+ not (allow_smooth_updates p && Hashtbl.mem u nm)
+ then
+ associates (fst p.M.source, "source") pkg
+ (Binary_not_propagated pkg))
+ t'.M.packages_by_num;
+ (List.rev !l, st.uid, !sources_with_binaries, !fake_srcs)
+
+let arch_constraints = Task.funct arch_constraints
+
+(****)
+
+let find_coinst_constraints st unchanged =
+ let arch = st.arch in
+ let (t', u') = get_upgrade_state st unchanged in
+ let changes = ref [] in
+ if debug_coinst () then
+ Format.eprintf "==================== %s@." arch;
+ let step_t = Timer.start () in
+ let problems =
+ Upgrade_common.find_problematic_packages
+ ~check_new_packages:true t' u'
+ (fun nm -> Hashtbl.mem unchanged nm)
+ in
+ let t = Timer.start () in
+ let has_singletons =
+ List.exists
+ (fun (cl, _) -> StringSet.cardinal cl.Upgrade_common.pos = 1)
+ problems
+ in
+ List.iter
+ (fun ({Upgrade_common.pos = pos; neg = neg}, s) ->
+ let n = StringSet.cardinal pos in
+ if not (has_singletons && n > 1) then begin
+ let nm = StringSet.choose pos in
+ let can_learn = n = 1 && StringSet.cardinal neg <= 1 in
+ changes := (nm, arch, neg, s, can_learn) :: !changes
+ end)
+ problems;
+ if debug_time () then begin
+ Format.eprintf " New constraints: %f@." (Timer.stop t);
+ Format.eprintf "Step duration: %f@." (Timer.stop step_t)
+ end;
+ List.rev !changes
+
+let find_coinst_constraints = Task.funct find_coinst_constraints
+
+let find_all_coinst_constraints a =
+ let t = Timer.start () in
+ let c = Array.length a in
+ let running = Array.make c false in
+ let changed = Array.make c true in
+ let n = ref 0 in
+ let max_proc = Task.get_processor_count () in
+ let scheduler = Task.scheduler () in
+ let rec start c i0 i =
+ if running.(i) || not changed.(i) then begin
+ let i = (i + 1) mod c in
+ if i <> i0 then start c i0 i
+ end else begin
+ changed.(i) <- false;
+ running.(i) <- true;
+ let (arch, st) = a.(i) in
+ Task.async scheduler
+ (find_coinst_constraints st (Hashtbl.find unchanged arch))
+ (fun changes -> stop c i changes);
+ if !n < max_proc then begin
+ start c 0 0
+ end
+ end
+ and stop c i changes =
+ if changes <> [] then begin
+ Array.fill changed 0 c true;
+ List.iter
+ (fun (nm, arch, neg, s, can_learn) ->
+ if can_learn then learn_rule nm arch neg s;
+ no_change (nm, arch) (Conflict (neg, s)))
+ changes
+ end;
+ running.(i) <- false;
+ decr n;
+ start c i i
+ in
+ start 1 0 0;
+ Task.run scheduler;
+ start c 0 0;
+ Task.run scheduler;
+ if debug_time () then
+ Format.eprintf "Solving constraints: %f@." (Timer.stop t)
+
+(****)
+
+let arch_change st unchanged =
+ let arch = st.arch in
+ let t' = st.testing in
+ let u' = st.unstable in
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ let v = p.M.version in
+ if not (Hashtbl.mem unchanged nm) then
+ match bin_version u' nm with
+ Some v' ->
+ Format.eprintf
+ "Upgrade binary package %s/%s from %a to %a@."
+ nm arch M.print_version v M.print_version v'
+ | None ->
+ Format.eprintf "Remove binary package %s/%s@." nm arch)
+ t'.M.packages_by_num;
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ if not (Hashtbl.mem unchanged nm) then
+ if not (ListTbl.mem t'.M.packages_by_name nm) then
+ Format.eprintf "Adding binary package %s/%s@." nm arch)
+ u'.M.packages_by_num
+
+let arch_change = Task.funct arch_change
+
+(****)
module Union_find = struct
@@ -859,49 +1231,81 @@ let rec get t =
Link _ -> assert false
| Value v -> v
-let merge t t' =
+let merge t t' f =
let t = repr t in
let t' = repr t' in
- t'.state <- Link t
+ if t != t' then begin
+ t.state <- Value (f (get t) (get t'));
+ t'.state <- Link t
+ end
let elt v = { state = Value v }
end
+let cluster_packages st (unchanged, clusters) =
+ let clusters =
+ List.map (fun (lst, id) -> (lst, (id, Union_find.elt id))) clusters
+ in
+ let merge (_, e1) (_, e2) = Union_find.merge e1 e2 min in
+ let (t, u) =
+ match st.upgrade_state with Some st -> st | None -> assert false in
+ Upgrade_common.find_clusters t u
+ (fun nm -> Hashtbl.mem unchanged nm) clusters merge;
+ List.map (fun (_, (id, elt)) -> (id, Union_find.get elt)) clusters
+
+let cluster_packages = Task.funct cluster_packages
+
+type 'a easy_hint =
+ { mutable h_names : 'a list;
+ mutable h_pkgs : (string * string) list;
+ mutable h_live : bool;
+ h_id : int }
+
let generate_small_hints l buckets =
let to_consider = ref [] in
+ let buckets_by_id = Hashtbl.create 17 in
+ let n = ref 0 in
ListTbl.iter
(fun (src, arch) lst ->
- let info = { h_names = [(src, arch)]; h_pkgs = lst; h_live = true } in
+ let info =
+ { h_names = [(src, arch)]; h_pkgs = lst; h_live = true; h_id = !n } in
let elt = Union_find.elt info in
+ Hashtbl.add buckets_by_id !n elt;
+ incr n;
to_consider := (info, elt) :: !to_consider)
buckets;
let merge elt elt' =
- if Union_find.repr elt != Union_find.repr elt' then begin
- let info = Union_find.get elt in
- let info' = Union_find.get elt' in
- assert (info.h_live);
- assert (info'.h_live);
- Union_find.merge elt elt';
- info.h_names <- info'.h_names @ info.h_names;
- info.h_pkgs <- info'.h_pkgs @ info.h_pkgs;
- info'.h_live <- false
- end
+ Union_find.merge elt elt'
+ (fun info info' ->
+ assert (info.h_live);
+ assert (info'.h_live);
+ info.h_names <- info'.h_names @ info.h_names;
+ info.h_pkgs <- info'.h_pkgs @ info.h_pkgs;
+ info'.h_live <- false;
+ info)
in
- List.iter
- (fun (arch, t, u) ->
+ Task.iter l
+ (fun (arch, st) ->
+ let unchanged' = Hashtbl.find unchanged arch in
let clusters = ref [] in
List.iter
(fun (info, elt) ->
- let l = List.filter (fun (_, arch') -> arch = arch') info.h_pkgs in
+ let l =
+ List.filter (fun (_, arch') -> arch = arch') info.h_pkgs in
if l <> [] then
- clusters := (List.map fst l, elt) :: !clusters)
+ clusters :=
+ (List.map fst l, (Union_find.get elt).h_id) :: !clusters)
!to_consider;
- Upgrade_common.find_clusters t u
- (fun nm -> ListTbl.mem unchanged (nm, arch)) !clusters merge)
- l;
+ cluster_packages st (unchanged', !clusters))
+ (fun lst ->
+ List.iter
+ (fun (id, id') ->
+ merge (Hashtbl.find buckets_by_id id)
+ (Hashtbl.find buckets_by_id id'))
+ lst);
let lst =
List.filter (fun info -> info.h_live) (List.map fst !to_consider) in
@@ -920,42 +1324,49 @@ let generate_small_hints l buckets =
in
let lst = List.map (fun names -> List.sort compare_elt names) lst in
let lst = List.sort compare_lst lst in
- let lst =
- List.stable_sort
- (fun l l' -> compare (List.length l) (List.length l')) lst
- in
- lst
+ List.stable_sort (fun l l' -> compare (List.length l) (List.length l')) lst
-let generate_hints t u l l' =
+let collect_changes st unchanged =
+ let changes = ref [] in
+ let u' = st.unstable in
+ let t' = st.testing in
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ if not (Hashtbl.mem unchanged nm) then begin
+ let (src, v) = p.M.source in
+ changes := (src, nm) :: !changes
+ end)
+ u'.M.packages_by_num;
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ if
+ not (Hashtbl.mem unchanged nm)
+ &&
+ not (ListTbl.mem u'.M.packages_by_name nm)
+ then begin
+ let (src, v) = p.M.source in
+ changes := (src, nm) :: !changes
+ end)
+ t'.M.packages_by_num;
+ List.rev !changes
+
+let collect_changes = Task.funct collect_changes
+
+let generate_hints t u l =
let hint_t = Timer.start () in
let changes = ListTbl.create 101 in
- List.iter
- (fun (arch, (t', u')) ->
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- if not (ListTbl.mem unchanged (nm, arch)) then begin
- let (src, v) = p.M.source in
- ListTbl.add changes src (nm, arch)
- end)
- u'.M.packages_by_num;
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- if
- not (ListTbl.mem unchanged (nm, arch))
- &&
- not (ListTbl.mem u'.M.packages_by_name nm)
- then begin
- let (src, v) = p.M.source in
- ListTbl.add changes src (nm, arch)
- end)
- t'.M.packages_by_num)
- l;
+ Task.iteri l
+ (fun (arch, st) ->
+ (arch, collect_changes st (Hashtbl.find unchanged arch)))
+ (fun arch lst ->
+ List.iter (fun (src, nm) -> ListTbl.add changes src (nm, arch)) lst);
let buckets = ListTbl.create 101 in
+ let unchanged' = Hashtbl.find unchanged "source" in
ListTbl.iter
(fun src l ->
- if not (ListTbl.mem unchanged (src, "source")) then
+ if not (Hashtbl.mem unchanged' src) then
List.iter
(fun info -> ListTbl.add buckets (src, "source") info)
l
@@ -965,7 +1376,7 @@ let generate_hints t u l l' =
ListTbl.add buckets (src, arch) info)
l)
changes;
- let hints = generate_small_hints l' buckets in
+ let hints = generate_small_hints l buckets in
if debug_time () then
Format.eprintf "Generating hints: %f@." (Timer.stop hint_t);
let print_pkg f src arch =
@@ -1001,28 +1412,70 @@ let generate_hints t u l l' =
(****)
+let heidi_buffer = Buffer.create 80
+
+let heidi_line lines nm vers arch sect =
+ Format.bprintf heidi_buffer "%s %a %s %s@."
+ nm M.print_version vers arch sect;
+ lines := Buffer.contents heidi_buffer :: !lines;
+ Buffer.clear heidi_buffer
+
+let heidi_arch st unchanged =
+ let lines = ref [] in
+ let arch = st.arch in
+ let t = st.testing in
+ let u = st.unstable in
+ let is_preserved nm = Hashtbl.mem unchanged nm in
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ let sect = if p.M.section = "" then "faux" else p.M.section in
+ if is_preserved nm then heidi_line lines nm p.M.version arch sect)
+ t.M.packages_by_num;
+ Hashtbl.iter
+ (fun _ p ->
+ let nm = p.M.package in
+ let sect = if p.M.section = "" then "faux" else p.M.section in
+ if not (is_preserved nm) then
+ heidi_line lines nm p.M.version arch sect)
+ u.M.packages_by_num;
+ String.concat "" (List.sort compare !lines)
+
+let heidi_arch = Task.funct heidi_arch
+
+let print_heidi ch fake_src l t u =
+ let heidi_t = Timer.start () in
+ let lines = ref [] in
+ Task.iter (List.sort (fun (arch, _) (arch', _) -> compare arch arch') l)
+ (fun (arch, st) -> heidi_arch st (Hashtbl.find unchanged arch))
+ (fun lines -> output_string ch lines);
+ let unchanged' = Hashtbl.find unchanged "source" in
+ let is_preserved nm = Hashtbl.mem unchanged' nm in
+ let source_sect nm s =
+ if Hashtbl.mem fake_src nm then "faux"
+ else if s.M.s_section = "" then "unknown"
+ else s.M.s_section
+ in
+ Hashtbl.iter
+ (fun nm s ->
+ let sect = source_sect nm s in
+ if is_preserved nm then
+ heidi_line lines nm s.M.s_version "source" sect)
+ t;
+ Hashtbl.iter
+ (fun nm s ->
+ let sect = source_sect nm s in
+ if not (is_preserved nm) then
+ heidi_line lines nm s.M.s_version "source" sect)
+ u;
+ List.iter (output_string ch) (List.sort compare !lines);
+ if debug_time () then
+ Format.eprintf "Writing Heidi file: %f@." (Timer.stop heidi_t)
+
let f () =
+ Util.enable_messages false;
let load_t = Timer.start () in
- let (dates, urgencies, testing_bugs, unstable_bugs, hints) =
- read_extra_info () in
- let files =
- List.flatten
- (List.map
- (fun arch ->
- [bin_package_file (testing ()) arch;
- bin_package_file (unstable ()) arch])
- !archs)
- in
- let cache = Filename.concat cache_dir "Packages" in
- let (l, uid) =
- cached files cache "version 2" (fun () ->
- List.map
- (fun arch ->
- (arch,
- (load_bin_packages (testing ()) arch,
- load_bin_packages (unstable ()) arch)))
- !archs)
- in
+ let (testing_bugs, unstable_bugs) = read_bugs () in
let files =
[src_package_file (testing ()); src_package_file (unstable ())] in
let cache = Filename.concat cache_dir "Sources" in
@@ -1030,11 +1483,20 @@ let f () =
cached files cache "version 2" (fun () ->
(load_src_packages (testing ()), load_src_packages (unstable ())))
in
- if debug_time () then Format.eprintf "Loading: %f@." (Timer.stop load_t);
+ if debug_time () then
+ Format.eprintf " Loading shared data: %f@." (Timer.stop load_t);
+ let l =
+ List.map
+ (fun arch ->
+ (arch, Task.spawn (init_arch arch t testing_bugs u unstable_bugs)))
+ !archs
+ in
+ let (dates, urgencies, hints) = read_extra_info () in
- load_rules uid;
+ if debug_time () then Format.eprintf "Loading: %f@." (Timer.stop load_t);
let init_t = Timer.start () in
+ init_changes ();
let compute_hints = debug_hints () || !hint_file <> "" in
let compute_ages nm uv tv =
let d =
@@ -1103,6 +1565,10 @@ let f () =
(fun (pkg, reason) -> no_change pkg reason) !deferred_constraints;
deferred_constraints := []
in
+ let arch_results =
+ List.map
+ (fun (_, t) -> arch_constraints t (produce_excuses, compute_hints)) l
+ in
Hashtbl.iter
(fun nm s ->
let v = s.M.s_version in
@@ -1125,207 +1591,64 @@ let f () =
no_change_deferred (nm, "source") More_bugs
end)
u;
- let fake_src = Hashtbl.create 17 in
- let sources_with_binaries = Hashtbl.create 16384 in
- List.iter
- (fun (arch, (t', u')) ->
- let bin_nmus = ListTbl.create 101 in
- Hashtbl.iter
- (fun _ p ->
- let pkg = (p.M.package, arch) in
- let (nm, v) = p.M.source in
- (* Faux packages *)
- if not (Hashtbl.mem u nm) then begin
- Hashtbl.add u nm
- { M.s_name = nm; s_version = v; s_section = "" };
- Hashtbl.add fake_src nm ();
- no_change (nm, "source") Unchanged
- end;
- let v' = (Hashtbl.find u nm).M.s_version in
- (* Do not add a binary package if its source is not
- the most up to date source file. *)
- if M.compare_version v v' <> 0 then
- no_change pkg (Not_yet_built (nm, v, v'))
- else
- Hashtbl.replace sources_with_binaries nm ();
- let source_changed =
- not (same_source_version t u (fst p.M.source)) in
- (* We only propagate binary packages with a larger version.
- Faux packages are not propagated. *)
- if no_new_bin t' u' p.M.package || Hashtbl.mem fake_src nm then
- no_change pkg Unchanged
- else begin
- (* Do not upgrade a package if it has new bugs *)
- let is_new = bin_version t' p.M.package = None in
- if not (no_new_bugs is_new p.M.package) then
- no_change_deferred pkg More_bugs;
- if source_changed then
- (* We cannot add a binary package without also adding
- its source. *)
- associates pkg (fst p.M.source, "source")
- (Source_not_propagated p.M.source)
- else
- ListTbl.add bin_nmus p.M.source pkg;
-
- end;
- (* If a source is propagated, all its binaries should
- be propagated as well *)
- if source_changed || produce_excuses then
- associates (fst p.M.source, "source") pkg
- (Binary_not_propagated pkg))
- u'.M.packages_by_num;
- (* All binaries packages from a same source are propagated
- atomically on any given architecture. *)
- ListTbl.iter
- (fun _ pkgs -> all_or_none pkgs (Atomic pkgs)) bin_nmus;
- Hashtbl.iter
- (fun _ p ->
- let pkg = (p.M.package, arch) in
- let (nm, v) = p.M.source in
- (* Faux packages *)
- if not (Hashtbl.mem t nm) then begin
- (* The source should be fake in unstable as well. *)
- assert (not (Hashtbl.mem u nm) || Hashtbl.mem fake_src nm);
- Hashtbl.add t nm
- { M.s_name = nm; s_version = v; s_section = "" };
- Hashtbl.add fake_src nm ();
- no_change (nm, "source") Unchanged
- end;
- let v' = (Hashtbl.find t nm).M.s_version in
- let source_changed =
- not (same_source_version t u (fst p.M.source)) in
- (* We only propagate binary packages with a larger version.
- Faux packages are not propagated. *)
- if no_new_bin t' u' p.M.package || Hashtbl.mem fake_src nm then
- no_change pkg Unchanged
- else begin
- (* Binary packages without source of the same version can
- be removed freely when not needed anymore (these are
- binaries left for smooth update).
- However, when producing hints, we do not allow this, as
- we have no way to communicate the change to britney... *)
- if not compute_hints && M.compare_version v v' <> 0 then
- ()
- (* We cannot remove a binary without removing its source. *)
- else if source_changed then
- associates pkg (fst p.M.source, "source")
- (Source_not_propagated p.M.source)
- else
- ListTbl.add bin_nmus p.M.source pkg
- end;
- (* We cannot remove or upgrade a source package if a
- corresponding binary package still exists.
- We relax this constraint for libraries when upgrading
- a source package. *)
- if
- (source_changed || produce_excuses)
- &&
- not (allow_smooth_updates p && Hashtbl.mem u nm)
- then
- associates (fst p.M.source, "source") pkg
- (Binary_not_propagated pkg))
- t'.M.packages_by_num)
- l;
-
+ let source_has_binaries = Hashtbl.create 8192 in
+ let is_fake = Hashtbl.create 17 in
+ let uids =
+ List.map
+ (fun r ->
+ let (l, uid, sources_with_binaries, fake_srcs) = Task.wait r in
+ List.iter
+ (fun nm ->
+ if not (Hashtbl.mem source_has_binaries nm) then
+ Hashtbl.add source_has_binaries nm ())
+ sources_with_binaries;
+ List.iter
+ (fun (nm, v) ->
+ if not (Hashtbl.mem is_fake nm) then begin
+ Hashtbl.add is_fake nm ();
+ Hashtbl.add t nm
+ { M.s_name = nm; s_version = v; s_section = "" };
+ end)
+ fake_srcs;
+ List.iter
+ (fun c ->
+ match c with
+ No_change (0, pkg, reason) ->
+ no_change pkg reason
+ | No_change (_, pkg, reason) ->
+ no_change_deferred pkg reason
+ | Associates (pkg1, pkg2, reason) ->
+ associates pkg1 pkg2 reason
+ | All_or_none (pkgl, reason) ->
+ all_or_none pkgl reason)
+ l;
+ uid)
+ arch_results
+ in
Hashtbl.iter
(fun nm s ->
- if not (Hashtbl.mem sources_with_binaries nm) then
+ if not (Hashtbl.mem source_has_binaries nm) then
no_change (nm, "source") No_binary)
u;
-
+ load_rules uids;
if debug_time () then
Format.eprintf "Initial constraints: %f@." (Timer.stop init_t);
- let l0 = l in
- let l = reduce_repositories l in
-
- let flatten_t = Timer.start () in
- let l' =
- List.map
- (fun (arch, (t', u')) ->
- (arch,
- Upgrade_common.prepare_analyze t',
- Upgrade_common.prepare_analyze u'))
- l
- in
- if debug_time () then
- Format.eprintf "Preparing analyze: %f@." (Timer.stop flatten_t);
+ reduce_repositories l;
- let find_coinst_constraints () =
- while
- let first = ref true in
- let changed = ref false in
- List.iter
- (fun (arch, t', u') ->
- if debug_coinst () then
- Format.eprintf "==================== %s@." arch;
- while
- let step_t = Timer.start () in
- let problems =
- Upgrade_common.find_problematic_packages
- ~check_new_packages:true t' u'
- (fun nm -> ListTbl.mem unchanged (nm, arch))
- in
- let t = Timer.start () in
- let has_singletons =
- List.exists
- (fun (cl, _) -> StringSet.cardinal cl.Upgrade_common.pos = 1)
- problems
- in
- let arch_changed = ref false in
- List.iter
- (fun ({Upgrade_common.pos = pos; neg = neg}, s) ->
- let n = StringSet.cardinal pos in
- if not (has_singletons && n > 1) then begin
- let nm = StringSet.choose pos in
- let p =
- match
- ListTbl.find
- u'.Upgrade_common.dist.M.packages_by_name nm
- with
- p :: _ ->
- p
- | [] ->
- match
- ListTbl.find
- t'.Upgrade_common.dist.M.packages_by_name nm
- with
- p :: _ ->
- p
- | [] ->
- assert false
- in
- arch_changed := true;
- if n = 1 && StringSet.cardinal neg <= 1 then
- learn_rule nm p.M.version arch neg s;
- no_change (nm, arch) (Conflict (neg, s))
- end)
- problems;
- if debug_time () then begin
- Format.eprintf " New constraints: %f@." (Timer.stop t);
- Format.eprintf "Step duration: %f@." (Timer.stop step_t)
- end;
- if !arch_changed && not !first then changed := true;
- first := false;
- !arch_changed
- do () done)
- l';
- !changed
- do () done
- in
-
- find_coinst_constraints ();
+ find_all_coinst_constraints (Array.of_list l);
if !deferred_constraints <> [] then begin
perform_deferred ();
- find_coinst_constraints ()
+ find_all_coinst_constraints (Array.of_list l)
end;
- save_rules uid;
+ save_rules uids;
if debug_outcome () then begin
+ let unchanged_src = Hashtbl.find unchanged "source" in
Hashtbl.iter
(fun nm s ->
- if not (ListTbl.mem unchanged (nm, "source")) then
+ if not (Hashtbl.mem unchanged_src nm) then
try
let s' = Hashtbl.find u nm in
Format.eprintf "Upgrade source package %s from %a to %a@." nm
@@ -1335,89 +1658,27 @@ let f () =
t;
Hashtbl.iter
(fun nm v ->
- if not (Hashtbl.mem t nm || ListTbl.mem unchanged (nm, "source")) then
+ if not (Hashtbl.mem t nm || Hashtbl.mem unchanged_src nm) then
Format.eprintf "Adding source package %s@." nm)
u;
+
List.iter
- (fun (arch, (t', u')) ->
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- let v = p.M.version in
- if not (ListTbl.mem unchanged (nm, arch)) then
- match bin_version u' nm with
- Some v' ->
- Format.eprintf
- "Upgrade binary package %s/%s from %a to %a@."
- nm arch M.print_version v M.print_version v'
- | None ->
- Format.eprintf "Remove binary package %s/%s@." nm arch)
- t'.M.packages_by_num;
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- if not (ListTbl.mem unchanged (nm, arch)) then
- if not (ListTbl.mem t'.M.packages_by_name nm) then
- Format.eprintf "Adding binary package %s/%s@." nm arch)
- u'.M.packages_by_num)
+ (fun (arch, st) ->
+ Task.wait (arch_change st (Hashtbl.find unchanged arch)))
l
end;
- if compute_hints then generate_hints t u l l';
+ if compute_hints then generate_hints t u l;
- let print_heidi ch =
- let lines = ref [] in
- let add_line nm vers arch sect =
- let b = Buffer.create 80 in
- Format.bprintf b "%s %a %s %s@." nm M.print_version vers arch sect;
- lines := Buffer.contents b :: !lines
- in
- let output_lines ch =
- List.iter (output_string ch) (List.sort compare !lines); lines := []
- in
- List.iter
- (fun (arch, (t, u)) ->
- let is_preserved nm = ListTbl.mem unchanged (nm, arch) in
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- let sect = if p.M.section = "" then "faux" else p.M.section in
- if is_preserved nm then add_line nm p.M.version arch sect)
- t.M.packages_by_num;
- Hashtbl.iter
- (fun _ p ->
- let nm = p.M.package in
- let sect = if p.M.section = "" then "faux" else p.M.section in
- if not (is_preserved nm) then
- add_line nm p.M.version arch sect)
- u.M.packages_by_num;
- output_lines ch)
- (List.sort (fun (arch, _) (arch', _) -> compare arch arch') l0);
- let is_preserved nm = ListTbl.mem unchanged (nm, "source") in
- let source_sect nm s =
- if Hashtbl.mem fake_src nm then "faux"
- else if s.M.s_section = "" then "unknown"
- else s.M.s_section
- in
- Hashtbl.iter
- (fun nm s ->
- let sect = source_sect nm s in
- if is_preserved nm then add_line nm s.M.s_version "source" sect)
- t;
- Hashtbl.iter
- (fun nm s ->
- let sect = source_sect nm s in
- if not (is_preserved nm) then add_line nm s.M.s_version "source" sect)
- u;
- output_lines ch; flush ch
- in
if !heidi_file <> "" then begin
let ch = open_out !heidi_file in
- print_heidi ch;
+ print_heidi ch is_fake l t u;
close_out ch
end;
- if !excuse_file <> "" then output_reasons l0 !excuse_file
+ if !excuse_file <> "" then output_reasons l !excuse_file;
+
+ List.iter (fun (_, t) -> Task.kill t) l
(****)
@@ -1452,40 +1713,46 @@ let spec =
Arg.align
["--input",
Arg.String (fun d -> dir := d),
- "DIR Select directory containing britney data";
+ "DIR Select directory containing britney data";
"-c",
Arg.String read_conf,
- "FILE Read britney config FILE";
+ "FILE Read britney config FILE";
"--hints",
Arg.String (fun f -> hint_file := f),
- "FILE Output hints to FILE";
+ "FILE Output hints to FILE";
"--all-hints",
Arg.Unit (fun () -> all_hints := true),
- " Show all hints (including those for single packages)";
+ " Show all hints (including single package ones)";
"--heidi",
Arg.String (fun f -> heidi_file := f),
- "FILE Output Heidi results to FILE";
+ "FILE Output Heidi results to FILE";
"--excuses",
Arg.String (fun f -> excuse_file := f),
- "FILE Output excuses to FILE";
+ "FILE Output excuses to FILE";
"--offset",
Arg.Int (fun n -> offset := n),
- "N Move N days into the future";
+ "N Move N days into the future";
+ "--no-cache",
+ Arg.Unit (fun () -> cache_disabled := true),
+ " Disable on-disk caching";
+ "--proc",
+ Arg.Int Task.set_processor_count,
+ "N Provide number of processors (use 1 to disable concurrency)";
"--debug",
Arg.String Debug.set,
- "NAME Activate debug option NAME";
+ "NAME Activate debug option NAME";
"--control-files",
Arg.Unit (fun () -> ()),
- " Currently ignored";
+ " Currently ignored";
"--auto-hinter",
Arg.Unit (fun () -> ()),
- " Currently ignored";
+ " Currently ignored";
"-v",
Arg.Unit (fun () -> ()),
- " Currently ignored";
+ " Currently ignored";
"--compatible",
Arg.Unit (fun () -> ()),
- " Currently ignored"]
+ " Currently ignored"]
in
Arg.parse spec (fun p -> ())
("Usage: " ^ Sys.argv.(0) ^ " OPTIONS\n\
@@ -1495,3 +1762,7 @@ Arg.parse spec (fun p -> ())
\n\
Options:");
f ()
+
+(*
+let _ = Format.eprintf ">>>> %f@." (Unix.times ()).Unix.tms_utime
+*)
diff --git a/upgrade.ml b/upgrade.ml
index f3c3549..dc75020 100644
--- a/upgrade.ml
+++ b/upgrade.ml
@@ -20,6 +20,8 @@
(*
XXXX List broken new packages!
+- Show how important each issue is (use strong dependencies?)
+
- Does it make sense to consider new packages as previously
installable, and report issues for them in a uniform way?
diff --git a/upgrade_common.ml b/upgrade_common.ml
index bd0c6ea..01875b0 100644
--- a/upgrade_common.ml
+++ b/upgrade_common.ml
@@ -524,10 +524,10 @@ let analyze ?(check_new_packages = false) ?reference dist1_state dist2 =
if
PSet.exists (fun p -> not (now_installable (PSet.remove p s))) s
then begin
- if true (*debug*) then begin
- Format.printf "Not minimal:";
- List.iter (fun p -> Format.printf " %a" (Package.print_name dist2) p) l;
- Format.printf "@.";
+ if debug_coinst () then begin
+ Format.eprintf "Not minimal:";
+ List.iter (fun p -> Format.eprintf " %a" (Package.print_name dist2) p) l;
+ Format.eprintf "@.";
end;
end else begin
add_result s
diff --git a/util.ml b/util.ml
index 7f7ee70..8a776a1 100644
--- a/util.ml
+++ b/util.ml
@@ -17,8 +17,11 @@
* along with this program. If not, see .
*)
-let enable_msgs = (* isatty is not available...*)
- (Unix.fstat Unix.stderr).Unix.st_kind = Unix.S_CHR
+let can_enable_msgs = Unix.isatty Unix.stderr
+
+let enable_msgs = ref can_enable_msgs
+
+let enable_messages b = if can_enable_msgs then enable_msgs := b
let cur_msg = ref ""
@@ -34,7 +37,7 @@ let show_msg () =
if !cur_msg <> "" then begin prerr_string !cur_msg; flush stderr end
let set_msg s =
- if enable_msgs && s <> !cur_msg then begin
+ if !enable_msgs && s <> !cur_msg then begin
hide_msg (); cur_msg := s; show_msg ()
end
@@ -70,6 +73,12 @@ module Timer = struct
let stop t = Unix.gettimeofday () -. t
end
+module Utimer = struct
+ type t = float
+ let start () = (Unix.times ()).Unix.tms_utime
+ let stop t = start () -. t
+end
+
module IntSet =
Set.Make (struct type t = int let compare x (y : int) = compare x y end)
@@ -92,6 +101,11 @@ module ListTbl = struct
let mem = Hashtbl.mem
let iter f h = Hashtbl.iter (fun k l -> f k !l) h
+
+ let copy h =
+ let h' = Hashtbl.create (2 * Hashtbl.length h) in
+ Hashtbl.iter (fun k l -> Hashtbl.add h' k (ref !l)) h;
+ h'
end
(****)
diff --git a/util.mli b/util.mli
index a120baf..8a49bc2 100644
--- a/util.mli
+++ b/util.mli
@@ -20,6 +20,7 @@
val set_msg : string -> unit
val hide_msg : unit -> unit
val show_msg : unit -> unit
+val enable_messages : bool -> unit
val set_warning_location : string -> unit
val reset_warning_location : unit -> unit
@@ -35,6 +36,12 @@ module Timer : sig
val stop : t -> float
end
+module Utimer : sig
+ type t
+ val start : unit -> t
+ val stop : t -> float
+end
+
module IntSet : Set.S with type elt = int
module ListTbl : sig
@@ -44,6 +51,7 @@ module ListTbl : sig
val find : ('a, 'b) t -> 'a -> 'b list
val mem : ('a, 'b) t -> 'a -> bool
val iter : ('a -> 'b list -> unit) -> ('a, 'b) t -> unit
+ val copy : ('a, 'b) t -> ('a, 'b) t
end
val print_list :