summaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorlefessan <lefessan@30fcff6e-8de6-41c7-acce-77ff6d1dd07b>2011-04-11 15:24:45 +0000
committerlefessan <lefessan@30fcff6e-8de6-41c7-acce-77ff6d1dd07b>2011-04-11 15:24:45 +0000
commit1b3bbda12e948e4d9fe34a4c59b9dac9e7b64e8f (patch)
treeb1e44c5b779b593f4065c28e790f15b2ac7b777d /sources
parentdecfef69b25175e672a3216d85b9b4c7e1165b98 (diff)
downloadpacemaker-1b3bbda12e948e4d9fe34a4c59b9dac9e7b64e8f.tar.gz
Added sources of simulator and emulator
git-svn-id: https://scm.gforge.inria.fr/svn/pacemaker@2 30fcff6e-8de6-41c7-acce-77ff6d1dd07b
Diffstat (limited to 'sources')
-rw-r--r--sources/fabrice/pacemaker/ChangeLog.txt40
-rw-r--r--sources/fabrice/pacemaker/avt2trace.ml85
-rw-r--r--sources/fabrice/pacemaker/build.ocp70
-rw-r--r--sources/fabrice/pacemaker/compavail.ml238
-rw-r--r--sources/fabrice/pacemaker/data/Makefile.plots45
-rw-r--r--sources/fabrice/pacemaker/data/Makefile.simul64
-rw-r--r--sources/fabrice/pacemaker/data/usetrace.tex137
-rw-r--r--sources/fabrice/pacemaker/doplots.ml1046
-rw-r--r--sources/fabrice/pacemaker/finalplots.ml626
-rw-r--r--sources/fabrice/pacemaker/genrand.ml27
-rw-r--r--sources/fabrice/pacemaker/gentrace.ml141
-rw-r--r--sources/fabrice/pacemaker/liartrace.ml308
-rw-r--r--sources/fabrice/pacemaker/notes.txt15
-rw-r--r--sources/fabrice/pacemaker/overnetTrace.ml130
-rw-r--r--sources/fabrice/pacemaker/pMArgs.ml87
-rw-r--r--sources/fabrice/pacemaker/pMConst.ml210
-rw-r--r--sources/fabrice/pacemaker/pMDriver.ml280
-rw-r--r--sources/fabrice/pacemaker/pMGlobals.ml261
-rw-r--r--sources/fabrice/pacemaker/pMHandlers.ml709
-rw-r--r--sources/fabrice/pacemaker/pMLog.ml53
-rw-r--r--sources/fabrice/pacemaker/pMNetwork.ml435
-rw-r--r--sources/fabrice/pacemaker/pMOptions.ml140
-rw-r--r--sources/fabrice/pacemaker/pMTypes.ml67
-rw-r--r--sources/fabrice/pacemaker/pM_pl_plot.ml442
-rw-r--r--sources/fabrice/pacemaker/pingtrace.ml147
-rw-r--r--sources/fabrice/pacemaker/userand.ml7
-rw-r--r--sources/fabrice/pacemaker/usetrace.ml783
-rw-r--r--sources/fabrice/simulator/build.ocp13
-rw-r--r--sources/fabrice/simulator/notes.txt15
-rw-r--r--sources/fabrice/simulator/randomArray.ml73
-rw-r--r--sources/fabrice/simulator/simulGraphes.ml129
-rw-r--r--sources/fabrice/simulator/simulTrace.ml162
-rw-r--r--sources/fabrice/simulator/simulTypes.ml91
33 files changed, 7076 insertions, 0 deletions
diff --git a/sources/fabrice/pacemaker/ChangeLog.txt b/sources/fabrice/pacemaker/ChangeLog.txt
new file mode 100644
index 0000000..d67b739
--- /dev/null
+++ b/sources/fabrice/pacemaker/ChangeLog.txt
@@ -0,0 +1,40 @@
+2008/09/30:
+ * rotate .log files every hour, delete after 10 hours
+ * started planetlab analysis with pm_planal
+
+2008/09/26:
+ * Bug: refilling candidates with always the same bad peers prevents
+ querying the servers
+ * Bug: server rejecting children connections because it has no parent,
+ should make an exception for servers
+ * Set min reconnect time to 10 minutes
+ * Set reconnect time to master to 10 minutes
+
+2008/09/25:
+ * Experiment: started on all peers at 09:00
+ * Prevent accepting a child when no parents
+ * Drop a well connected peer when an orphan is connecting
+
+2008/09/25:
+ * Experiment: started on first 100 peers at 23:30
+ * Experiment: started on first 50 peers at 16:00
+ * Set ndegree to 10 for servers
+ * Choose first candidates with smallest distance
+ * Disconnect from children with the same distance
+ * Remove old files:
+ * Remove old log files after uploading them, except the current one
+ * Remove old binaries and pretend to still have them
+ * Bug fixes:
+ * Most logs where deleted by mistake between 18h and 23h
+
+2008/09/24:
+ * Bug fixes
+ - IdentifiedMsg provides remote correct port
+ - ByeMsg does not requires IDENTIFIED state to trigger handler
+ - Export new binary only with argument -new_binary
+ - Import new binary only with option "auto_update"
+
+2008/09/23:
+ * Automatically propagates new binaries
+ * Propagates HeartBeatMsg to all neighbours
+ * Master and Server peers implementaed
diff --git a/sources/fabrice/pacemaker/avt2trace.ml b/sources/fabrice/pacemaker/avt2trace.ml
new file mode 100644
index 0000000..e032acb
--- /dev/null
+++ b/sources/fabrice/pacemaker/avt2trace.ml
@@ -0,0 +1,85 @@
+open Sets
+
+open SimulTypes
+open SimulTrace
+
+let input_line ic =
+ let s = String.lowercase (input_line ic) in
+ for i = 0 to String.length s - 1 do
+ match s.[i] with
+ '\t' -> s.[i] <- ' '
+ | _ -> ()
+ done;
+ s
+
+
+let filename = Sys.argv.(1)
+
+let _ =
+ let events = ref [] in
+
+ let min_time = ref max_float in
+ let max_time = ref min_float in
+ let npeers = ref 0 in
+ let ic = open_in filename in
+ begin
+ try
+ while true do
+ let line = input_line ic in
+ match String2.split_simplify line ' ' with
+ id :: nsessions :: sessions ->
+ let id = !npeers in
+ let rec iter sessions =
+ match sessions with
+ | [] -> ()
+ | begin_time :: end_time :: sessions ->
+ let begin_time = float_of_string begin_time in
+ let end_time = float_of_string end_time in
+ min_time := min begin_time !min_time;
+ max_time := max end_time !max_time;
+ events := (begin_time, id, true) :: (end_time, id, false) :: !events;
+ iter sessions
+ | _ ->
+ Printf.printf "Unexpected line [%s]\n"
+ (String.escaped line);
+ assert false
+ in
+ iter sessions;
+ incr npeers;
+ | _ -> assert false
+ done;
+ with
+ End_of_file -> close_in ic;
+ end;
+
+ Printf.printf "Sorting...\n%!";
+ let events = List.sort compare !events in
+ let ndays = 1 + int_of_float ((!max_time -. !min_time) /. 86400.) in
+ let oc = open_out (filename ^ ".dat") in
+ trace_output oc (Peers !npeers);
+ trace_output oc (Days (ndays, 60 * 24));
+ for i = 0 to !npeers - 1 do
+ trace_output oc (Peer (i,0., "avt"));
+ done;
+ let rec iter round next_round events =
+ match events with
+ [] -> ()
+ | (time, p, status) :: tail ->
+
+ if time < next_round then begin
+ trace_output oc (if status then
+ On p
+ else
+ Off p);
+ iter round next_round tail
+
+ end else begin
+ trace_output oc (Round (round+1));
+ iter (round+1) (next_round +. 60.) events
+ end
+
+ in
+ trace_output oc (Round 0);
+ iter 0 (!min_time +. 60.) events;
+ trace_output oc End;
+ close_out oc \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/build.ocp b/sources/fabrice/pacemaker/build.ocp
new file mode 100644
index 0000000..70cc473
--- /dev/null
+++ b/sources/fabrice/pacemaker/build.ocp
@@ -0,0 +1,70 @@
+pp = "camlp4o.opt"
+
+requires = [ "cdk"; "simul"; "net" ]
+
+begin "gentrace"
+ files = "gentrace.ml"
+ type = program
+end
+
+(* Compute:
+ peers_per_round (number of peers online per round)
+ availability (real availability, and expected measured availability)
+ sessions (CDF of sessions lengths)
+*)
+begin "compavail"
+ files = "compavail.ml"
+ type = program
+end
+
+begin "usetrace"
+ files = "usetrace.ml"
+ type = program
+end
+
+begin "pingtrace"
+ files = "pingtrace.ml"
+ type = program
+end
+
+begin "liartrace"
+ files = "liartrace.ml"
+ type = program
+end
+
+begin "overnettrace"
+ files = "overnetTrace.ml"
+ type = program
+end
+
+begin "avt2trace"
+ files = "avt2trace.ml"
+ type = program
+end
+
+begin "doplots"
+ files = "doplots.ml"
+ type = program
+end
+
+
+begin "pacemaker"
+ files = [
+ "pMTypes.ml";
+ "pMConst.ml";
+ "pMNetwork.ml";
+ "pMOptions.ml";
+ "pMArgs.ml";
+ "pMGlobals.ml";
+ "pMLog.ml";
+ "pMHandlers.ml";
+ "pMDriver.ml" ]
+ type = program
+end
+
+
+begin "pm_planal"
+
+ files = [ "pM_pl_plot.ml" ]
+ type = program
+end
diff --git a/sources/fabrice/pacemaker/compavail.ml b/sources/fabrice/pacemaker/compavail.ml
new file mode 100644
index 0000000..567dbbf
--- /dev/null
+++ b/sources/fabrice/pacemaker/compavail.ml
@@ -0,0 +1,238 @@
+open SimulTrace
+open SimulTypes
+
+(* Compute peers_per_round *)
+
+let day = 60 * 24
+
+type peer = {
+ mutable availabilities : int array;
+ }
+
+let ndays = ref 0
+
+let anon_args = ref [ Sys.argv.(0) ]
+let accuracy_arg = ref 0
+let subdir = ref None
+
+let _ =
+ Arg.parse [
+ "-subdir", Arg.String (fun s ->
+ subdir := Some s), "<subdir> : set subdir for data files";
+ "-accu", Arg.Int ((:=) accuracy_arg), " <n>: period between heartbeats";
+ "-ndays", Arg.Int ((:=) ndays), " <n> : number of days";
+ ]
+ (fun t -> anon_args := t :: !anon_args) ""
+
+
+let subdir =
+ match !subdir with
+ None -> failwith "You must specify a subdirectory for data files"
+ | Some dir ->
+ Unix2.safe_mkdir (Filename2.of_string dir);
+ dir
+
+
+let argv = Array.of_list (List.rev !anon_args)
+let trace = argv.(1)
+let accuracy = if !accuracy_arg = 0 then 60 else !accuracy_arg
+
+let peers, nrounds, do_round = trace_read trace
+
+let nrounds =
+ if !ndays <> 0 then
+ day * !ndays
+ else nrounds
+
+let peers_per_round = Array.create nrounds 0
+let sessions = ref []
+
+let npeers = Array.length peers
+
+let peers2 = Array.init npeers (fun _ ->
+ {
+ availabilities = [| 0; 0;0;0;0;0;0;0 |]
+ })
+
+let _ =
+ let hour = ref 0 in
+ let next_ticket = ref (Random.int accuracy) in
+ for round = 0 to nrounds - 1 do
+
+ do_round round;
+ let nb_on = ref 0 in
+ for i = 0 to npeers -1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+ if p.state = ON then begin
+ p2.availabilities.(0) <- p2.availabilities.(0) + 1;
+ p.session <- p.session + 1;
+ incr nb_on
+ end else
+ if p.session > 0 then begin
+ sessions := p.session :: !sessions;
+ p.session <- 0;
+ end
+ done;
+
+
+ if round = !next_ticket then begin
+ incr hour;
+ next_ticket := accuracy * !hour + Random.int accuracy;
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if p.state = ON then
+ p2.availabilities.(1) <- p2.availabilities.(1) + accuracy
+ done
+ end;
+
+ if round mod accuracy = 1 then begin
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if p.state = ON then
+ if p.session > 5 then begin
+ p2.availabilities.(2) <- p2.availabilities.(2) + 60;
+ if p.session > 10 then begin
+ p2.availabilities.(3) <- p2.availabilities.(3) + 60;
+ if p.session > 20 then begin
+ p2.availabilities.(4) <- p2.availabilities.(4) + 60;
+ if p.session > 30 then begin
+ p2.availabilities.(5) <- p2.availabilities.(5) + 60;
+ if p.session > 40 then begin
+ p2.availabilities.(6) <- p2.availabilities.(6) + 60;
+ if p.session > 50 then begin
+ p2.availabilities.(7) <- p2.availabilities.(7) + 60;
+ end end
+ end end
+ end
+ end
+ done
+ end;
+
+
+ peers_per_round.(round) <- !nb_on
+ done
+
+(*
+let _ =
+ let oc = open_out "peers_per_round.txt" in
+ for round = 0 to nrounds - 1 do
+ output_string oc (Printf.sprintf "%d %d\n" round peers_per_round.(round))
+ done;
+ close_out oc
+
+let _ =
+ let oc = open_out "peers_per_round.plot" in
+ output_string oc (Printf.sprintf "
+set out 'peers_per_round.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'peers_per_round.eps'
+set yrange [0:%d]
+set xrange [0:%d]
+set ylabel 'Number of available peers'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"peers_per_round.txt\" using ($1):($2) title 'Peers'
+ " npeers nrounds);
+ close_out oc
+ *)
+
+let _ =
+ if !accuracy_arg = 0 then
+ let avail = Array.init 8 (fun _ -> Array.create npeers 0) in
+ for i = 0 to npeers - 1 do
+ for k = 0 to 7 do
+ avail.(k).(i) <- peers2.(i).availabilities.(k)
+ done
+ done;
+ Array.iter (fun avail ->
+ Array.sort compare avail) avail;
+
+ let oc = open_out (Printf.sprintf "%s/availpolicies.txt" subdir) in
+ for i = 0 to npeers - 1 do
+ output_string oc (Printf.sprintf "%d " i);
+ for k = 0 to 7 do
+ output_string oc (Printf.sprintf "%.3f "
+ (float_of_int avail.(k).(i) /. float_of_int nrounds))
+ done;
+ output_string oc "\n";
+ done;
+ close_out oc
+ else
+ let error = Array.create npeers 0 in
+ for i = 0 to npeers - 1 do
+ error.(i) <-
+ abs (peers2.(i).availabilities.(1) - peers2.(i).availabilities.(1))
+ done;
+ Array.sort compare error;
+
+ let oc = open_out (
+ (Printf.sprintf "%s/availpolicies_%d.txt" subdir accuracy)) in
+ for i = 0 to npeers - 1 do
+ output_string oc (Printf.sprintf "%d " i);
+ output_string oc (Printf.sprintf "%.3f "
+ (float_of_int error.(i) /. float_of_int nrounds));
+ output_string oc "\n";
+ done;
+ close_out oc
+
+let npoints = 30
+
+let _ =
+
+
+ let every =
+ if npeers > npoints then
+ Printf.sprintf " every %d " (npeers / npoints) else "" in
+
+ let oc = open_out (
+ Printf.sprintf "%s/availpolicies.plot" subdir) in
+ output_string oc (Printf.sprintf "
+set out 'availpolicies.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'availpolicies.eps'
+set key left
+set yrange [0:%d*21.0/20]
+set xrange [0:%d*21.0/20]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set data style linespoints
+
+plot \"availpolicies.txt\" %s using ($1):($2) title 'Real Availability', \"availpolicies.txt\" %s using ($1):($3) title 'Measured Availability (random)', \"availpolicies.txt\" %s using ($1):($4) title 'Measured Availability (5)',\"availpolicies.txt\" %s using ($1):($5) title 'Measured Availability (10)',\"availpolicies.txt\" %s using ($1):($6) title 'Measured Availability (20)',\"availpolicies.txt\" %s using ($1):($7) title 'Measured Availability (30)',\"availpolicies.txt\" %s using ($1):($8) title 'Measured Availability (40)',\"availpolicies.txt\" %s using ($1):($9) title 'Measured Availability (50)'
+ " 1 npeers every every every every every every every every);
+ close_out oc
+
+(*
+let _ =
+ let sessions = Array.of_list !sessions in
+ let nsessions = Array.length sessions in
+ Array.sort compare sessions;
+ let oc = open_out "sessions.txt" in
+ for i = 0 to nsessions - 1 do
+ output_string oc (Printf.sprintf "%d %d\n" i sessions.(i))
+ done;
+ close_out oc;
+
+ let oc = open_out "sessions.plot" in
+ output_string oc (Printf.sprintf "
+set out 'sessions.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'sessions.eps'
+set logscale y
+set yrange [1:%d]
+set xrange [0:%d]
+set ylabel 'Session Length (minutes)'
+set xlabel 'CDF of sessions'
+
+set data style lines
+
+plot \"sessions.txt\" %s using ($1):($2) title 'Sessions', 60 title '1 hour'
+ " sessions.(nsessions-1) nsessions);
+ close_out oc
+*) \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/data/Makefile.plots b/sources/fabrice/pacemaker/data/Makefile.plots
new file mode 100644
index 0000000..e27049d
--- /dev/null
+++ b/sources/fabrice/pacemaker/data/Makefile.plots
@@ -0,0 +1,45 @@
+FIGURES=\
+ figs/ask_root_msgs.eps \
+ figs/max_distance_per_round.eps \
+ figs/mean_avail_distance.eps \
+ figs/peers_per_round.eps \
+ figs/sessions.eps \
+ figs/connections.eps \
+ figs/error_avail.eps \
+ figs/ping_error_avail.eps \
+
+#availability.eps connections.eps all_availability.eps all_error_avail.eps error_avail.eps ping_error_avail.eps liars_measure.eps
+
+all: figs $(FIGURES) $(FIGURES:.pdf=.eps)
+
+figs:
+ mkdir -p figs
+
+%.eps: %.cdf
+%.cdf: %.txt
+ sort -n -k 2 $*.txt | cat -b > $*.cdf
+
+figs/mean_avail_distance.eps: \
+ usetrace0x10/mean_avail_distance1.cdf \
+ usetrace0x10/mean_avail_distance2.cdf \
+ usetrace0x10/mean_avail_distance3.cdf \
+ usetrace0x10/mean_avail_distance4.cdf \
+ usetrace0x10/mean_avail_distance5.cdf \
+ usetrace0x10/mean_avail_distance6.cdf \
+ usetrace0x10/mean_avail_distance7.cdf \
+ usetrace0x10/mean_avail_distance8.cdf \
+
+figs/connections.eps: usetrace0x10/connections3.txt
+usetrace0x10/connections3.txt: usetrace0x10/connections2.txt
+ cat -n usetrace0x10/connections2.txt > usetrace0x10/connections3.txt
+usetrace0x10/connections2.txt: usetrace0x10/connections.txt
+ tac usetrace0x10/connections.txt > usetrace0x10/connections2.txt
+
+figs/peers_per_round.eps: figs/peers_per_round.plot usetrace0x10/peers_per_round.txt
+ gnuplot < figs/peers_per_round.plot
+
+%.eps: %.plot
+ gnuplot < $*.plot
+
+%.pdf: %.eps
+ epstopdf $*.eps
diff --git a/sources/fabrice/pacemaker/data/Makefile.simul b/sources/fabrice/pacemaker/data/Makefile.simul
new file mode 100644
index 0000000..739a4bd
--- /dev/null
+++ b/sources/fabrice/pacemaker/data/Makefile.simul
@@ -0,0 +1,64 @@
+BIN_DIR=/home/lefessan/devel/onzego/research/pace-maker
+USETRACE_BIN=$(BIN_DIR)/usetrace
+COMPAVAIL_BIN=$(BIN_DIR)/compavail
+PINGTRACE_BIN=$(BIN_DIR)/pingtrace
+LIARTRACE_BIN=$(BIN_DIR)/liartrace
+
+COMPAVAIL_DATA= compavail/availpolicies.txt
+
+USETRACE_DATA= \
+usetrace$(NSELFISH)x$(ACCURACY)/ask_root_msgs.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/availability.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/connections.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/error_avail.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/lost_tickets.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/max_distance_per_round.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/mean_avail_distance1.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/mean_avail_distance2.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/mean_avail_distance3.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/mean_avail_distance4.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/peers_per_round.txt \
+usetrace$(NSELFISH)x$(ACCURACY)/sessions.txt
+
+PINGTRACE_DATA= \
+pingtrace$(NDEGREE)/ping_availability_$(NDEGREE).txt \
+pingtrace$(NDEGREE)/ping_error_avail_$(NDEGREE).txt
+
+LIARTRACE_DATA= \
+liartrace$(NLIARS)x$(NPROBES)/liar_measured_$(NLIARS)x$(NPROBES).txt \
+liartrace$(NLIARS)x$(NPROBES)/liar_measuredE_$(NLIARS)x$(NPROBES).txt \
+liartrace$(NLIARS)x$(NPROBES)/liar_number_$(NLIARS)x$(NPROBES).txt \
+liartrace$(NLIARS)x$(NPROBES)/liar_real_$(NLIARS)x$(NPROBES).txt \
+liartrace$(NLIARS)x$(NPROBES)/liar_real.txt
+
+DATA= $(COMPAVAIL_DATA)
+
+all: $(DATA)
+ for i in 10 20 30 60 120; do \
+ $(MAKE) -f Makefile.simul NSELFISH=0 ACCURACY=$$i selfish; \
+ done
+ for i in 0 10 20 30 40 50 60 70 80 90; do \
+ $(MAKE) -f Makefile.simul NSELFISH=$$i ACCURACY=60 selfish; \
+ done
+ for i in 5 10 15 20 25 30; do \
+ $(MAKE) -f Makefile.simul NDEGREE=$$i ping; \
+ done
+ for i in 1 2 3; do \
+ $(MAKE) -f Makefile.simul NLIARS=5 NPROBES=$$i liars; \
+ done
+
+selfish: $(USETRACE_DATA)
+ping: $(PINGTRACE_DATA)
+liars: $(LIARTRACE_DATA)
+
+$(LIARTRACE_DATA): trace.dat
+ $(LIARTRACE_BIN) -subdir liartrace$(NLIARS)x$(NPROBES) -nliars $(NLIARS) -probes $(NPROBES) trace.dat
+
+$(USETRACE_DATA): trace.dat
+ time $(USETRACE_BIN) -subdir usetrace$(NSELFISH)x$(ACCURACY) -accuracy $(ACCURACY) -nselfish $(NSELFISH) trace.dat
+
+$(COMPAVAIL_DATA): trace.dat
+ time $(COMPAVAIL_BIN) -subdir compavail trace.dat
+
+$(PINGTRACE_DATA): trace.dat
+ time $(PINGTRACE_BIN) -subdir pingtrace$(NDEGREE) -degree $(NDEGREE) trace.dat
diff --git a/sources/fabrice/pacemaker/data/usetrace.tex b/sources/fabrice/pacemaker/data/usetrace.tex
new file mode 100644
index 0000000..1495c26
--- /dev/null
+++ b/sources/fabrice/pacemaker/data/usetrace.tex
@@ -0,0 +1,137 @@
+\documentclass[11pt,a4paper]{article}
+
+\usepackage{epsfig}
+
+\newcommand{\figurebox}[1]{#1}
+
+\def\figheader{fig:}
+
+\newcommand{\psfigure}[3]{ % {scale}{filename=label}{caption}
+ \begin{figure}[t]\begin{center}%
+ \epsfig{file=#2,width=#1\hsize}%
+ \begin{quote}\let\normalsize\small\caption{#3\label{\figheader#2}}\end{quote}%
+ \end{center}
+ \vspace{-0.8cm}%
+\end{figure}}
+
+\newcommand{\psfigureR}[3]{ % {scale}{filename=label}{caption}
+ \begin{figure}[t]\begin{center}%
+ \epsfig{file=#2,width=#1\hsize,angle=-90}%
+ \begin{quote}\let\normalsize\small\caption{#3\label{\figheader#2}}\end{quote}%
+ \end{center}
+ \vspace{-0.8cm}%
+\end{figure}}
+
+\begin{document}
+
+\input{data.tex}
+
+\section*{Simulation Parameters}
+
+Here are the parameters used to compute the simulation:
+
+\begin{tabular}{|l|l|}
+\hline
+Network size: &\npeers peers\\
+Length: &\nminutes minutes (\ndays days)\\
+Availability: & Uniform Distribution in [0.1;1.0]\\
+Deconnections per day:& Uniform Distribution in [1;10]\\
+Timezones:& Uniform Distribution in [0;12]\\
+\hline
+\end{tabular}\\
+
+ For each peer, we randomly choose an availability and a number of
+disconnections per day. We then compute its probabilities of coming online
+and offline using Markov Chains. We use these probabilities in the
+simulation.
+
+ Note that the uniform distribution of availabilities is not standard in
+peer-to-peer systems, but here, we want to show that the measured
+availability is not different from the real availability, so the
+distribution of availabilities does not matter. We will check later that
+the mesh behaves correctly with a powerlaw, but the mesh is not the focus
+of this paper...
+
+ Timezones are used to obtain a diurnal pattern: during day, peers have
+twice their normal probability of coming online and half their normal
+probability of going offline.
+
+\section*{Simulation Results}
+
+Here are some values obtained during the simulation:
+
+\begin{tabular}{|l|l|}
+\hline
+Number of Sessions : &\nsessions sessions\\
+\hline
+\end{tabular}
+
+\section*{Simulation Mesh}
+
+ We simulate a network of peers connected in a mesh around a server. The
+server diffuses tickets every hours to measure the availability of peers.
+
+ In the current simulation, the mesh protocol is the following: the server
+has a degree of 10 children, and each peer has a degree of 5 children and 5
+parents. To connect to the mesh, a peer first queries the server, which
+replies with a list of its children. The peer then queries the children.
+Every children either accepts the peer as a child, or send a random of its
+children. The process iterates until the peer is connected to 5 different
+parents.
+
+ We take the following (local) decisions to improve the system:
+\begin{itemize}
+\item At every round, one a peer has a free child slot, it chooses among
+all the candidates who queried it during the round (one minute) the one
+with the best measured availability.
+\item A peer disconnects its children which are at the same distance from
+the server as it. (hey, this is not a local property ! we should only
+do it after a ticket diffusion or during the query !)
+\end{itemize}
+
+ Every round in the simulation takes one minute. From a communication
+point of view, it allows us to assume some timeout on messages that allows
+detection of peer disconnection (TCP keepalive is 30 seconds).
+
+\begin{center}
+
+\psfigureR{1.5}{sessions}{CDF of Sessions lengths. Note that the median
+session length is around two hours. It does not follow a powerlaw, but we
+don't really.}
+
+\psfigureR{1.5}{max_distance_per_round}{Maximal distance to the server over
+ time. Note that the diameter of the network is not too high.}
+
+ \psfigureR{1.5}{peers_per_round}{Number of peers online over time. Note
+that since the timezones of peers are only on 12 hours, we observe some
+diurnal pattern that we would not observe if the distribution was over 24
+hours.}
+
+\psfigureR{1.5}{connections}{Time spent between the beginning of a peer
+session and the connection to its first parent. Only in some rare cases, it is
+above 7 minutes. Since in our system, we focus on long session times
+(median session length is two hours), this delay is neglectible.}
+
+\psfigureR{1.5}{mean_avail_distance}{Mean Availability of Connected Peers
+depending on their distance to the server. It shows that peers at distance
+1 from the server have a much better availability, and so on...}
+
+% \psfigureR{1.5}{availpolicies}{}
+
+ \psfigureR{1.5}{ask_root_msgs}{The number of AskRoot messages sent
+per minute to the server in our mesh.}
+
+
+\psfigureR{1.5}{availability}{Measured availability compared to real
+availability. Note that the difference between the real availability and
+the availability measured using tickets is very close.}
+ \psfigureR{1.5}{error_avail}{}
+
+ \psfigureR{1.5}{all_availability}{}
+ \psfigureR{1.5}{all_error_avail}{}
+
+ \psfigureR{1.5}{ping_error_avail}{}
+ \psfigureR{1.5}{liars_measure}{}
+
+\end{center}
+\end{document}
diff --git a/sources/fabrice/pacemaker/doplots.ml b/sources/fabrice/pacemaker/doplots.ml
new file mode 100644
index 0000000..99e861e
--- /dev/null
+++ b/sources/fabrice/pacemaker/doplots.ml
@@ -0,0 +1,1046 @@
+open SimulGraphes
+
+let data_dir = Filename2.of_string "/home/lefessan/devel/onzego/research/pace-maker/data"
+let current_dir = Filename2.of_string "."
+
+
+let _ =
+ Unix2.safe_mkdir (Filename2.of_string "figs");
+ List.iter (fun basename ->
+ File.of_string (Filename2.add_basename current_dir basename)
+ (File.to_string (Filename2.add_basename data_dir basename)))
+ [ "Makefile.simul"; "Makefile.plots"; "usetrace.tex"]
+
+
+let npeers1, exp =
+ let exp = ref false in
+ let npeers = ref 0 in
+ let ic = open_in "trace.dat" in
+ for i = 0 to 10 do
+ match SimulTrace.trace_input ic with
+ SimulTrace.Exponential -> exp := true
+ | SimulTrace.Peers n -> npeers := n
+ | _ -> ()
+ done;
+ !npeers, !exp
+
+let _ =
+ Printf.printf "1/ Update simulations\n%!";
+ Sys.command "make -f Makefile.simul"
+
+
+let _ =
+ Printf.printf "2/ Prepare data for plots\n%!"
+
+
+let max_error_abs, max_error_rel =
+ let errors_abs = ref [] in
+ let errors_pct = ref [] in
+ File.iter_lines (fun line ->
+ match String2.split_simplify line ' ' with
+ [ _; avail1; avail2 ] ->
+ let avail1 = float_of_string avail1 in
+ let avail2 = float_of_string avail2 in
+ let error_abs = abs_float (avail1 -. avail2) in
+ let error_pct = if avail1 > 0.0001 then
+ error_abs /. avail1 else 0. in
+ errors_abs := error_abs :: !errors_abs;
+ errors_pct := error_pct :: !errors_pct;
+ | _ -> assert false
+ ) (Filename2.of_string "usetrace0x60/availability.txt");
+ let errors_abs = List.sort compare !errors_abs in
+ let errors_pct = List.sort compare !errors_pct in
+ let oc = open_out "usetrace0x60/availability2.txt" in
+ let count = ref 1 in
+ let max_error_abs = ref 0. in
+ let max_error_rel = ref 0. in
+ List.iter2 (fun e1 e2 ->
+ Printf.fprintf oc "%d %f %f\n" !count e1 e2;
+ incr count;
+ if e1 > !max_error_abs then max_error_abs := e1;
+ if e1 > !max_error_rel then max_error_rel := e1
+ ) errors_abs errors_pct;
+ close_out oc;
+ !max_error_abs, !max_error_rel
+
+let npeers =
+ Printf.printf "figs/availability.plot\n%!";
+ let np, _,_ = on_file "usetrace0x60/availability.txt" in
+ let npoints = 1000000 in
+ let every = if np > npoints then np / npoints else 1 in
+ let oc = open_out "figs/availability.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/availability.eps'
+set yrange [0:1]
+set xrange [0:%d*51.0/50]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style linespoints
+
+plot \"usetrace0x60/availability2.txt\" every %d using ($1):($2) title 'Absolute Error', \"usetrace0x60/availability2.txt\" every %d using ($1):($3) title 'Relative Error'
+ "
+ np every every
+ ;
+ close_out oc;
+ np
+
+let nsessions =
+ Printf.printf "figs/sessions.plot\n%!";
+ let nsessions, mins, maxs = on_file "usetrace0x10/sessions.txt" in
+
+ let npoints = 1000 in
+ let every = if nsessions > npoints then nsessions / npoints else 1 in
+
+ let oc = open_out "figs/sessions.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/sessions.eps'
+
+set logscale y
+set yrange [1:%.0f]
+set xrange [0:%d]
+set ylabel 'Session Length (minutes)'
+set xlabel 'CDF of sessions'
+
+set data style lines
+set key left
+
+plot \"usetrace0x10/sessions.txt\" every %d using ($1):($2) title 'Sessions', 60 title '1 hour'
+ "
+ maxs.(1) nsessions every
+ ;
+ close_out oc;
+ nsessions
+
+let variance_of filename =
+ let ic = open_in filename in
+ let count = ref 0 in
+ let prevs = ref [||] in
+ let diffs = ref [||] in
+ (try
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ prevs := Array.create (List.length line) 0.;
+ diffs := Array.create (List.length line) 0.;
+ let prevs = !prevs in
+ let diffs = !diffs in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ prevs.(i) <- x;
+ diffs.(i) <- x) line;
+ while true do
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ let y = max (x -. prevs.(i)) ( prevs.(i) -. x) in
+(* if i = 1 then
+ Printf.printf "%d %.1f->%.1f = %.1f\n" i prevs.(i) x y; *)
+ prevs.(i) <- x;
+ diffs.(i) <- y +. diffs.(i)) line;
+ done
+
+ with End_of_file -> ());
+ let diffs = !diffs in
+ if !count > 0 then begin
+ for i = 0 to Array.length diffs - 1 do
+ diffs.(i) <- diffs.(i) /. float_of_int !count;
+ done;
+ end;
+ !count, diffs
+
+
+let nminutes =
+ Printf.printf "figs/mean_avail_distance.plot\n%!";
+ let ntime, _, _ = on_file "usetrace0x10/mean_avail_distance1.txt" in
+ let every = max 1 (ntime / 200) in
+ let oc = open_out "figs/mean_avail_distance.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/mean_avail_distance.eps'
+set yrange [0:1001]
+set xrange [0:%d]
+set ylabel 'Mean availability (1/1000)'
+set xlabel 'CDF of minutes'
+set title 'Mean avail/distance %d peers%s'
+
+set key bottom
+set data style lines
+
+# We don't print distance=5 because the variance is too high
+
+ plot \"usetrace0x10/mean_avail_distance1.cdf\" every %d using ($1):($3) title 'distance 1'"
+ ntime npeers (if exp then " exp" else " uni")every;
+
+ (try
+ for i = 2 to 10 do
+ let filename = Printf.sprintf "usetrace0x10/mean_avail_distance%d.txt" i in
+ if Sys.file_exists filename then
+ let _, diffs = variance_of filename in
+ if diffs.(1) < 5. then begin
+ Printf.fprintf oc ",\"usetrace0x10/mean_avail_distance%d.cdf\" every %d using ($1):($3) title 'distance %d'" i every i
+ end else begin
+ Printf.printf "stopping at curve %d\n" i;
+ raise Exit
+ end
+ done with Exit -> ());
+ Printf.fprintf oc "\n";
+ close_out oc;
+ ntime
+
+let nsessions =
+ Printf.printf "figs/connections.plot\n%!";
+ let nconns,_, maxs = on_file "usetrace0x10/connections.txt" in
+ let oc = open_out "figs/connections.plot" in
+
+ let npoints = 1000 in
+ let every = nconns / npoints in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/connections.eps'
+
+set yrange [1:%.1f*21/20]
+set xrange [0:%d*51/50]
+set ylabel 'Time to first connection (minutes)'
+set xlabel 'CDF of connections'
+
+set key left
+set data style lines
+
+ plot \"usetrace0x10/connections3.txt\" every %d using ($1/%d):($2) title 'Connection time (minutes)'
+ " maxs.(1) nconns every every;
+ close_out oc;
+ nsessions
+
+let _ =
+ Printf.printf "figs/peers_er_round.plot\n%!";
+ let oc = open_out "figs/peers_per_round.plot" in
+ let ntime, _, maxs = on_file "usetrace0x10/peers_per_round.txt" in
+
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/peers_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'Number of available peers'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"usetrace0x10/peers_per_round.txt\" using ($1):($2) title 'available peers'
+ " ntime maxs.(1);
+ close_out oc
+
+(*
+let _ =
+ let oc = open_out "ask_root_msgs.plot" in
+ let ntime, _, maxs = on_file "ask_root_msgs.txt" in
+
+ Printf.fprintf oc "
+
+set out 'ask_root_msgs.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'ask_root_msgs.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'AskRoot messages per minute'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"ask_root_msgs.txt\" using ($1):($2) title 'AskRoot msgs(%d peers)'
+ " ntime maxs.(1) npeers;
+ close_out oc
+
+
+let _ =
+ let ntime, _, maxs = on_file "max_distance_per_round.txt" in
+ let oc = open_out "max_distance_per_round.plot" in
+
+ Printf.fprintf oc "set out 'max_distance_per_round.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'max_distance_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*12/10]
+set ylabel 'Maximal distance from server'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+ plot \"max_distance_per_round.txt\" using ($1):($2) title 'maximal distance'
+ " ntime maxs.(1);
+ close_out oc
+
+
+let _ =
+ let plots = ref [] in
+ for nselfish = 1 to 99 do
+ let filename = Printf.sprintf "availability_%d.txt" nselfish in
+ if Sys.file_exists filename then
+ plots := nselfish :: !plots
+ done;
+
+ let oc = open_out "all_availability.plot" in
+
+ Printf.fprintf oc "
+set out 'all_availability.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'all_availability.eps'
+set yrange [0:1]
+set xrange [0:%d]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"availability.txt\" using ($1):($2) title 'real availability' " npeers;
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"availability_%d.txt\" using ($1):($3) title 'measured availability (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+
+
+(*
+ let oc = open_out "all_lost_tickets.plot" in
+ let filename = match !plots with
+ [] ->
+ "lost_tickets.txt"
+ | max :: _ ->
+ Printf.sprintf "lost_tickets_%d.txt" max
+ in
+ let nhours, mins, maxs = on_file filename in
+
+ Printf.fprintf oc "
+set out 'all_lost_tickets.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'all_lost_tickets.eps'
+set yrange [0:%.0f]
+set xrange [0:%d]
+set ylabel 'Number of lost heartbeats'
+set xlabel 'Time (minutes)'
+
+set key left
+set data style lines
+
+ plot \"lost_tickets.txt\" using ($1):($2) title 'lost heartbeats (0 selfish peers)'"
+ maxs.(1) nhours;
+
+
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"lost_tickets_%d.txt\" using ($1):($2) title 'lost heartbeats (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+*)
+
+
+
+
+
+
+
+ let maxe = ref 0.1 in
+ List.iter (fun plot ->
+ let filename = Printf.sprintf "error_avail_%d.txt" plot in
+ let _, _, maxs = on_file filename in
+ maxe := max !maxe maxs.(1)
+ ) !plots;
+
+ let oc = open_out "all_error_avail.plot" in
+
+ Printf.fprintf oc "
+set out 'all_error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'all_error_avail.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Error on measured availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"error_avail.txt\" using ($1):($2) title 'error (no selfish peers)'"
+ !maxe npeers;
+
+
+ let w = ref 0 in
+ List.iter (fun nselfish ->
+ incr w;
+ Printf.fprintf oc ", \"error_avail_%d.txt\" using ($1):($2) title 'error (%d%% selfish peers)' lw %d"
+ nselfish nselfish !w
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+()
+*)
+
+let max_error =
+ let _, _, maxs = on_file "usetrace0x60/error_avail.txt" in
+ let oc = open_out "figs/error_avail.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/error_avail.eps'
+set yrange [0:%.4f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+
+plot \"usetrace0x60/error_avail.txt\" every 2 using ($1):($2) title 'error'
+ " maxs.(1) npeers;
+ close_out oc;
+ maxs.(1)
+
+let _ =
+ let max_error = ref max_error in
+ let degrees = ref [] in
+ for degree = 1 to 100 do
+ let filename = Printf.sprintf "pingtrace%d/ping_error_avail_%d.txt" degree degree in
+ if Sys.file_exists filename then begin
+ let _, _, maxs = on_file filename in
+ max_error := max !max_error maxs.(1);
+ degrees := degree :: !degrees;
+ end
+ done;
+ let oc = open_out "figs/ping_error_avail.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/ping_error_avail.eps'
+set yrange [0.001:1]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+set key left
+set logscale y
+
+plot \
+ \"usetrace0x60/error_avail.txt\" every 2 using ($1):($2) title 'diffusion error'"
+ (*!max_error*) npeers;
+ List.iter (fun degree ->
+ Printf.fprintf oc ",\"pingtrace%d/ping_error_avail_%d.txt\" every 2 using ($1):($2) title 'ping error (%d observers)'" degree degree degree)
+ (List.rev !degrees);
+
+ Printf.fprintf oc "\n";
+ close_out oc
+
+ (*
+
+let _ =
+ let degrees = ref [] in
+ let maxa = ref 0.1 in
+ for degree = 1 to 20 do
+ for nprobes = 1 to 5 do
+ let filename = Printf.sprintf "liar_measured_%dx%d.txt"
+ degree nprobes in
+ if Sys.file_exists filename then
+ let _, _, maxs = on_file filename in
+ maxa := max !maxa maxs.(1);
+ degrees := (degree, nprobes) :: !degrees
+ done;
+ done;
+
+ let maxa = 1.3 *. !maxa in
+ let oc = open_out "liars_measure.plot" in
+ Printf.fprintf oc "
+ set xtics (\"5\" 7200, \"10\" 20400, \"15\" 21600, \"20\" 28800)
+set out 'liars_measure.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'liars_measure.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Network Availability'
+set xlabel 'Time (days)'
+
+set data style lines
+
+ plot \"liar_real.txt\" using ($1):($2) title 'real (without liars)'"
+ maxa nminutes;
+
+ List.iter (fun (degree, nprobes) ->
+ Printf.fprintf oc
+ ", \"liar_measured_%dx%d.txt\" using ($1):($2) title 'measured (%d challenges, %d observers)'" degree nprobes nprobes degree
+ ) !degrees;
+ Printf.fprintf oc "\n";
+ close_out oc
+
+let _ =
+ let _, _, maxs = on_file "error_avail.txt" in
+ let oc = open_out "error_avail.plot" in
+ Printf.fprintf oc "
+set out 'error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'error_avail.eps'
+set yrange [0:%.3f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+
+plot \"error_avail.txt\" every 2 using ($1):($2) title 'error'
+" maxs.(1) npeers;
+ close_out oc
+
+let _ =
+ let npoints = 50 in
+ let every = 1 + npeers / npoints in
+ let files = ref [] in
+ let maxi = ref 0. in
+ for i = 1 to 300 do
+ let filename = Printf.sprintf "error_avail_period%d.txt" i in
+ if Sys.file_exists filename then begin
+ let _, _, maxs = on_file filename in
+ for_every every filename;
+ maxi := max maxs.(1) !maxi;
+ files := i :: !files
+ end
+ done;
+
+ let oc = open_out "error_avail_periods.plot" in
+ Printf.fprintf oc "
+set out 'error_avail_periods.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'error_avail_periods.eps'
+set yrange [0.0001:%.3f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style linespoints
+set key left
+
+plot " !maxi npeers;
+
+ match List.rev !files with
+ [] -> ()
+ | n :: tail ->
+ Printf.fprintf oc " \"error_avail_period%d.txt\" every %d using ($1):($2) title 'error (period %d minutes)'" n every n;
+ List.iter (fun n ->
+ Printf.fprintf oc ", \"error_avail_period%d.txt\" every %d using ($1):($2) title 'error (period %d minutes)'" n every n
+ ) tail;
+
+ Printf.fprintf oc "\n";
+ close_out oc
+
+
+
+let _ =
+ let npoints = 50 in
+ let every = 1 + npeers / npoints in
+ let files = ref [] in
+ let maxi = ref 0. in
+ for i = 1 to 40 do
+ let filename = Printf.sprintf "error_avail_ndays%d0.txt" i in
+ if Sys.file_exists filename then begin
+ let _, _, maxs = on_file filename in
+ for_every every filename;
+ maxi := max maxs.(1) !maxi;
+ files := i * 10 :: !files
+ end
+ done;
+
+ let oc = open_out "error_avail_ndays.plot" in
+ Printf.fprintf oc "
+set out 'error_avail_ndays.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'error_avail_ndays.eps'
+set yrange [0.0001:%.3f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style linespoints
+set key left
+
+plot " !maxi npeers;
+
+ match List.rev !files with
+ [] -> ()
+ | n :: tail ->
+ Printf.fprintf oc " \"error_avail_ndays%d.txt\" every %d using ($1):($2) title 'error (%d days)'" n every n;
+ List.iter (fun n ->
+ Printf.fprintf oc ", \"error_avail_ndays%d.txt\" every %d using ($1):($2) title 'error (%d days)'" n every n
+ ) tail;
+
+ Printf.fprintf oc "\n";
+ close_out oc
+
+let _ =
+ let oc = open_out "data.tex" in
+
+ Printf.fprintf oc "\\def\\npeers{%d }\n" npeers;
+ Printf.fprintf oc "\\def\\nminutes{%d }\n" nminutes;
+ Printf.fprintf oc "\\def\\ndays{%d }\n" (nminutes / 24 / 60);
+ Printf.fprintf oc "\\def\\nsessions{%d }\n" nsessions;
+
+ close_out oc
+
+
+ open SimulGraphes
+
+let npeers =
+
+ let np, _,_ = on_file "availability.txt" in
+ let npoints = 1000000 in
+ let every = if np > npoints then np / npoints else 1 in
+ let oc = open_out "availability.plot" in
+ Printf.fprintf oc "
+set out 'availability.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'availability.eps'
+set yrange [0:1]
+set xrange [0:%d*51.0/50]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style linespoints
+
+plot \"availability.txt\" every %d using ($1):($2) title 'Real Availability', \"availability.txt\" every %d using ($1):($3) title 'Measured Availability (random)'
+ "
+ np every every
+ ;
+ close_out oc;
+ np
+
+let nsessions =
+
+ let nsessions, mins, maxs = on_file "usetrace0x10/sessions.txt" in
+
+ let npoints = 1000 in
+ let every = if nsessions > npoints then nsessions / npoints else 1 in
+
+ let oc = open_out "figs/sessions.plot" in
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/sessions.eps'
+
+set logscale y
+set yrange [1:%.0f]
+set xrange [0:%d]
+set ylabel 'Session Length (minutes)'
+set xlabel 'CDF of sessions'
+
+set data style lines
+set key left
+
+plot \"sessions.txt\" every %d using ($1):($2) title 'Sessions', 60 title '1 hour'
+ "
+ maxs.(1) nsessions every
+ ;
+ close_out oc;
+ nsessions
+*)
+
+(*
+let variance_of filename =
+ let ic = open_in filename in
+ let count = ref 0 in
+ let prevs = ref [||] in
+ let diffs = ref [||] in
+ (try
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ prevs := Array.create (List.length line) 0.;
+ diffs := Array.create (List.length line) 0.;
+ let prevs = !prevs in
+ let diffs = !diffs in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ prevs.(i) <- x;
+ diffs.(i) <- x) line;
+ while true do
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ let y = max (x -. prevs.(i)) ( prevs.(i) -. x) in
+(* if i = 1 then
+ Printf.printf "%d %.1f->%.1f = %.1f\n" i prevs.(i) x y; *)
+ prevs.(i) <- x;
+ diffs.(i) <- y +. diffs.(i)) line;
+ done
+
+ with End_of_file -> ());
+ let diffs = !diffs in
+ if !count > 0 then begin
+ for i = 0 to Array.length diffs - 1 do
+ diffs.(i) <- diffs.(i) /. float_of_int !count;
+ done;
+ end;
+ !count, diffs
+
+let nminutes =
+ let ntime, _, _ = on_file "mean_avail_distance1.txt" in
+
+ let oc = open_out "mean_avail_distance.plot" in
+ Printf.fprintf oc "
+ set out 'mean_avail_distance.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'mean_avail_distance.eps'
+set yrange [0:1001]
+set xrange [0:%d]
+set ylabel 'Mean availability (1/1000)'
+set xlabel 'Time (minutes)'
+
+set key bottom
+set data style lines
+
+# We don't print distance=5 because the variance is too high
+
+ plot \"mean_avail_distance1.txt\" using ($1):($2) title 'distance 1'"
+ ntime;
+
+ (try
+ for i = 2 to 10 do
+ let filename = Printf.sprintf "mean_avail_distance%d.txt" i in
+ if Sys.file_exists filename then
+ let _, diffs = variance_of filename in
+ if diffs.(1) < 5. then begin
+ Printf.fprintf oc ",\"mean_avail_distance%d.txt\" using ($1):($2) title 'distance %d'" i i
+ end else begin
+ Printf.printf "stopping at curve %d\n" i;
+ raise Exit
+ end
+ done with Exit -> ());
+ Printf.fprintf oc "\n";
+ close_out oc;
+ ntime
+
+let nsessions =
+ let nconns,_, maxs = on_file "connections.txt" in
+ let oc = open_out "connections.plot" in
+ let npoints = 10000 in
+ let every = if nconns > npoints then (nconns-1) / npoints else 1 in
+
+ let nconns =
+ let nconns' = every * (nconns / every) + 1 in
+ if nconns' <> nconns then begin
+
+ let nconns' = nconns' + every in
+ Printf.printf "every: %d, nconns: %d, nconns': %d\n" every nconns nconns';
+ let oc = open_out_gen [Open_append] 0o644 "connections.txt" in
+ for i = nconns+1 to nconns' do
+ Printf.fprintf oc "%d %.0f\n" i maxs.(1)
+ done;
+ close_out oc;
+ nconns'+1
+
+ end else nconns in
+
+
+
+ Printf.fprintf oc "
+ set out 'connections.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'connections.eps'
+
+set yrange [1:%.1f*21/20]
+set xrange [0:%d*51/50]
+set ylabel 'Time to first connection (minutes)'
+set xlabel 'CDF of connections'
+
+set key left
+set data style lines
+
+ plot \"connections.txt\" every %d using ($1):($2) title 'Connection time (minutes)'
+ " maxs.(1) nconns every;
+ close_out oc;
+ nsessions
+
+let _ =
+ let oc = open_out "peers_per_round.plot" in
+ let ntime, _, maxs = on_file "peers_per_round.txt" in
+
+ Printf.fprintf oc "
+
+set out 'peers_per_round.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'peers_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'Number of available peers'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"peers_per_round.txt\" using ($1):($2) title 'available peers'
+ " ntime maxs.(1);
+ close_out oc
+
+ *)
+
+let _ =
+ let oc = open_out "figs/ask_root_msgs.plot" in
+ let ntime, _, maxs = on_file "usetrace0x10/ask_root_msgs.txt" in
+
+ let every = max 1 (ntime / 200) in
+ Printf.fprintf oc "
+
+set out 'figs/ask_root_msgs.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'AskRoot messages per minute'
+set xlabel 'CDF of minutes'
+
+set data style lines
+
+plot \"usetrace0x10/ask_root_msgs2.txt\" every %d using ($1):($3) title 'AskRoot msgs(%d peers)'
+ " ntime maxs.(1) every npeers;
+ close_out oc
+
+let _ =
+ let ntime, _, maxs = on_file "usetrace0x10/max_distance_per_round.txt" in
+ let oc = open_out "figs/max_distance_per_round.plot" in
+ let every = max 1 (ntime / 200) in
+
+ Printf.fprintf oc "
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/max_distance_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*12/10]
+set ylabel 'Maximal distance from server'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+ plot \"usetrace0x10/max_distance_per_round2.txt\" every %d using ($1):($3) title 'maximal distance(%d peers)'
+ " ntime maxs.(1) every npeers;
+ close_out oc
+
+let _ =
+ let plots = ref [] in
+ for nselfish = 1 to 99 do
+ let filename = Printf.sprintf "usetrace%dx60/availability.txt" nselfish in
+ if Sys.file_exists filename then
+ plots := nselfish :: !plots
+ done;
+
+ (*
+ let oc = open_out "figs/selfish_impact.plot" in
+
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/selfish_impact.eps'
+set yrange [0:1]
+set xrange [0:%d]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"availability.txt\" using ($1):($2) title 'real availability' " npeers;
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"availability_%d.txt\" using ($1):($3) title 'measured availability (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+*)
+
+(*
+ let oc = open_out "all_lost_tickets.plot" in
+ let filename = match !plots with
+ [] ->
+ "lost_tickets.txt"
+ | max :: _ ->
+ Printf.sprintf "lost_tickets_%d.txt" max
+ in
+ let nhours, mins, maxs = on_file filename in
+
+ Printf.fprintf oc "
+set out 'all_lost_tickets.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'all_lost_tickets.eps'
+set yrange [0:%.0f]
+set xrange [0:%d]
+set ylabel 'Number of lost heartbeats'
+set xlabel 'Time (minutes)'
+
+set key left
+set data style lines
+
+ plot \"lost_tickets.txt\" using ($1):($2) title 'lost heartbeats (0 selfish peers)'"
+ maxs.(1) nhours;
+
+
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"lost_tickets_%d.txt\" using ($1):($2) title 'lost heartbeats (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+*)
+
+
+
+
+
+
+
+ let maxe = ref 0.1 in
+ List.iter (fun plot ->
+ let filename = Printf.sprintf "usetrace%dx60/error_avail.txt" plot in
+ let _, _, maxs = on_file filename in
+ maxe := max !maxe maxs.(1)
+ ) !plots;
+
+ let oc = open_out "figs/selfish_impact.plot" in
+
+ Printf.fprintf oc "
+
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'figs/selfish_impact.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Error on measured availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"usetrace0x60/error_avail.txt\" using ($1):($2) title 'error (no selfish peers)'"
+ !maxe npeers;
+
+
+ let w = ref 0 in
+ List.iter (fun nselfish ->
+ incr w;
+ Printf.fprintf oc ", \"usetrace%dx60/error_avail.txt\" using ($1):($2) title 'error (%d%% selfish peers)' lw %d"
+ nselfish nselfish !w
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+()
+
+ (*
+
+let max_error =
+ let _, _, maxs = on_file "error_avail.txt" in
+ let oc = open_out "error_avail.plot" in
+ Printf.fprintf oc "
+set out 'error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'error_avail.eps'
+set yrange [0:%.4f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+
+plot \"error_avail.txt\" every 2 using ($1):($2) title 'error'
+ " maxs.(1) npeers;
+ close_out oc;
+ maxs.(1)
+
+let _ =
+ let max_error = ref max_error in
+ let degrees = ref [] in
+ for degree = 1 to 100 do
+ let filename = Printf.sprintf "ping_error_avail_%d.txt" degree in
+ if Sys.file_exists filename then begin
+ let _, _, maxs = on_file filename in
+ max_error := max !max_error maxs.(1);
+ degrees := degree :: !degrees;
+ end
+ done;
+ let oc = open_out "ping_error_avail.plot" in
+ Printf.fprintf oc "
+set out 'ping_error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'ping_error_avail.eps'
+set yrange [0.01:1]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+set key left
+set logscale y
+
+plot \
+ \"error_avail.txt\" every 2 using ($1):($2) title 'diffusion error'"
+ (*!max_error*) npeers;
+ List.iter (fun degree ->
+ Printf.fprintf oc ",\"ping_error_avail_%d.txt\" every 2 using ($1):($2) title 'ping error (%d observers)'" degree degree)
+ (List.rev !degrees);
+
+ Printf.fprintf oc "\n";
+ close_out oc
+
+
+
+let _ =
+ let degrees = ref [] in
+ let maxa = ref 0.1 in
+ for degree = 1 to 20 do
+ for nprobes = 1 to 5 do
+ let filename = Printf.sprintf "liar_measured_%dx%d.txt"
+ degree nprobes in
+ if Sys.file_exists filename then
+ let _, _, maxs = on_file filename in
+ maxa := max !maxa maxs.(1);
+ degrees := (degree, nprobes) :: !degrees
+ done;
+ done;
+
+ let maxa = 1.3 *. !maxa in
+ let oc = open_out "liars_measure.plot" in
+ Printf.fprintf oc "
+ set xtics (\"5\" 7200, \"10\" 20400, \"15\" 21600, \"20\" 28800)
+set out 'liars_measure.eps'
+set terminal postscript eps enhanced \"Helvetica\" 20
+set out 'liars_measure.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Network Availability'
+set xlabel 'Time (days)'
+
+set data style lines
+
+ plot \"liar_real.txt\" using ($1):($2) title 'real (without liars)'"
+ maxa nminutes;
+
+ List.iter (fun (degree, nprobes) ->
+ Printf.fprintf oc
+ ", \"liar_measured_%dx%d.txt\" using ($1):($2) title 'measured (%d challenges, %d observers)'" degree nprobes nprobes degree
+ ) !degrees;
+ Printf.fprintf oc "\n";
+ close_out oc
+ *)
+
+(*
+let _ =
+ let oc = open_out "data.tex" in
+
+ Printf.fprintf oc "\\def\\npeers{%d }\n" npeers;
+ Printf.fprintf oc "\\def\\nminutes{%d }\n" nminutes;
+ Printf.fprintf oc "\\def\\ndays{%d }\n" (nminutes / 24 / 60);
+ Printf.fprintf oc "\\def\\nsessions{%d }\n" nsessions;
+
+ close_out oc
+ *)
+
+let _ =
+ Printf.printf "3/ Compute plots\n%!";
+ Sys.command "make -f Makefile.plots" \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/finalplots.ml b/sources/fabrice/pacemaker/finalplots.ml
new file mode 100644
index 0000000..83824a3
--- /dev/null
+++ b/sources/fabrice/pacemaker/finalplots.ml
@@ -0,0 +1,626 @@
+open SimulGraphes
+
+let npeers =
+
+ let np, _,_ = on_file "uniform/availability.txt" in
+ let npoints = 1000000 in
+ let every = if np > npoints then np / npoints else 1 in
+ let oc = open_out "availability.plot" in
+ Printf.fprintf oc "
+set out 'availability.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'availability.eps'
+set yrange [0:1]
+set xrange [0:%d*51.0/50]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style linespoints
+
+plot \"uniform/availability.txt\" every %d using ($1):($2) title 'Real Availability', \"uniform/availability.txt\" every %d using ($1):($3) title 'Measured Availability (random)'
+ "
+ np every every
+ ;
+ close_out oc;
+ np
+
+
+let nsessions =
+
+ let nsessions, mins, maxs = on_file "uniform/sessions.txt" in
+
+ let npoints = 1000 in
+ let every = if nsessions > npoints then nsessions / npoints else 1 in
+
+ let oc = open_out "sessions.plot" in
+ Printf.fprintf oc "
+ set out 'sessions.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'sessions.eps'
+
+set logscale y
+set yrange [1:%.0f]
+set xrange [0:%d]
+set ylabel 'Session Length (minutes)'
+set xlabel 'CDF of sessions'
+
+set data style lines
+set key left
+
+plot \"uniform/sessions.txt\" every %d using ($1):($2) title 'Sessions', 60 title '1 hour'
+ "
+ maxs.(1) nsessions every
+ ;
+ close_out oc;
+ nsessions
+
+
+let variance_of filename =
+ let ic = open_in filename in
+ let count = ref 0 in
+ let prevs = ref [||] in
+ let diffs = ref [||] in
+ (try
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ prevs := Array.create (List.length line) 0.;
+ diffs := Array.create (List.length line) 0.;
+ let prevs = !prevs in
+ let diffs = !diffs in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ prevs.(i) <- x;
+ diffs.(i) <- x) line;
+ while true do
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ let y = max (x -. prevs.(i)) ( prevs.(i) -. x) in
+(* if i = 1 then
+ Printf.printf "%d %.1f->%.1f = %.1f\n" i prevs.(i) x y; *)
+ prevs.(i) <- x;
+ diffs.(i) <- y +. diffs.(i)) line;
+ done
+
+ with End_of_file -> ());
+ let diffs = !diffs in
+ if !count > 0 then begin
+ for i = 0 to Array.length diffs - 1 do
+ diffs.(i) <- diffs.(i) /. float_of_int !count;
+ done;
+ end;
+ !count, diffs
+
+let nminutes =
+ let ntime, _, _ = on_file "uniform/mean_avail_distance1.txt" in
+
+ let oc = open_out "mean_avail_distance.plot" in
+ Printf.fprintf oc "
+ set out 'mean_avail_distance.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'mean_avail_distance.eps'
+set yrange [0:1001]
+set xrange [0:%d]
+set ylabel 'Mean availability (1/1000)'
+set xlabel 'Time (minutes)'
+
+set key bottom
+set data style lines
+
+# We don't print distance=5 because the variance is too high
+
+ plot \"uniform/mean_avail_distance1.txt\" using ($1):($2) title 'distance 1'"
+ ntime;
+
+ (try
+ for i = 2 to 10 do
+ let filename = Printf.sprintf "uniform/mean_avail_distance%d.txt" i in
+ if Sys.file_exists filename then
+ let _, diffs = variance_of filename in
+ if diffs.(1) < 5. then begin
+ Printf.fprintf oc ",\"uniform/mean_avail_distance%d.txt\" using ($1):($2) title 'distance %d'" i i
+ end else begin
+ Printf.printf "stopping at curve %d\n" i;
+ raise Exit
+ end
+ done with Exit -> ());
+ Printf.fprintf oc "\n";
+ close_out oc;
+ ntime
+
+let nsessions =
+ let nconns,_, maxs = on_file "uniform/connections.txt" in
+ let oc = open_out "connections.plot" in
+ let npoints = 10000 in
+ let every = if nconns > npoints then (nconns-1) / npoints else 1 in
+
+ let nconns =
+ let nconns' = every * (nconns / every) + 1 in
+ if nconns' <> nconns then begin
+
+ let nconns' = nconns' + every in
+ Printf.printf "every: %d, nconns: %d, nconns': %d\n" every nconns nconns';
+ let oc = open_out_gen [Open_append] 0o644 "connections.txt" in
+ for i = nconns+1 to nconns' do
+ Printf.fprintf oc "%d %.0f\n" i maxs.(1)
+ done;
+ close_out oc;
+ nconns'+1
+
+ end else nconns in
+
+
+
+ Printf.fprintf oc "
+ set out 'connections.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'connections.eps'
+
+set yrange [1:%.1f*21/20]
+set xrange [0:%d*51/50]
+set ylabel 'Time to first connection (minutes)'
+set xlabel 'CDF of connections'
+
+set key left
+set data style lines
+
+ plot \"uniform/connections.txt\" every %d using ($1):($2) title 'Connection time (minutes)'
+ " maxs.(1) nconns every;
+ close_out oc;
+ nsessions
+
+let _ =
+ let oc = open_out "peers_per_round.plot" in
+ let ntime, _, maxs = on_file "uniform/peers_per_round.txt" in
+
+ Printf.fprintf oc "
+
+set out 'peers_per_round.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'peers_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'Number of available peers'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"uniform/peers_per_round.txt\" using ($1):($2) title 'available peers'
+ " ntime maxs.(1);
+ close_out oc
+
+let _ =
+ let oc = open_out "ask_root_msgs.plot" in
+ let ntime, _, maxs = on_file "uniform/ask_root_msgs.txt" in
+
+ Printf.fprintf oc "
+
+set out 'ask_root_msgs.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'ask_root_msgs.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*21/20]
+set ylabel 'AskRoot messages per minute'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"uniform/ask_root_msgs.txt\" using ($1):($2) title 'AskRoot msgs(%d peers)'
+ " ntime maxs.(1) npeers;
+ close_out oc
+
+
+let _ =
+ let ntime, _, maxs = on_file "uniform/max_distance_per_round.txt" in
+ let oc = open_out "max_distance_per_round.plot" in
+
+ Printf.fprintf oc "set out 'max_distance_per_round.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'max_distance_per_round.eps'
+set xrange [0:%d]
+set yrange [0:%.0f*12/10]
+set ylabel 'Maximal distance from server'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+ plot \"uniform/max_distance_per_round.txt\" using ($1):($2) title 'maximal distance'
+ " ntime maxs.(1);
+ close_out oc
+
+let _ =
+ let plots = ref [] in
+ for nselfish = 1 to 99 do
+ let filename = Printf.sprintf "uniform/availability_%d.txt" nselfish in
+ if Sys.file_exists filename then
+ plots := nselfish :: !plots
+ done;
+
+ let oc = open_out "all_availability.plot" in
+
+ Printf.fprintf oc "
+set out 'all_availability.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'all_availability.eps'
+set yrange [0:1]
+set xrange [0:%d]
+set ylabel 'Availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"uniform/availability.txt\" using ($1):($2) title 'real availability' " npeers;
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"uniform/availability_%d.txt\" using ($1):($3) title 'measured availability (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+
+
+(*
+ let oc = open_out "all_lost_tickets.plot" in
+ let filename = match !plots with
+ [] ->
+ "lost_tickets.txt"
+ | max :: _ ->
+ Printf.sprintf "lost_tickets_%d.txt" max
+ in
+ let nhours, mins, maxs = on_file filename in
+
+ Printf.fprintf oc "
+set out 'all_lost_tickets.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'all_lost_tickets.eps'
+set yrange [0:%.0f]
+set xrange [0:%d]
+set ylabel 'Number of lost heartbeats'
+set xlabel 'Time (minutes)'
+
+set key left
+set data style lines
+
+ plot \"lost_tickets.txt\" using ($1):($2) title 'lost heartbeats (0 selfish peers)'"
+ maxs.(1) nhours;
+
+
+ List.iter (fun nselfish ->
+ Printf.fprintf oc ", \"lost_tickets_%d.txt\" using ($1):($2) title 'lost heartbeats (%d selfish peers)'"
+ nselfish nselfish
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+*)
+
+
+
+
+
+
+
+ let maxe = ref 0.1 in
+ List.iter (fun plot ->
+ let filename = Printf.sprintf "uniform/error_avail_%d.txt" plot in
+ let _, _, maxs = on_file filename in
+ maxe := max !maxe maxs.(1)
+ ) !plots;
+
+ let oc = open_out "all_error_avail.plot" in
+
+ Printf.fprintf oc "
+set out 'all_error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'all_error_avail.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Error on measured availability'
+set xlabel 'CDF of peers'
+
+set key left
+set data style lines
+
+ plot \"uniform/error_avail.txt\" using ($1):($2) title 'error (no selfish peers)'"
+ !maxe npeers;
+
+
+ let w = ref 0 in
+ List.iter (fun nselfish ->
+ incr w;
+ Printf.fprintf oc ", \"uniform/error_avail_%d.txt\" using ($1):($2) title 'error (%d%% selfish peers)' lw %d"
+ nselfish nselfish !w
+ ) (List.rev !plots);
+ Printf.fprintf oc "\n";
+ close_out oc;
+()
+
+
+let max_error =
+ let _, _, maxs = on_file "uniform/error_avail.txt" in
+ let oc = open_out "error_avail.plot" in
+ Printf.fprintf oc "
+set out 'error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'error_avail.eps'
+set yrange [0:%.4f]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+
+plot \"uniform/error_avail.txt\" every 2 using ($1):($2) title 'error'
+ " maxs.(1) npeers;
+ close_out oc;
+ maxs.(1)
+
+let _ =
+ let max_error = ref max_error in
+ let degrees = ref [] in
+ for degree = 1 to 100 do
+ let filename = Printf.sprintf "uniform/ping_error_avail_%d.txt" degree in
+ if Sys.file_exists filename then begin
+ let _, _, maxs = on_file filename in
+ max_error := max !max_error maxs.(1);
+ degrees := degree :: !degrees;
+ end
+ done;
+ let oc = open_out "ping_error_avail.plot" in
+ Printf.fprintf oc "
+set out 'ping_error_avail.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'ping_error_avail.eps'
+set yrange [0.01:1]
+set xrange [0:%d+2]
+set ylabel 'Error in measured availability'
+set xlabel 'CDF of peers'
+set data style lines
+set key left
+set logscale y
+
+plot \
+ \"uniform/error_avail.txt\" every 2 using ($1):($2) title 'diffusion error'"
+ (*!max_error*) npeers;
+ List.iter (fun degree ->
+ Printf.fprintf oc ",\"uniform/ping_error_avail_%d.txt\" every 2 using ($1):($2) title 'ping error (%d observers)'" degree degree)
+ (List.rev !degrees);
+
+ Printf.fprintf oc "\n";
+ close_out oc
+
+
+
+let _ =
+ let degrees = ref [] in
+ let maxa = ref 0.1 in
+ for degree = 1 to 20 do
+ for nprobes = 1 to 5 do
+ let filename = Printf.sprintf "uniform/liar_measured_%dx%d.txt"
+ degree nprobes in
+ if Sys.file_exists filename then
+ let _, _, maxs = on_file filename in
+ maxa := max !maxa maxs.(1);
+ degrees := (degree, nprobes) :: !degrees
+ done;
+ done;
+
+ let maxa = 1.3 *. !maxa in
+ let oc = open_out "liars_measure.plot" in
+ Printf.fprintf oc "
+ set xtics (\"5\" 7200, \"10\" 14400, \"15\" 21600, \"20\" 28800)
+set out 'liars_measure.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out 'liars_measure.eps'
+set yrange [0:%.1f]
+set xrange [0:%d]
+set ylabel 'Network Availability'
+set xlabel 'Time (days)'
+
+set data style lines
+
+ plot \"uniform/liar_real.txt\" using ($1):($2) title 'real (without liars)'"
+ maxa nminutes;
+
+ List.iter (fun (degree, nprobes) ->
+ Printf.fprintf oc
+ ", \"uniform/liar_measured_%dx%d.txt\" using ($1):($2) title 'measured (%d challenges, %d observers)'" degree nprobes nprobes degree
+ ) !degrees;
+ Printf.fprintf oc "\n";
+ close_out oc
+
+let _ =
+ File.of_string (Filename2.of_string "Makefile") "FIGURES=availability.eps max_distance_per_round.eps peers_per_round.eps mean_avail_distance.eps connections.eps sessions.eps ask_root_msgs.eps all_availability.eps all_error_avail.eps error_avail.eps ping_error_avail.eps liars_measure.eps
+
+#availpolicies.eps
+
+usetrace: $(FIGURES) $(FIGURES:.eps=.plot) usetrace.pdf
+
+availability.plot max_distance_per_round.plot peers_per_round.plot mean_avail_distance.plot connections.plot sessions.plot:uniform/availability.txt uniform/max_distance_per_round.txt uniform/peers_per_round.txt uniform/connections.txt uniform/sessions.txt
+ doplots
+
+mean_avail_distance.eps: mean_avail_distance.plot uniform/mean_avail_distance1.txt
+ gnuplot < mean_avail_distance.plot
+
+ping_error_avail.eps: uniform/error_avail.txt ping_error_avail.plot uniform/ping_error_avail_10.txt
+ gnuplot < ping_error_avail.plot
+
+liars_measure.eps: liars_measure.plot uniform/liar_real.txt
+ gnuplot < liars_measure.plot
+
+all_availability.eps: uniform/availability_0.txt all_availability.plot
+ gnuplot < all_availability.plot
+
+all_error_avail.eps: uniform/error_avail_0.txt all_error_avail.plot
+ gnuplot < all_error_avail.plot
+
+all_lost_tickets.eps: uniform/lost_tickets_0.txt all_lost_tickets.plot
+ gnuplot < all_lost_tickets.plot
+
+%.eps: %.plot uniform/%.txt
+ gnuplot < $*.plot
+
+%.pdf: %.eps
+ epstopdf $*.eps
+
+usetrace.pdf: $(FIGURES:.eps=.pdf) usetrace.tex
+ pdflatex usetrace.tex
+"
+
+let _ =
+ File.of_string (Filename2.of_string "usetrace.tex")
+ "\\documentclass[11pt,a4paper]{article}
+
+\\usepackage{epsfig}
+
+\\newcommand{\\figurebox}[1]{#1}
+
+\\def\\figheader{fig:}
+
+\\newcommand{\\psfigure}[3]{ % {scale}{filename=label}{caption}
+ \\begin{figure}[t]\\begin{center}%
+ \\epsfig{file=#2,width=#1\\hsize}%
+ \\begin{quote}\\let\\normalsize\\small\\caption{#3\\label{\\figheader#2}}\\end{quote}%
+ \\end{center}
+ \\vspace{-0.8cm}%
+\\end{figure}}
+
+\\newcommand{\\psfigureR}[3]{ % {scale}{filename=label}{caption}
+ \\begin{figure}[t]\\begin{center}%
+ \\epsfig{file=#2,width=#1\\hsize,angle=-90}%
+ \\begin{quote}\\let\\normalsize\\small\\caption{#3\\label{\\figheader#2}}\\end{quote}%
+ \\end{center}
+ \\vspace{-0.8cm}%
+\\end{figure}}
+
+\\begin{document}
+
+\\input{data.tex}
+
+\\section*{Simulation Parameters}
+
+Here are the parameters used to compute the simulation:
+
+\\begin{tabular}{|l|l|}
+\\hline
+Network size: &\\npeers peers\\\\
+Length: &\\nminutes minutes (\\ndays days)\\\\
+Availability: & Uniform Distribution in [0.1;1.0]\\\\
+Deconnections per day:& Uniform Distribution in [1;10]\\\\
+Timezones:& Uniform Distribution in [0;12]\\\\
+\\hline
+\\end{tabular}\\\\
+
+ For each peer, we randomly choose an availability and a number of
+disconnections per day. We then compute its probabilities of coming online
+and offline using Markov Chains. We use these probabilities in the
+simulation.
+
+ Note that the uniform distribution of availabilities is not standard in
+peer-to-peer systems, but here, we want to show that the measured
+availability is not different from the real availability, so the
+distribution of availabilities does not matter. We will check later that
+the mesh behaves correctly with a powerlaw, but the mesh is not the focus
+of this paper...
+
+ Timezones are used to obtain a diurnal pattern: during day, peers have
+twice their normal probability of coming online and half their normal
+probability of going offline.
+
+\\section*{Simulation Results}
+
+Here are some values obtained during the simulation:
+
+\\begin{tabular}{|l|l|}
+\\hline
+Number of Sessions : &\\nsessions sessions\\\\
+\\hline
+\\end{tabular}
+
+\\section*{Simulation Mesh}
+
+ We simulate a network of peers connected in a mesh around a server. The
+server diffuses tickets every hours to measure the availability of peers.
+
+ In the current simulation, the mesh protocol is the following: the server
+has a degree of 10 children, and each peer has a degree of 5 children and 5
+parents. To connect to the mesh, a peer first queries the server, which
+replies with a list of its children. The peer then queries the children.
+Every children either accepts the peer as a child, or send a random of its
+children. The process iterates until the peer is connected to 5 different
+parents.
+
+ We take the following (local) decisions to improve the system:
+\\begin{itemize}
+\\item At every round, one a peer has a free child slot, it chooses among
+all the candidates who queried it during the round (one minute) the one
+with the best measured availability.
+\\item A peer disconnects its children which are at the same distance from
+the server as it. (hey, this is not a local property ! we should only
+do it after a ticket diffusion or during the query !)
+\\end{itemize}
+
+ Every round in the simulation takes one minute. From a communication
+point of view, it allows us to assume some timeout on messages that allows
+detection of peer disconnection (TCP keepalive is 30 seconds).
+
+\\begin{center}
+
+\\psfigureR{1.5}{sessions}{CDF of Sessions lengths. Note that the median
+session length is around two hours. It does not follow a powerlaw, but we
+don't really.}
+
+\\psfigureR{1.5}{max_distance_per_round}{Maximal distance to the server over
+ time. Note that the diameter of the network is not too high.}
+
+ \\psfigureR{1.5}{peers_per_round}{Number of peers online over time. Note
+that since the timezones of peers are only on 12 hours, we observe some
+diurnal pattern that we would not observe if the distribution was over 24
+hours.}
+
+\\psfigureR{1.5}{connections}{Time spent between the beginning of a peer
+session and the connection to its first parent. Only in some rare cases, it is
+above 7 minutes. Since in our system, we focus on long session times
+(median session length is two hours), this delay is neglectible.}
+
+\\psfigureR{1.5}{mean_avail_distance}{Mean Availability of Connected Peers
+depending on their distance to the server. It shows that peers at distance
+1 from the server have a much better availability, and so on...}
+
+% \\psfigureR{1.5}{availpolicies}{}
+
+ \\psfigureR{1.5}{ask_root_msgs}{The number of AskRoot messages sent
+per minute to the server in our mesh.}
+
+
+\\psfigureR{1.5}{availability}{Measured availability compared to real
+availability. Note that the difference between the real availability and
+the availability measured using tickets is very close.}
+ \\psfigureR{1.5}{error_avail}{}
+
+ \\psfigureR{1.5}{all_availability}{}
+ \\psfigureR{1.5}{all_error_avail}{}
+
+ \\psfigureR{1.5}{ping_error_avail}{}
+ \\psfigureR{1.5}{liars_measure}{}
+
+\\end{center}
+\\end{document}
+"
+
+
+
+
+
+let _ =
+ let oc = open_out "data.tex" in
+
+ Printf.fprintf oc "\\def\\npeers{%d }\n" npeers;
+ Printf.fprintf oc "\\def\\nminutes{%d }\n" nminutes;
+ Printf.fprintf oc "\\def\\ndays{%d }\n" (nminutes / 24 / 60);
+ Printf.fprintf oc "\\def\\nsessions{%d }\n" nsessions;
+
+ close_out oc
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/genrand.ml b/sources/fabrice/pacemaker/genrand.ml
new file mode 100644
index 0000000..718762f
--- /dev/null
+++ b/sources/fabrice/pacemaker/genrand.ml
@@ -0,0 +1,27 @@
+open BigEndian
+
+let _ =
+ Printf.printf "genrand <filename> <nrandom>\n%!"
+
+let filename = Sys.argv.(1)
+let n = Int64.of_string Sys.argv.(2)
+
+let block = 4096
+let blockL = Int64.of_int block
+
+let _ =
+ let bound = 1 lsl 29 in
+ let oc = open_out filename in
+ let s = String.create (4 * block) in
+ let nblocks = Int64.to_int (Int64.div n blockL) + 1 in
+ for i = 1 to nblocks do
+ for x = 0 to block - 1 do
+
+ str_int s (x*4) (Random.int bound)
+
+ done;
+ output_string oc s
+
+ done;
+ close_out oc
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/gentrace.ml b/sources/fabrice/pacemaker/gentrace.ml
new file mode 100644
index 0000000..be75c4e
--- /dev/null
+++ b/sources/fabrice/pacemaker/gentrace.ml
@@ -0,0 +1,141 @@
+open SimulTypes
+open SimulTrace
+
+let day = 60 * 24
+
+type peer2 = {
+ lambda : float;
+ mu : float;
+ decs : int;
+ mutable timezone : int;
+
+ }
+
+let _ =
+ if Array.length Sys.argv < 4 then begin
+ Printf.printf "./gentrace trace_name npeers ndays\n";
+ Printf.printf "ERROR: bad number of arguments\n";
+ exit 2
+ end
+
+let trace = Sys.argv.(1)
+let npeers = int_of_string Sys.argv.(2)
+let ndays = int_of_string Sys.argv.(3)
+let nrounds = day * ndays
+let exponential = ref (
+ Array.length Sys.argv = 5 && Sys.argv.(4) = "exp")
+
+let _ = Random.self_init ()
+
+let oc = open_out trace
+
+let _ =
+ trace_output oc (Peers npeers);
+ trace_output oc (Days (ndays, day));
+ if !exponential then
+ trace_output oc Exponential;
+ ()
+
+
+let peers = Array.init npeers (fun i ->
+
+ let avail = Random.int 900000 in
+ let decs = 1 + Random.int 10 in
+ let timezone = Random.int (60 * 12) in
+
+ let x = float_of_int avail /. 900000. in
+
+ let avail = (if !exponential then
+ max 0.02 (min 1. (exp(1. -. log(2. +. 65. *. x))))
+ else
+ 0.02 +. 0.98 *. x
+ )
+ in
+ trace_output oc (Peer (i, avail, Printf.sprintf "%d %d" decs timezone));
+
+ let lambda = float_of_int decs /. (60. *. 24.) in
+ let mu = avail *. lambda /. (1. -. avail) in
+ let p2 = {
+ decs = decs;
+ lambda = lambda;
+ mu = mu;
+ timezone = timezone;
+ } in
+ let p = {
+ avail = avail;
+ i = i;
+ descr = "";
+ session = 0;
+ day = true;
+ state = OFF;
+ real_avail = 0;
+ real_decs = 0;
+ } in
+ p,p2
+ )
+
+let peer_round round p p2 =
+ if p.state = ON then
+ p.real_avail <- p.real_avail + 1;
+
+ if round = p2.timezone then begin
+ p.day <- not p.day;
+ p2.timezone <- p2.timezone + 12 * 60;
+ end;
+
+ let x = float_of_int (Random.int 900000) /. 1000000. in
+ if p.state = ON then begin
+ let lambda = if p.day then p2.lambda /. 2. else p2.lambda *. 2. in
+ if x < lambda then begin
+ p.state <- OFF;
+ p.real_decs <- p.real_decs + 1;
+ trace_output oc (Off p.i);
+ end
+ end
+ else
+ begin
+ let mu = if p.day then p2.mu *. 2. else p2.mu /. 2. in
+ if x < mu then begin
+ p.state <- ON;
+ trace_output oc (On p.i);
+ end
+ end
+
+let _ =
+ for round = 0 to nrounds - 1 do
+ trace_output oc (Round round);
+(*
+ let daytime = round mod day in
+ utput_string oc (Printf.sprintf "Round %d %d %02d:%02d\n" round
+ (round / day) (daytime / 60) (daytime mod 60)
+ ); *)
+ (* Printf.printf "Round %d/%d\n%!" round nrounds; *)
+ for x = 0 to npeers - 1 do
+ let p,p2 = peers.(x) in
+ peer_round round p p2
+ done
+ done
+
+let _ =
+ Array.iter (fun (p,p2) ->
+ if p.state = ON then begin
+ p.real_decs <- p.real_decs + 1;
+ p.state <- OFF;
+ end;
+ ) peers
+
+(*
+let _ =
+ Array.iteri (fun i p ->
+ Printf.printf "%d: %.3f --> %.3f (%d: %.3f)\n" i p.avail
+ (float_of_int p.real_avail /. float_of_int nrounds)
+ p.decs
+ ((float_of_int p.real_avail /. float_of_int p.real_decs) /. 60. )
+ ) peers
+ *)
+
+let _ =
+ trace_output oc End;
+ close_out oc
+
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/liartrace.ml b/sources/fabrice/pacemaker/liartrace.ml
new file mode 100644
index 0000000..e227dc0
--- /dev/null
+++ b/sources/fabrice/pacemaker/liartrace.ml
@@ -0,0 +1,308 @@
+
+open Sets
+
+open SimulTrace
+open SimulTypes
+open SimulGraphes
+
+
+
+ let day = 60 * 24
+(*
+Every peer is responsible to "observe" $degree$ other peers in the system.
+Such peers are usually peers with which it is exchanging some resources.
+
+TODO: currently, a peer has the knowledge of when another it is observing
+is online when testing the probability to send a challenge. We should change
+that, so that when a peer is online, the probability of sending a challenge
+is independant from the status of the observed peer.
+
+*)
+
+type observer = {
+ mutable observer : int;
+ mutable observed : int;
+ mutable next : int;
+ }
+
+type peer2 = {
+ mutable observers : observer IntMap.t;
+ mutable observing : observer IntMap.t;
+ mutable availabilities : int array;
+ mutable liar : float; (* liar by how much, not liar = 1. ? *)
+ mutable excluded : bool;
+ mutable is_liar : bool;
+ }
+
+let probes = ref 1
+let degree = ref 5
+let nliars = ref 5
+let anon_args = ref [ Sys.argv.(0) ]
+let ndays = ref 0
+let subdir = ref None
+
+let _ =
+ Printf.printf "Version 2.0\n%!";
+ Arg.parse [
+ "-subdir", Arg.String (fun s ->
+ subdir := Some s), "<subdir> : set subdir for data files";
+ "-dist", Arg.Set print_distribution, " : print distribution";
+ "-ndays", Arg.Int ((:=) ndays), " <n> : number of days";
+ "-degree", Arg.Int ((:=)degree), " <n> : number of observers";
+ "-nliars", Arg.Int ((:=)nliars), " <n> : number of liars(%)";
+ "-probes", Arg.Int ((:=)probes), " <n> : number of challenges";
+ ]
+ (fun t -> anon_args := t :: !anon_args) ""
+
+
+
+let subdir =
+ match !subdir with
+ None -> failwith "You must specify a subdirectory for data files"
+ | Some dir ->
+ Unix2.safe_mkdir (Filename2.of_string dir);
+ dir
+let nliars = !nliars
+let degree = !degree
+let probes = !probes
+
+let argv = Array.of_list (List.rev !anon_args)
+let trace = argv.(1)
+
+
+let _ =
+ if trace = "" then
+ failwith "You must at least specify the name of the trace file";
+ Random.self_init ()
+
+let peers, nrounds, do_round = trace_read trace
+
+let nrounds =
+ if !ndays <> 0 then
+ day * !ndays
+ else nrounds
+
+let npeers = Array.length peers
+
+
+let nrounds =
+ if Array.length argv = 3 then
+ day * int_of_string argv.(2)
+ else nrounds
+
+let peers2 = Array.init npeers (fun i ->
+ let p = {
+ observers = IntMap.empty;
+ observing = IntMap.empty;
+ availabilities = [| 0; 0 |];
+ liar = 1.0;
+ excluded = false;
+ is_liar = false;
+ } in
+
+ p)
+
+let npeersf = float_of_int npeers
+
+let _ = Printf.printf "Find observers\n%!"
+
+let rec find_observer i p =
+ let x = Random.int npeers in
+ let op2 = peers2.(x) in
+ if x = i ||
+ op2.excluded ||
+ IntMap.mem x p.observers then find_observer i p
+ else
+ let ob = {
+ observer = x;
+ observed = i;
+ next = 7200; (* 5 days *)
+ } in
+ p.observers <- IntMap.add x ob p.observers;
+ op2.observing <- IntMap.add i ob op2.observing
+
+
+let _ =
+ for i = 0 to npeers - 1 do
+
+ let p = peers2.(i) in
+ for x = 1 to degree do
+ find_observer i p
+ done
+
+ done
+
+let rec find_liar x =
+ if x = npeers then () else
+ let n = Random.int npeers in
+ let p2 = peers2.(n) in
+ if p2.liar > 1.001 then find_liar (x+1) else
+ let p = peers.(n) in
+ let avail = p.avail in
+ if avail > 0.95 then find_liar (x+1) else
+ let max_lying = 1. /. avail in
+ let lying = Random.float max_lying in
+ p2.liar <- 1.01 +. lying;
+ p2.is_liar <- true
+
+let _ = Printf.printf "Find liars\n%!"
+
+let _ = (* 5% of liars ? *)
+ let liars = Printf.sprintf "liars_%d.dat" nliars in
+ if Sys.file_exists liars then
+ let ic = open_in liars in
+ (try
+ while true do
+ let line = input_line ic in
+ match String2.split line ' ' with
+ [num; liar] ->
+ peers2.(int_of_string num).liar <- float_of_string liar;
+ peers2.(int_of_string num).is_liar <- true
+
+ | _ -> assert false
+ done
+ with End_of_file -> ());
+ close_in ic
+ else
+ for i = 1 to npeers * nliars / 100 do
+ find_liar 0
+ done;
+ let oc = open_out (Printf.sprintf "liars_%d.dat" nliars) in
+ for i = 0 to npeers - 1 do
+ if peers2.(i).is_liar then
+ Printf.fprintf oc "%d %f\n" i peers2.(i).liar
+ done;
+ close_out oc
+
+let _ = Printf.printf "Find liars...done\n%!"
+
+let liars = Array.create nrounds 0
+let measured_availabilities = Array.create nrounds 0.
+let real_availabilities = Array.create nrounds 0.
+
+let measured_availabilitiesE = Array.create nrounds 0.
+let real_availabilitiesE = Array.create nrounds 0.
+
+let _ =
+ let rec iter_observers p list =
+ match list with
+ [] -> ()
+ | o :: tail ->
+ let po = peers.(o) in
+ if po.state = ON then
+ p.availabilities.(1) <- p.availabilities.(1) + 1
+ else
+ iter_observers p tail
+ in
+
+ for round = 0 to nrounds - 1 do
+ do_round round;
+
+ let ticket = 0 = (round+59) mod 60 in
+
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if p.state = ON then begin
+ p2.availabilities.(0) <- p2.availabilities.(0) + 1;
+ if ticket then
+ p2.availabilities.(1) <- p2.availabilities.(1) + 60;
+ if not p2.excluded then
+ let to_replace = ref [] in
+ IntMap.iter (fun o ob ->
+ let p2 = peers2.(o) in
+ if p2.excluded then
+ to_replace := o :: !to_replace
+ ) p2.observers;
+
+ List.iter (fun o ->
+ p2.observers <- IntMap.remove o p2.observers;
+ let op2 = peers2.(o) in
+ op2.observing <- IntMap.remove i op2.observing;
+ find_observer i p2
+ ) !to_replace;
+
+ IntMap.iter (fun _ ob ->
+ let p = peers.(ob.observed) in
+ let p2 = peers2.(ob.observed) in
+ if (not p2.excluded) && p.state = ON && ob.next <= round &&
+ Random.int 180 = 0
+ then begin
+ ob.next <- round + 24 * 60;
+
+ for x = 1 to probes do
+ let y = Random.float p2.liar in
+ if y > 1.0 then begin
+ Printf.printf "Probe failed for %d\n%!" i;
+ p2.excluded <- true;
+ assert (p2.is_liar )
+ end
+ done
+
+ end
+ ) p2.observing
+
+ end
+ done;
+
+ if round > 20 then
+ let measured_availE = ref 0. in
+ let real_availE = ref 0. in
+ let measured_avail = ref 0. in
+ let real_avail = ref 0. in
+ for i = 0 to npeers - 1 do
+(* let p = peers.(i) in *)
+ let p2 = peers2.(i) in
+ assert (p2.liar >= 0.);
+ assert (p2.availabilities.(0) >= 0);
+ assert (p2.availabilities.(1) >= 0);
+
+ measured_availE := !measured_availE +.
+ ( p2.liar *.
+ (float_of_int p2.availabilities.(1)) );
+ if not p2.is_liar then
+ real_availE := !real_availE +.
+ float_of_int p2.availabilities.(0);
+
+ if (not p2.excluded) then begin
+ if p2.liar > 1.001 then
+ liars.(round) <- liars.(round) + 1;
+
+ measured_avail := !measured_avail +.
+ ( p2.liar *.
+ (float_of_int p2.availabilities.(1)) );
+ real_avail := !real_avail +.
+ float_of_int p2.availabilities.(0)
+ end
+ done;
+ let roundf = float_of_int (1+round) *. npeersf in
+ let measured_avail = !measured_avail /. roundf in
+ let real_avail = !real_avail /. roundf in
+ measured_availabilities.(round) <- measured_avail;
+ real_availabilities.(round) <- real_avail;
+
+ let measured_availE = !measured_availE /. roundf in
+ let real_availE = !real_availE /. roundf in
+ measured_availabilitiesE.(round) <- measured_availE;
+ real_availabilitiesE.(round) <- real_availE;
+ done;
+
+ value_per_time string_of_float
+ (Printf.sprintf "%s/liar_measured_%dx%d" subdir degree probes)
+ measured_availabilities "avail";
+
+ value_per_time string_of_float
+ (Printf.sprintf "%s/liar_real_%dx%d" subdir degree probes)
+ real_availabilities "avail";
+
+ value_per_time string_of_float
+ (Printf.sprintf "%s/liar_measuredE_%dx%d" subdir degree probes)
+ measured_availabilitiesE "avail";
+
+ value_per_time string_of_float
+ (Printf.sprintf "%s/liar_real" subdir)
+ real_availabilitiesE "avail";
+
+ value_per_time string_of_int
+ (Printf.sprintf "%s/liar_number_%dx%d" subdir degree probes) liars "avail";
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/notes.txt b/sources/fabrice/pacemaker/notes.txt
new file mode 100644
index 0000000..fb8bdc8
--- /dev/null
+++ b/sources/fabrice/pacemaker/notes.txt
@@ -0,0 +1,15 @@
+ peerolyse:~/devel/onzego% time ./research/p2p_avail/gentrace trace_10000x1000_1 10000 1000
+./research/p2p_avail/gentrace trace_10000x1000_1 10000 1000 1183.25s user 2.83s system 99% cpu 19:46.89 total
+
+
+
+ peerolyse:~/articles/p2p_avail_metro/simulation% time gentrace trace_500x365_1 500 365
+gentrace trace_500x365_1 500 365 22.19s user 0.05s system 99% cpu 22.267 total
+
+
+In the current implementation of gentrace, all the timezones are in the
+first 12 hours.
+
+
+To obtain big graphs, don't use -Tps, but Tjpg with display
+ dot -Tjpg graph_000000.dot -o graph.jpg
diff --git a/sources/fabrice/pacemaker/overnetTrace.ml b/sources/fabrice/pacemaker/overnetTrace.ml
new file mode 100644
index 0000000..c84bf20
--- /dev/null
+++ b/sources/fabrice/pacemaker/overnetTrace.ml
@@ -0,0 +1,130 @@
+open Sets
+
+open SimulTypes
+open SimulTrace
+
+let input_line ic = String.lowercase (input_line ic)
+
+let ts = ref 1042666697
+
+let npeers = 3000
+
+let peers = Array.create npeers false
+let avail = Array.create npeers 0
+
+let counter = ref 0
+let map = ref StringMap.empty
+
+let add_hosts = ref true
+
+let blacklist = ref StringSet.empty
+
+let find_host name =
+ try
+ StringMap.find name !map
+ with Not_found ->
+ if !add_hosts && not (StringSet.mem name !blacklist) then
+ let id = !counter in
+ Printf.printf "New host %d\n%!" !counter;
+ map := StringMap.add name id !map;
+ incr counter;
+ id
+ else
+ -1
+
+let f round oc i =
+ Printf.printf "CURRENT: %d\n%!" i;
+ let ic = open_in (Printf.sprintf "pd_%d" i) in
+
+ let line = input_line ic in
+ let new_ts =
+ match String2.split_simplify line ' ' with
+ "#" :: "timestamp" :: "of" :: "probe:" :: new_ts :: [] ->
+ int_of_string new_ts
+ | _ -> assert false
+ in
+
+ let changes = Array.create 20 [] in
+ begin try
+ while true do
+ let line = input_line ic in
+ match String2.split_simplify line '\t' with
+ [name; ip; ping] ->
+ let id = find_host name in
+ if id >= 0 then
+ let status = ping = "1" in
+ if peers.(id) <> status then
+ let n = Random.int 20 in
+ changes.(n) <- id :: changes.(n)
+ | [] -> ()
+ | _ ->
+ Printf.printf "Unexpceted line [%s]\n"
+ (String.escaped line);
+ assert false
+ done
+ with
+ | End_of_file ->
+ close_in ic
+ end;
+ ts := new_ts;
+
+ for j = 0 to 19 do
+ trace_output oc (Round !round);
+
+ List.iter (fun p ->
+ let status = peers.(p) in
+ peers.(p) <- not status;
+ trace_output oc (if status then
+ Off p
+ else
+ On p)
+ ) changes.(j);
+
+ for k = 0 to npeers - 1 do
+ if peers.(k) then
+ avail.(k) <- avail.(k) + 1
+ done;
+
+ incr round;
+ done
+
+
+let nremoved = ref 0
+
+let _ =
+
+ if Sys.file_exists "blacklist" then
+ begin
+ let ic = open_in "blacklist" in
+ try
+ while true do
+ let name = input_line ic in
+ blacklist := StringSet.add name !blacklist;
+ incr nremoved
+ done
+ with End_of_file -> close_in ic
+ end;
+
+ let oc = open_out "overnet" in
+ trace_output oc (Peers (npeers- !nremoved));
+ trace_output oc (Days (7,24*60));
+ for i = 1 to npeers - !nremoved do
+ trace_output oc (Peer (i-1, 0., "overnet"));
+ done;
+ let round = ref 0 in
+ f round oc 0;
+(* add_hosts := false; *)
+
+ for i = 1 to 503 do
+ f round oc i
+ done;
+ Printf.printf "NUMBER OF HOSTS: %d\n%!" !counter;
+ trace_output oc End;
+
+ close_out oc;
+
+ let oc = open_out "blacklist" in
+ StringMap.iter (fun name id ->
+ if avail.(id) < 1 then
+ Printf.fprintf oc "%s\n" name) !map;
+ close_out oc;
diff --git a/sources/fabrice/pacemaker/pMArgs.ml b/sources/fabrice/pacemaker/pMArgs.ml
new file mode 100644
index 0000000..6b0162d
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMArgs.ml
@@ -0,0 +1,87 @@
+open SafeCaml
+open Pervasives
+
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+
+open PMTypes
+open PMNetwork
+open PMOptions
+
+(*
+let uid = ref (Sha1.random ())
+let port = ref (1024 + Random.int 64000)
+let run_as_server = ref false
+let servers = ref []
+let ndegree = ref 5
+ *)
+
+
+let binary_hash = Sha1.string (File.to_string binary_filename)
+
+let binary_mtime = Int64.of_float (Unix.stat binary_filename).Unix.st_mtime
+
+let new_binary = ref false
+
+let arg_help = "pacemaker: run a pacemaker daemon"
+let arg_list = [
+ "-new_binary", Arg.Set new_binary, " : export new binary";
+ "-port", Arg.Int ((=:=) my_port), " <port> : bind on port";
+ "-uid", Arg.String (fun s ->
+ uid =:= Sha1.of_string s), " <uid> : use as uid";
+ "-server", Arg.Unit (fun _ ->
+ run_as_server =:= true), " : run as a server";
+ "-master", Arg.Unit (fun _ ->
+ run_as_master =:= true), " : run as a server";
+ "-s", Arg.String (fun s ->
+ try
+ match String.split_simplify s ':' with
+ [sha1; ip; port ] ->
+ let x = (Sha1.of_string sha1,
+ Ip.of_string ip, int_of_string port) in
+ if not (List.mem x !!servers) then
+ servers =:= x :: !!servers
+ | _ -> assert false
+ with _ ->
+ failwith (Printf.sprintf "[-s %s] is not correctly formatted" s)
+ ), " <uid:ip:port> : info on server";
+ ]
+
+let _ =
+ Arg.parse arg_list (fun _ -> Arg.usage arg_list arg_help) arg_help;
+ if Array.length Sys.argv <> 1 then must_save_options ();
+
+
+
+ PMOptions.save_options ()
+
+(*
+
+let nservers = ref 0
+let servers_map = ref Sha1Map.empty
+
+let servers_list = List.map (fun (s, sha1, ip, port) ->
+ let p = PaceMakerNetwork.new_peer sha1 (Some (ip, port)) in
+ incr nservers;
+ p.peer_type <- PEER_SERVER;
+ servers_map := Sha1Map.add sha1 p !servers_map;
+ s, p
+ ) !servers
+let nservers = !nservers
+let servers_map = !servers_map
+let servers_tab = Array.of_list servers_list
+
+let ndegree = !ndegree
+let parents = Array.create ndegree (None : peer_info option)
+let children = Array.create ndegree (None : peer_info option)
+let candidates = ref ([] : peer_info list)
+
+let dir = Filename.of_string "/home/irisa_pacemaker/planetlab/pacemaker"
+
+let heartbeats = (Hashtbl.create 2047 : (HeartBeatMsg.msg, bool) Hashtbl.t)
+
+ *)
diff --git a/sources/fabrice/pacemaker/pMConst.ml b/sources/fabrice/pacemaker/pMConst.ml
new file mode 100644
index 0000000..c898bbd
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMConst.ml
@@ -0,0 +1,210 @@
+open SafeCaml
+open Pervasives
+
+open Checksum
+open Sets
+open Options
+
+
+let max_distance = 10
+
+let config_dir = Filename.of_string "/home/irisa_pacemaker/pacemaker"
+
+
+let allpeers = [|
+ Ip.of_string "12.108.127.137", 7000, Sha1.of_string "NSGWQIWXMWB33ZK7MK5X67ADJ4Q62FCT";
+ Ip.of_string "204.85.191.10", 7000, Sha1.of_string "E2IS7NA4KMJD4VRPAWL6XWHQ4Y5OMZX7";
+ Ip.of_string "128.135.11.152", 7000, Sha1.of_string "2FPG3B6KWSKWGKL5DAOR6GJ73PT4X3NS";
+ Ip.of_string "169.229.50.5", 7000, Sha1.of_string "B2JR7FL6FOOXPNNYCRCQ7DJKPDXFTHH6";
+ Ip.of_string "195.37.16.97", 7000, Sha1.of_string "FHGIY3HVTO3YTTJ7JEMCWB4KZ7P564LE";
+ Ip.of_string "219.243.201.17", 7000, Sha1.of_string "2PT37PP6LTKKHQTAEMENJECMSDGCLFJA";
+ Ip.of_string "195.83.212.155", 7001, Sha1.of_string "KLQCLYRUP3NMDOH3LNAEPX3L4QBGA6HQ";
+ Ip.of_string "195.83.212.159", 7001, Sha1.of_string "JZGBBR2VOSAZFVGQGBSAQ4E6MN6QMNWQ";
+ Ip.of_string "195.83.212.149", 7001, Sha1.of_string "V7T52VJ7WIQWP4T5UXH2E7XLUJXDJ6C7";
+ Ip.of_string "138.232.66.194", 7000, Sha1.of_string "XCW66RLNEJLR5MX7URUV2LIXJEKGVO3N";
+ Ip.of_string "143.205.172.11", 7000, Sha1.of_string "SH6RMI4K76JRYORHZTAVMPHZXBR7H2AK";
+ Ip.of_string "131.130.32.152", 7000, Sha1.of_string "X7VL4KLFQIL3WEVSGTOG45E2PS4R3C4U";
+ Ip.of_string "220.245.140.196", 0, Sha1.of_string "QVB26DD524S5TZGJYI2RVW6BPQWBKHZZ";
+ Ip.of_string "193.191.148.227", 7000, Sha1.of_string "S5ESW43NQRXEJGYPXUP5NVMNOTD46AGQ";
+ Ip.of_string "200.133.215.141", 7000, Sha1.of_string "F22Q7LQUHDFEJRMOBC4PVD2XAEZPTAZL";
+ Ip.of_string "200.19.159.34", 7000, Sha1.of_string "GLWIVJOV6CKMJV7WE6ZNXVXI3XNLB3EN";
+ Ip.of_string "200.132.0.70", 7000, Sha1.of_string "WXQNGCNAVOQ7KYFYB7NLA3JXPUVRPGBV";
+ Ip.of_string "143.107.111.194", 7000, Sha1.of_string "2SMNW43FH3XJUAZZQTOALFZCIQ4IEGDY";
+ Ip.of_string "206.12.16.154", 7000, Sha1.of_string "SYMW3EMUPXT6IEEGPE2LEFUVQ3GYGMAJ";
+ Ip.of_string "198.163.152.229", 7000, Sha1.of_string "EXKG2MWZNKRVSNZEG6V4BW3JA3SD5HD7";
+ Ip.of_string "205.211.183.2", 7000, Sha1.of_string "MVDJCNAKPQA6PUAMLCSSVTVG4FUOAUT6";
+ Ip.of_string "128.233.252.11", 7000, Sha1.of_string "FXSJW44QXO24PU7V5HE2BLHVTZC62XV3";
+ Ip.of_string "142.150.238.12", 7000, Sha1.of_string "ENMWFEDPAXV5LF24HBFLJJM2FXZYES6I";
+ Ip.of_string "142.150.3.77", 7000, Sha1.of_string "GHWQKGC7E3WWOGQCR6PRZ7DEST2SELQP";
+ Ip.of_string "142.104.21.241", 7000, Sha1.of_string "3KYC6PICAZ3EWAMV2RKS47XKRDUEP6DJ";
+ Ip.of_string "192.33.210.16", 7000, Sha1.of_string "FMMFTYOPXF6PGLHMSM7L7Y63E4NMKTYZ";
+ Ip.of_string "192.33.90.66", 7000, Sha1.of_string "7AYGTH42HNIFS2K44EXJVQISSJRSDV3B";
+ Ip.of_string "130.92.70.251", 7000, Sha1.of_string "XBSITJEGFPOIFAYKGWBP2VH2YH6WDB56";
+ Ip.of_string "192.42.43.22", 7000, Sha1.of_string "7UCWZIILOIWRRXB7C7L52IDRBUOENYS3";
+ Ip.of_string "192.41.135.218", 7000, Sha1.of_string "H43G5MZW2FA3Y3A6KY7T6AQD33WMCW5J";
+ Ip.of_string "219.243.206.36", 7000, Sha1.of_string "KXWDRWEZS4H2ZJGAHH5GFJ7VDVGRYQ4V";
+ Ip.of_string "216.98.102.29", 7000, Sha1.of_string "RCZHNJUBYJRVNYJUTD7A3CI5H6RTCMVK";
+ Ip.of_string "192.6.10.50", 7000, Sha1.of_string "AJDEUX57HUFG3BQQ4BR43MBL2KJPQUJ4";
+ Ip.of_string "198.175.112.104", 7000, Sha1.of_string "PQQLV434OTWPM65LDLMMAA2T2KTIDUGX";
+ Ip.of_string "63.64.153.82", 7000, Sha1.of_string "3T7GFCLFWYZOIAZ2F2NCT5KHHL3LEUA4";
+ Ip.of_string "138.15.10.55", 7000, Sha1.of_string "TA6P3PYG3JYL2NDVRZQZV2HVL7UE7U4P";
+ Ip.of_string "194.42.17.123", 7000, Sha1.of_string "YJAIZCFOM7M2UDTY2ZEZJ5VSL7RLLE6X";
+ Ip.of_string "195.113.161.82", 7000, Sha1.of_string "G2EJIM7M34VKVWNKM3LA24EH4A3YR62L";
+ Ip.of_string "147.229.10.250", 7000, Sha1.of_string "3FMD5HNWLMQSKVSX5MIK343PUUXTJ4ZD";
+ Ip.of_string "131.246.191.42", 7000, Sha1.of_string "HQCCDIDJHNUM5ODQQ5RHEJMDIN5EBVZE";
+ Ip.of_string "193.174.67.186", 7000, Sha1.of_string "JMMS2LJBXDYS7SRPB7G4U4CUI4HU7AFG";
+ Ip.of_string "141.22.213.35", 7000, Sha1.of_string "LVLF7F2JXSSWNXKRDV4T4JIBRLTKCYBA";
+ Ip.of_string "141.20.103.210", 7000, Sha1.of_string "Q7CAAV6A5VAIEXRMHHTTP75GNSS5CSN7";
+ Ip.of_string "212.201.44.81", 7000, Sha1.of_string "2SQGMZR2WOXH7FHXT53B5HCYPEXVKNER";
+ Ip.of_string "139.19.142.1", 7000, Sha1.of_string "RI6PV5M6FGGP27O3WC7OAKC6A2UZYAL6";
+ Ip.of_string "137.226.138.154", 7000, Sha1.of_string "GPA454N4YE4F7UYJDYFB6ST22CGJ3O3Q";
+ Ip.of_string "130.83.166.198", 7000, Sha1.of_string "3G5ZMOSM2QC6XHMPILAWPU2Y2V6SDZVK";
+ Ip.of_string "141.76.45.17", 7000, Sha1.of_string "SH5B33PC7AYVX6X2235DGV7UXROWRT5K";
+ Ip.of_string "141.24.249.129", 7000, Sha1.of_string "55SQEF3S5S6UH7D2FUSB24ORVTELVN32";
+ Ip.of_string "141.24.33.161", 7000, Sha1.of_string "JZDFMXEZUANTTH26BUXIHQWI5SNBKEXD";
+ Ip.of_string "138.246.99.249", 7000, Sha1.of_string "TEXD2OP47VVJFGWCWXS5G5GYIGU5B7QD";
+ Ip.of_string "141.13.16.201", 7000, Sha1.of_string "7HCOSHF5Z7PB6E55NYAUW2MY4BBNO6HE";
+ Ip.of_string "131.188.44.101", 7000, Sha1.of_string "X3BG3LCC5U52BH77NP6WAEYXMT4WEEN3";
+ Ip.of_string "132.252.152.193", 7000, Sha1.of_string "6OTJGMWB3ENELUVFWI47WOCXBDRGDZKJ";
+ Ip.of_string "130.75.87.83", 7000, Sha1.of_string "NOTLBXT6CWJCPMWQO3MNE63HG6SJWKPJ";
+ Ip.of_string "193.196.39.9", 7000, Sha1.of_string "ZJLPBI6XUT3MEYK5QRKGRL6V6AJHPM2W";
+ Ip.of_string "131.246.19.201", 7000, Sha1.of_string "373A35MFSKLYV2TBQRVKZUULWLL56ZXP";
+ Ip.of_string "134.34.246.5", 7000, Sha1.of_string "PG26ZIAJFOQIUVTDXRI3ANHWR7MLBDD3";
+ Ip.of_string "129.69.210.96", 7000, Sha1.of_string "H7VMU27XPXMHG3QNV3KXJOJTTJSUFOO2";
+ Ip.of_string "134.2.172.253", 7000, Sha1.of_string "HW2PGBT6GFSGFW4IPI45E33BL7KMHBBZ";
+ Ip.of_string "132.187.230.1", 7000, Sha1.of_string "L4CY2A7BQ23IKMU5AQTGYSIDPRZURBPQ";
+ Ip.of_string "130.73.142.87", 7000, Sha1.of_string "6IFADLQG3NKMSTV5VWF73BS45ZFMBWUF";
+ Ip.of_string "149.169.227.129", 7000, Sha1.of_string "M5Z2ZDQIKQSTRDA2KISLY2EJOYU4WFEF";
+ Ip.of_string "198.7.242.43", 7000, Sha1.of_string "RPA3GHHEJFU3G5NSV5P24KUW5H4E62BZ";
+ Ip.of_string "204.8.155.226", 7000, Sha1.of_string "UVBSZKIAYAPVTRYEQWDEYCRV5BZ3J4UN";
+ Ip.of_string "128.187.223.211", 7000, Sha1.of_string "GJWQSHJJI7V2TBYJPRP6LMPLON6KYR5D";
+ Ip.of_string "131.215.45.71", 7000, Sha1.of_string "ZJA556UIRAAUFG3JOPO55VS6EBX6CKPX";
+ Ip.of_string "128.2.223.63", 7000, Sha1.of_string "NPPTGWL4M2WDRQRK65E4VM4M62IJHWIY";
+ Ip.of_string "128.84.154.49", 7000, Sha1.of_string "ACBEXODFZXAZPM6VWK6K76BSMLOZEZF6";
+ Ip.of_string "152.3.138.1", 7000, Sha1.of_string "H5V2WVFLCU2QQZKQEBKGTJQHMKRWRZ6D";
+ Ip.of_string "170.140.119.69", 7000, Sha1.of_string "EED3W3446UQ7HPVY2VXJP5E3TF7NVQHM";
+ Ip.of_string "141.161.20.32", 7000, Sha1.of_string "SDW4B4LWVIW2ZOROBEYM7WJGPO2W2TND";
+ Ip.of_string "129.174.79.249", 7000, Sha1.of_string "3DAD4KLLQNILVMLIXNRAJDQZOEYWE5T6";
+ Ip.of_string "140.247.60.123", 7000, Sha1.of_string "Z7GV5MRO27F4DHMOCIJXYTFHTD2NT55W";
+ Ip.of_string "129.186.205.71", 7000, Sha1.of_string "YCHGLP3RSXUQWUBZUHP2FMTLIC5TCO4T";
+ Ip.of_string "128.220.247.28", 7000, Sha1.of_string "2QJLLKYT2BJLS5FSTWDWHYW6B7OQ4YTD";
+ Ip.of_string "129.130.252.141", 7000, Sha1.of_string "TGEQRTA6W2H3BH7OZSWK53HVMSKIMA6Q";
+ Ip.of_string "129.237.161.193", 7000, Sha1.of_string "HDN42PP47TCOI2UQF7OQ4JOI3XLYYRFD";
+ Ip.of_string "128.31.1.11", 7000, Sha1.of_string "WTLLT7EKFQXNY2GN37YQN7R4Z3ZKQN4K";
+ Ip.of_string "35.9.27.26", 7000, Sha1.of_string "C3MFMD6TUZV7ELPIQBNP5CLJ6HPU22ZZ";
+ Ip.of_string "141.219.252.132", 7000, Sha1.of_string "XYFKQ7S5OAUTYKUFYCETCKOSRAAGRWHJ";
+ Ip.of_string "152.14.92.58", 7000, Sha1.of_string "GYEQSZH5GDPTVZ6ZUGJEIYD7X3N4UBL6";
+ Ip.of_string "129.74.74.15", 7000, Sha1.of_string "PQB5ILXWMFPZZZ522NDPLZXRXGFGGNZY";
+ Ip.of_string "129.10.120.193", 7000, Sha1.of_string "OOWUJIXQLSQ72A2F4BKBBI2BO2O37RON";
+ Ip.of_string "216.165.109.81", 7000, Sha1.of_string "IN6Z2C7CIR4QGNVY5FECWBDQEDIIRC76";
+ Ip.of_string "164.107.127.12", 7000, Sha1.of_string "D74K5YRAH4M4ZTYYWB5ON66S6O2B2YQY";
+ Ip.of_string "128.193.33.7", 7000, Sha1.of_string "HLN7LWFFTHOKJTEUAD3KXTMKZ7UV4AWV";
+ Ip.of_string "130.49.221.40", 7000, Sha1.of_string "3LTFOJRCJ774DBNU3T4ZFEASYKRRMBKP";
+ Ip.of_string "128.112.139.80", 7000, Sha1.of_string "4XVBELRD3GVZYNODZXKXR74R6MK4VYNU";
+ Ip.of_string "128.10.19.52", 7000, Sha1.of_string "VRF4WDGHK5B3U6Z4B2PQCXOMWF6DJBR6";
+ Ip.of_string "128.42.6.143", 7000, Sha1.of_string "O4H4QJN644R7G6IMVRLHFEYGW4RRLUZE";
+ Ip.of_string "128.151.65.101", 7000, Sha1.of_string "3UIYEKCORRCJWDOT432BYYEK5UGADZD6";
+ Ip.of_string "128.113.226.235", 7000, Sha1.of_string "5S4BQ5QYJ2DQQRD54ET6ODBY5SFEUIFX";
+ Ip.of_string "64.161.10.2", 7000, Sha1.of_string "BD3E44YRNGVMG7TQOHC6BX3LNGPLJHIW";
+ Ip.of_string "171.66.3.181", 7000, Sha1.of_string "N22GUUPB3PCL5VSTD3I4RWVSX6BFRMJP";
+ Ip.of_string "129.137.253.253", 7000, Sha1.of_string "II54XEMUDWFQAEFUVKAKQANXUSQJT4RO";
+ Ip.of_string "169.237.79.210", 7000, Sha1.of_string "IKEOMWHOEBJADYJFK2CCBTJWUK63JYV7";
+ Ip.of_string "132.170.3.32", 7000, Sha1.of_string "34YIASQ5UJE642T77RLAIH5XLV4O3MI6";
+ Ip.of_string "128.195.54.161", 7000, Sha1.of_string "4MJQRXVMUHF5FUSG7WPT7H2PWLKIF2KF";
+ Ip.of_string "131.179.50.70", 7000, Sha1.of_string "XMESSYMZLIPHT63HQJ5GMGL2GJBZXAAB";
+ Ip.of_string "138.23.204.133", 7000, Sha1.of_string "B3FSK4YYB5KBFWXJA2Z7STQLCXOFLZ6M";
+ Ip.of_string "128.114.63.14", 7000, Sha1.of_string "632WY6AWKZCLB6QCUMTO4NB2GZEBBU6Z";
+ Ip.of_string "132.239.17.224", 7000, Sha1.of_string "RW3GG4MYZ5OIHVRFCZEOMO3RXBA67RQS";
+ Ip.of_string "128.4.36.11", 7000, Sha1.of_string "S4HXULGPHIYEEX4VJKISRYOVVRIWR765";
+ Ip.of_string "128.227.56.81", 7000, Sha1.of_string "MSLYOK2N3QVEVASIUM3QTJLY64O2AWW7";
+ Ip.of_string "208.117.131.115", 7000, Sha1.of_string "FTASW6RQZ74ZMQCDRJDAZ7JXAANBGSPZ";
+ Ip.of_string "72.36.112.71", 7000, Sha1.of_string "IQH25AIMAPHZJ4GDLOCNRSCCZ4SPNTJP";
+ Ip.of_string "128.8.126.112", 7000, Sha1.of_string "PKZDYBVY5GS4BBVELRZ3CLPBUFYNSRSY";
+ Ip.of_string "141.213.4.201", 7000, Sha1.of_string "ZQPXFWOTPNGX2WIU7JSHUNZJHW3BMKIV";
+ Ip.of_string "204.56.0.137", 7000, Sha1.of_string "4I7DJCLADSVZBP7WOO2WAOJLZMCBARJN";
+ Ip.of_string "152.15.98.226", 7000, Sha1.of_string "UN4EZM363KBWBUW4OUX4IUG2G76CRQXI";
+ Ip.of_string "129.93.229.138", 7000, Sha1.of_string "LQSWZBJWNHTNBP2I44JKI7LRN5WEBAT6";
+ Ip.of_string "129.24.211.25", 7000, Sha1.of_string "VHGXP3KA4B6VLOT4APLBHCHYMSOOHE37";
+ Ip.of_string "128.223.8.111", 7000, Sha1.of_string "SVGRW4TSN4PL7S3WFFUV6FZQBI4JWZPW";
+ Ip.of_string "158.130.6.254", 7000, Sha1.of_string "OGRVZV3BIYFPP4ARWBG25GJEVCTDPSZK";
+ Ip.of_string "136.145.115.194", 7000, Sha1.of_string "U7KP2YKZP2DXNOGPX55KPJCDW3CMRS7V";
+ Ip.of_string "131.247.2.241", 7000, Sha1.of_string "CFNVVEEPKWBW2D7XOAKWENOF33NPAQY5";
+ Ip.of_string "155.98.35.2", 7000, Sha1.of_string "4MEBVWTXXAXS2W7WN4CVYKOL6LGNTWSC";
+ Ip.of_string "129.110.125.51", 7000, Sha1.of_string "Z7DVJG3SA6FYR3L34DWS62DBH2ILSTZE";
+ Ip.of_string "128.83.122.179", 7000, Sha1.of_string "QXN5OMVX4ZQR2PEPB642TBV5EB4DZQBH";
+ Ip.of_string "160.36.57.172", 7000, Sha1.of_string "JCPMWMYXZY7XTUOKMCRLL7ZUQQLPTJAL";
+ Ip.of_string "129.59.88.179", 7000, Sha1.of_string "KZ4P6T2ZSI3EQ4HHQSPSFKGIJJCPZE2M";
+ Ip.of_string "198.82.160.221", 7001, Sha1.of_string "3GFLHJSKHJO4BUGTKRC7ZGNMV7XHOJTI";
+ Ip.of_string "128.208.4.197", 7000, Sha1.of_string "J6Z2VJG4DJNQRNXXOFBOBQTRTGWWGXIL";
+ Ip.of_string "137.165.1.111", 7000, Sha1.of_string "KPQ66PS3SHLW6E2SHEYWLNFOOCPUEAHN";
+ Ip.of_string "198.133.224.145", 7000, Sha1.of_string "DIOFMYAYNDTUDD6SURRCDFORSTZO2AXN";
+ Ip.of_string "198.133.224.147", 7000, Sha1.of_string "JC6R2DAJQ66AJJVGB7SHRNT4DBHNGHJF";
+ Ip.of_string "134.121.64.4", 7000, Sha1.of_string "5ANZP6OSSTGCGQK7U6G5WIOFRHWUA6TZ";
+ Ip.of_string "128.252.19.20", 7000, Sha1.of_string "BMXBX7MGLXZCWM25LTQ52HSL4HOU5U3G";
+ Ip.of_string "130.206.158.138", 7000, Sha1.of_string "QRMHNZVPLLQT6DCIPG7LDJCDRIDGY5VI";
+ Ip.of_string "193.147.162.166", 7000, Sha1.of_string "F6CTFI32BMQHTCTK2TJ5AEMDOKQUDLVW";
+ Ip.of_string "193.167.187.187", 7000, Sha1.of_string "7ZECKF66WRHE524L66UYGUFXDYGKFKSC";
+ Ip.of_string "193.167.182.130", 7000, Sha1.of_string "QQOIVZQV4DKHS42Z53JEC2EF6HOVK7TZ";
+ Ip.of_string "193.55.112.41", 7000, Sha1.of_string "HNAANZ6AW3QQBJHVQEAUA7CEJ5GIQGRV";
+ Ip.of_string "131.254.208.10", 7000, Sha1.of_string "GIRZBSCV5V5EPVYLFRHULPOCQGZR6UNJ";
+ Ip.of_string "139.91.90.238", 7000, Sha1.of_string "ABZIAMQHWF2MSHYCRDBMDPDV2OUZ5O3U";
+ Ip.of_string "147.102.3.101", 7000, Sha1.of_string "BR67N7IK62JKA7P35RH6Q4OLT2HPU3ET";
+ Ip.of_string "147.102.224.228", 7000, Sha1.of_string "XD2VZ7UNZ64YXMMOYD6DODBXFXHZ7YCW";
+ Ip.of_string "195.130.121.204", 7000, Sha1.of_string "VWLL47QYR4S5DRG7XRMRAXYQDSEWFHBG";
+ Ip.of_string "150.140.140.91", 7000, Sha1.of_string "2TMFGHYW4Y7OGABBOPWPCKUVL5UL5MXW";
+ Ip.of_string "137.189.97.17", 7000, Sha1.of_string "EOQ35KWFO6WQOCKNZYZSNRZLDCOJ5ASI";
+ Ip.of_string "152.66.244.48", 7000, Sha1.of_string "QJHY6EAXZ7KH6SNZG2VKJQPXXP4NLUMT";
+ Ip.of_string "193.1.170.135", 7000, Sha1.of_string "AJYX3Q5R77E2AJLRX7YZ73H3FLVDA77Y";
+ Ip.of_string "132.68.237.34", 7000, Sha1.of_string "DBWHCFHNYIHT2DPRTKRQ5ELD2RZ7R2GP";
+ Ip.of_string "202.141.62.34", 7000, Sha1.of_string "ZI5BKY5BNU7MWMF3OJN6POGGAOFM7KML";
+ Ip.of_string "131.175.17.9", 7000, Sha1.of_string "JE5SXWKDDAHXC3Q4K5GLOLDTJD7MWJ5W";
+ Ip.of_string "130.192.86.29", 7000, Sha1.of_string "GLLAHAMZKQRVHG42PIHUMYHG6OGQ4XMY";
+ Ip.of_string "130.136.254.21", 7000, Sha1.of_string "GVML5IBATPOCGVTZZ5MX6C24WBGPGSMP";
+ Ip.of_string "151.100.59.10", 7000, Sha1.of_string "CIAURVKZKUVP66IWIUK4MMRSU26N2NX5";
+ Ip.of_string "130.192.157.131", 7000, Sha1.of_string "XHM7RZHPB7N63WWOMAJ5X6Q7XQFH7O73";
+ Ip.of_string "150.65.32.66", 7000, Sha1.of_string "E5AXATEOYQULYFIZ25CZOLIF3BGESHQT";
+ Ip.of_string "160.193.163.101", 7000, Sha1.of_string "C6AGGDYWUN6M5OJRO6JSZNDLX2FOFHXX";
+ Ip.of_string "133.1.74.162", 7000, Sha1.of_string "OLU4PRPJ54SJ2U36NTSWUUHL3OXRMIOT";
+ Ip.of_string "133.15.59.1", 7000, Sha1.of_string "FRRYCTY5G4BG53H42H5YQE6WPYJAMZGE";
+ Ip.of_string "133.11.240.56", 7000, Sha1.of_string "2IU5UF2G62H35SRBTO3RWQ53HPAXE24X";
+ Ip.of_string "163.221.11.71", 7000, Sha1.of_string "YEC37T3QLFT6K2UAIBZYD2DZVYBCWZ2C";
+ Ip.of_string "210.125.84.15", 7000, Sha1.of_string "JDVYM5XJT3ELOP6VFV6YNJ3ZSZUTSTXB";
+ Ip.of_string "210.123.39.102", 7000, Sha1.of_string "BO4N3OHLO6TVUEUN4QQMZY5MZO7PIVP4";
+ Ip.of_string "206.207.248.34", 7000, Sha1.of_string "ZZ5U64PXP7HXZBMH5J5A5V72JCVYF3T6";
+ Ip.of_string "87.84.153.114", 7000, Sha1.of_string "HX6XVFORH75GC4JNHIKY5KHIRUW2O4FV";
+ Ip.of_string "192.42.83.251", 7000, Sha1.of_string "YQ5HTJKPWKXAZZW62U447HN4QFACXF76";
+ Ip.of_string "12.46.129.14", 7000, Sha1.of_string "S7ISKO2G6NEKXDH5OETVX6QBMSAIS2HC";
+ Ip.of_string "116.89.165.133", 7000, Sha1.of_string "FIXBGILJSSCRTIFXYAJNTQY3KZZ5FIP2";
+ Ip.of_string "200.0.206.13", 7000, Sha1.of_string "CP3EVPHI2BBZGDGDFCXQM6QWDYE3BDGZ";
+ Ip.of_string "129.242.19.196", 7000, Sha1.of_string "EOQORY4MPENPOBE34WYCUQ3QVEOVRP5N";
+ Ip.of_string "213.19.160.195", 7000, Sha1.of_string "7QCNYSA4W7P3TTAJIQDA4XKARCMOOT6C";
+ Ip.of_string "198.128.56.11", 7000, Sha1.of_string "DYSDU466ZB3SX33HFKF4Z6MIVFSNYYCS";
+ Ip.of_string "140.112.107.82", 7000, Sha1.of_string "FINBXBKEWVP53HFZVENQ6PNVKO44WXMN";
+ Ip.of_string "206.117.37.4", 7000, Sha1.of_string "HENBVYH3TG7DBIDAA762CTI4NXNF7QTJ";
+ Ip.of_string "193.1.201.26", 7000, Sha1.of_string "33TYC2F2OMPZST6KZJ33A2ICWCQ4WH7V";
+ Ip.of_string "150.254.212.147", 7000, Sha1.of_string "J5JABLCZUP466I36GW4PXL4MMOW5YCV2";
+ Ip.of_string "156.17.10.51", 7000, Sha1.of_string "ILEA722SVWC4E5J3EY4FVJIANKUGW2PQ";
+ Ip.of_string "193.136.191.25", 7000, Sha1.of_string "CLTZUSZVPMOTBV3VYKNO2LDRFAELTKC4";
+ Ip.of_string "193.136.227.163", 7000, Sha1.of_string "QACXXKHISU343ABYFO33Q7DXYWROGYLN";
+ Ip.of_string "194.117.20.214", 7000, Sha1.of_string "ILVVG7A73FBDWOV2ARMOUC4PQMO37LNA";
+ Ip.of_string "193.136.166.54", 7000, Sha1.of_string "KAPY7DT26UCRRXFBQ4KNQRSJUOBBDOXQ";
+ Ip.of_string "144.206.66.56", 7000, Sha1.of_string "N7DRHVSHAGJVLARHIJMGFMLCINEOPOBQ";
+ Ip.of_string "213.131.1.101", 7000, Sha1.of_string "ENBCLF6R65IEBBY7FHXVMKOKM4IY6P4R";
+ Ip.of_string "193.10.133.128", 7000, Sha1.of_string "C7ZR7H6GDATOU363UOY2DPJW3VKHN73P";
+ Ip.of_string "137.132.80.106", 7000, Sha1.of_string "YSUINDE2HHPQV3JBMQUAFVBJEA6X2IOX";
+ Ip.of_string "212.235.189.114", 7000, Sha1.of_string "SQ7KIVII5BRI3ZV7RKCQWP5CXZUYQVA6";
+ Ip.of_string "140.119.164.84", 7000, Sha1.of_string "OPZMQJSNSYXB7V3J2FAUDLJUIV3THJL3";
+ Ip.of_string "140.114.79.231", 7000, Sha1.of_string "TPK5HAUMP23GEAV5DS3TL2LXCZMLIA3N";
+ Ip.of_string "140.112.42.158", 7000, Sha1.of_string "GRSH625P5OSM634QMLAQHKMIQLCHEMXH";
+ Ip.of_string "140.127.208.238", 7000, Sha1.of_string "ZDA3EVRLPVLK5IWQ3ZXJ7XQKJGJCPD6M";
+ Ip.of_string "140.109.17.180", 7000, Sha1.of_string "Z3UVL6D5ZA6RNVQUOYMMHUHQL5B6ZCXD";
+ Ip.of_string "134.151.255.180", 7000, Sha1.of_string "P775H52X33VUQBDOO7NCK6BNBQMPQHM4";
+ Ip.of_string "128.232.103.201", 7000, Sha1.of_string "HO4CH7B5RCHTF7RJJDZPDR2GZS3XWPQJ";
+ Ip.of_string "193.63.75.18", 7000, Sha1.of_string "JOS2CNM4QPNOUSQCKJT6IYNOYD4U4NBE";
+ Ip.of_string "129.12.3.74", 7000, Sha1.of_string "DYOTHWYUCE56BUCV6SW6FF44F4T7SX7U";
+ Ip.of_string "194.36.10.156", 7000, Sha1.of_string "LQM6UL5APWYURSQSQKGOZFOB64RXI6YK";
+ Ip.of_string "138.251.214.77", 7000, Sha1.of_string "TKV24JSJ24UCOSRXA2LUE4GEMW5P3EPM";
+ Ip.of_string "193.63.58.70", 7000, Sha1.of_string "WJUMRWGYFJGAT7N3TNQJCPADMZSMNZ7I";
+ Ip.of_string "143.215.129.115", 7000, Sha1.of_string "25UIPJBXDWDCPHHO4LGUM3T7X7SA7MXK";
+ Ip.of_string "164.73.47.242", 7000, Sha1.of_string "ZE5WKLKRUNYSWDE7W6YZHK5WR7W3R5KI"
+ |]
diff --git a/sources/fabrice/pacemaker/pMDriver.ml b/sources/fabrice/pacemaker/pMDriver.ml
new file mode 100644
index 0000000..048101f
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMDriver.ml
@@ -0,0 +1,280 @@
+open SafeCaml
+open Pervasives
+
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+open PMTypes
+open PMNetwork
+open PMOptions
+open PMGlobals
+open PMHandlers
+
+
+
+let detach_daemon () =
+ try
+ let pid = Unix.unsafe_fork () in
+ if pid < 0 then failwith "Error in fork";
+ if pid > 0 then begin
+ no_at_exit ();
+ exit 0;
+ end;
+ reset_pid ();
+ let _sid = Unix.setsid () in
+
+(* Changed in 2.5.27 *)
+ begin
+ let dev_zero = Filename.of_unix_string "/dev/zero" in
+ let stdin_new = Unix.openfile dev_zero [Unix.O_RDONLY] 0o444 in
+ Unix.dup2 stdin_new Unix.stdin;
+ Unix.close stdin_new;
+ end;
+
+ begin
+ let dev_null = Filename.of_unix_string "/dev/null" in
+ let stdout_new = Unix.openfile dev_null [Unix.O_WRONLY] 0o666 in
+ Unix.dup2 stdout_new Unix.stdout;
+ Unix.dup2 stdout_new Unix.stderr;
+ Unix.close stdout_new;
+ end;
+
+ with e ->
+ lprintf "Exception %s in detach_daemon\n"
+ (Printexc2.to_string e);
+ exit 2
+
+
+let check_best_binary () =
+ if !!auto_update
+ && !!best_binary_time > 0L
+ && !!best_binary_hash <> PMArgs.binary_hash
+ then
+ let filename = Filename.add_basename info_dir
+ (Sha1.to_string !!best_binary_hash) in
+ if Sys.file_exists filename then
+ let s = File.to_string filename in
+ let hash = Sha1.string s in
+ if hash = !!best_binary_hash then begin
+ PMLog.log (Printf.sprintf "new_binary %s"
+ (Sha1.to_string hash));
+ Unix.chmod filename 0o755;
+ let mtime = Int64.to_float !!best_binary_time in
+ Unix.utimes filename mtime mtime;
+ Sys.remove binary_filename;
+ Unix.U.link (Filename.to_string filename)
+ (Filename.to_string binary_filename);
+ Unix.execv binary_name [| binary_name |]
+ end
+
+
+let every_second _ =
+ if not (Fifo.empty to_ping) then begin
+ let (h,ip,port) = Fifo.take to_ping in
+ PMLog.log (Printf.sprintf "udps PING %s" (Sha1.to_string h));
+ udp_send !current_ping ip port
+ end;
+ ()
+
+(*
+ List.iter (fun s, p ->
+ if p.peer_id <> !uid then
+ let state = PaceMakerNetwork.peer_state p in
+ Printf.printf "Status of connection to %s = %s\n%!"
+ s (NetP2P.string_of_state state);
+ match state with
+ DISCONNECTED ->
+ D P "Connecting...";
+ PaceMakerNetwork.connect p
+ | _ -> ()
+ ) servers_list
+*)
+
+let uptime = ref 0
+let periods = [| 10; 30; 60; 120 |]
+let heartbeats = Array.map (fun n -> Random.int n) periods
+
+
+let send_heartbeat period =
+ let time = Time.int64_time () in
+ let m = {
+ HeartBeatMsg.time = time;
+ server = my_uid;
+ period = period;
+ pubkey = sample_key_public;
+ privkey = sample_key_private;
+ signature = Rsa.sign
+ (Sha1.string (Printf.sprintf "%Ld-%s" time sample_key_public))
+ server_key;
+ } in
+ PMHandlers.register_heartbeat m;
+ let send_heartbeat o = match o with
+ None -> ()
+ | Some p -> send p HeartBeatMsg.msg m in
+ Array.iter send_heartbeat children;
+ Array.iter send_heartbeat parents
+
+let check_heartbeats () =
+ for i = 0 to Array.length periods - 1 do
+ let period = periods.(i) in
+ if !uptime = heartbeats.(i) then begin
+ send_heartbeat period;
+ let next_heartbeat = ((!uptime / period) + 1) * period + Random.int period in
+ heartbeats.(i) <- next_heartbeat
+ end
+ done
+
+let every_minute _ =
+ lprintf "every_minute";
+
+ if Fifo.empty to_ping then begin
+ List.iter (fun x ->
+ Fifo.put to_ping x) !!observed;
+ current_ping :=
+ Printf.sprintf "PING|%Ld|%s|%d" (Time.int64_time ())
+ (Sha1.to_string my_uid) !!my_port
+ end;
+
+ let nchildren = ref 0 in
+ let nparents = ref 0 in
+ let ncandidates = ref 0 in
+ let count c =
+ match c with
+ None -> ()
+ | Some p ->
+ match p.peer_status with
+ PEER_CANDIDATE _ -> incr ncandidates
+ | PEER_PARENT _ -> incr nparents
+ | PEER_CHILD _ -> incr nchildren
+ | _ -> ()
+ in
+ Array.iter count parents;
+ Array.iter count children;
+
+ PMLog.log (Printf.sprintf "up %d (%d) %d %d" !nparents !ncandidates !nchildren !peer_distance);
+ if !!run_as_server then check_heartbeats ();
+ if !!auto_update then check_best_binary ();
+ if !uptime mod 10 = 0 then begin
+ if not !!run_as_master then begin
+ lprintf "Connect to master";
+ connect master
+ end
+ end;
+ incr uptime; (* do this after check_heartbeats *)
+
+ if !!run_as_master then
+ save_nodes ()
+ else
+ for i = 0 to ndegree - 1 do
+ match parents.(i) with
+ Some _ -> ()
+ | None -> connect_candidate i
+ done
+
+let hours = ref 0
+
+let log_filename = Filename.add_basename
+ PMConst.config_dir (Printf.sprintf "%s.log" binary_basename)
+let log_filenameX = Filename.add_basename
+ PMConst.config_dir (Printf.sprintf "%s." binary_basename)
+
+let skip_first = ref true
+
+let rotate_logs () =
+ (try Sys.remove (Filename.add_suffix log_filenameX "9") with _ -> ());
+ for i = 9 downto 2 do
+ try
+ Sys.rename
+ (Filename.add_suffix log_filenameX (string_of_int (i-1)))
+ (Filename.add_suffix log_filenameX (string_of_int i))
+ with _ -> ()
+ done;
+ (try
+ Sys.rename log_filename (Filename.add_suffix log_filenameX "1")
+ with _ -> ());
+ LogPrintf.set_log_out_filename log_filename
+
+let every_hour _ =
+ lprintf "every_hour";
+ PMHandlers.clean_heartbeats ();
+ lprintf "clean_heartbeats";
+ incr hours;
+ if !skip_first then skip_first := false else rotate_logs ()
+
+let _ =
+ assert (servers_list <> [] || !!run_as_server || !!run_as_master);
+ rotate_logs ();
+(* if Sys.file_exists log_filename then Sys.remove log_filename; *)
+ set_verboses !!verbosity;
+
+ if (not !!run_as_master) && !!observed = [] then begin
+
+ for i = 1 to 25 do
+ let (x,y,z) = PMConst.allpeers.(Random.int (Array.length PMConst.allpeers)) in
+ observed =:= (z,x,y) :: !!observed
+ done;
+ must_save_options ();
+ save_options ()
+ end;
+
+ List.iter (fun (h,ip, port) ->
+ observed_by_id := Sha1Map.add h (ip,port) !observed_by_id
+ ) !!observed;
+
+ if !!best_binary_hash = PMArgs.binary_hash then
+ lprintf "Running best binary !"
+ else
+ check_best_binary ();
+
+ PMHandlers.main ();
+ set_my_id my_uid;
+ let rec bind_port current_port =
+ try
+ let _s = PaceMaker.bind_port current_port in
+ start_udp current_port;
+ set_my_port current_port;
+ if !!my_port = 0 then begin
+ lprintf "Setting port to %d" current_port;
+ my_port =:= current_port;
+ must_save_options ();
+ save_options ()
+ end
+ with e ->
+ lprintf "Cannot bind port %d: %s" current_port
+ (Printexc2.to_string e);
+ if !!my_port <> 0 then
+ begin
+ PMLog.log "bind_failed";
+ exit 2
+ end
+ else
+ bind_port (current_port+1)
+ in
+
+ bind_port (if !!my_port = 0 then !!min_port else !!my_port);
+
+ PMHandlers.clean_binaries ();
+
+ BasicSocket.add_infinite_timer 1 every_second;
+ BasicSocket.add_infinite_timer 60 every_minute;
+ BasicSocket.add_infinite_timer 3600 every_hour;
+
+ BasicSocket.add_timer 1 every_hour;
+ BasicSocket.add_timer 2 every_minute;
+
+
+(* Check if we are already running (create unix socket /tmp/pacemaker.sock) *)
+
+
+ lprintf "Pace-Maker started on %s" (Date.to_string (Date.current ()));
+ lprintf " UID: %s port: %d" (Sha1.to_string my_uid) !!my_port;
+ PMLog.log (Printf.sprintf "started %s" (Sha1.to_string PMArgs.binary_hash));
+ detach_daemon ();
+ reset_pid ();
+ TestUnix.save_pid ();
+ NetMain.main ()
+
+
diff --git a/sources/fabrice/pacemaker/pMGlobals.ml b/sources/fabrice/pacemaker/pMGlobals.ml
new file mode 100644
index 0000000..deb88f0
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMGlobals.ml
@@ -0,0 +1,261 @@
+open SafeCaml
+open Pervasives
+
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+open PMTypes
+open PMConst
+open PMNetwork
+open PMOptions
+
+
+let nservers = ref 0
+let servers_map = ref Sha1Map.empty
+
+let servers_list = List.map (fun (sha1, ip, port) ->
+ let p = new_peer sha1 (Some (ip, port)) in
+ incr nservers;
+(* p.peer_status <- PEER_SERVER; *)
+ servers_map := Sha1Map.add sha1 p !servers_map;
+ p
+ ) !!servers
+
+let to_ping = (Fifo.create () : (Sha1.t * Ip.t * int) Fifo.t)
+let current_ping = ref ""
+
+
+
+let nservers = !nservers
+let servers_map = !servers_map
+let servers_tab = Array.of_list servers_list
+
+let master =
+ let (sha1, ip, port) = !!master in
+ let p = new_peer sha1 (Some (ip,port)) in
+ p.peer_status <- PEER_MASTER;
+ p
+
+let ndegree = !!ndegree
+let my_uid = !!uid
+
+let parents = Array.create ndegree (None : peer_info option)
+let children = Array.create ndegree (None : peer_info option)
+let candidates = Array.init (max_distance+1) (fun _ ->
+ Fifo.create ())
+
+let peer_nparents = ref 0
+
+let data_dir = Filename.add_basename config_dir (Sha1.to_string my_uid)
+let info_dir = Filename.add_basename config_dir "info"
+
+
+let _ =
+ Unix.safe_mkdir data_dir;
+ Unix.safe_mkdir info_dir;
+
+
+ if !PMArgs.new_binary &&
+ (!!best_binary_hash <> PMArgs.binary_hash ||
+ !!best_binary_time < PMArgs.binary_mtime) then begin
+ lprintf "Preparing binary for exportation";
+ let filename = Filename.add_basename info_dir
+ (Sha1.to_string PMArgs.binary_hash) in
+ let new_binary_ok =
+ if not (Sys.file_exists filename) ||
+ Sha1.string (File.to_string filename) <> PMArgs.binary_hash then
+ let s = File.to_string binary_filename in
+ File.of_string filename s;
+ lprintf "Binary exported";
+ Sha1.string (File.to_string filename) = PMArgs.binary_hash
+ else begin
+ lprintf "Binary already exported";
+ true
+ end
+ in
+
+ if new_binary_ok then begin
+ best_binary_hash =:= PMArgs.binary_hash;
+ best_binary_time =:= PMArgs.binary_mtime;
+ must_save_options ();
+ save_options ()
+ end else begin
+ lprintf "Cannot export new binary";
+ exit 2
+ end
+ end
+
+
+let heartbeats = (Hashtbl.create 2047 : (HeartBeatMsg.msg, bool) Hashtbl.t)
+
+type node = {
+ node_name : string;
+ node_ip : Ip.t option;
+ mutable node_port : int;
+ mutable node_hash : Sha1.t option;
+ mutable node_last : string option;
+ }
+
+let nodes_by_ip = Hashtbl.create 331
+let nodes = ref []
+
+let register_node node =
+ nodes := node :: !nodes;
+ match node.node_ip with
+ None -> ()
+ | Some ip ->
+ Hashtbl.add nodes_by_ip ip node
+
+let nodes_filename = Filename.add_basename config_dir "nodes.txt"
+
+let save_nodes () =
+ let b = Buffer.create 10000 in
+ List.iter (fun n ->
+ Printf.bprintf b "%s %s %d %s %s\n" n.node_name
+ (match n.node_ip with
+ None -> "---"
+ | Some ip -> Ip.to_string ip)
+ n.node_port
+ (match n.node_hash with
+ None -> "---"
+ | Some hash -> Sha1.to_string hash)
+ (match n.node_last with
+ None -> "---"
+ | Some s -> s)
+ ) !nodes;
+ File.of_string nodes_filename (Buffer.contents b)
+
+let _ =
+ if !!run_as_master then
+ let nodes_txt = try
+ File.to_string nodes_filename
+ with e ->
+ lprintf "Cannot load nodes.txt: aborting as master";
+ exit 2
+ in
+ List.iter (fun line ->
+ match String.split_simplify line ' ' with
+ [] -> ()
+ | [ node_name ] ->
+ let node_ip = try
+ Some (Ip.from_name node_name)
+ with _ -> None
+ in
+ register_node {
+ node_name = node_name;
+ node_ip = node_ip;
+ node_port = 0;
+ node_hash = None;
+ node_last = None;
+ }
+ | [ node_name; node_ip; node_port; node_hash; node_last ] ->
+ let node_ip = if node_ip = "---" then None else
+ Some (Ip.of_string node_ip)
+ in
+ let node_hash = if node_hash = "---" then None else
+ Some (Sha1.of_string node_hash)
+ in
+ let node_last = if node_last = "---" then None else
+ Some node_last
+ in
+ register_node {
+ node_name = node_name;
+ node_ip = node_ip;
+ node_port = int_of_string node_port;
+ node_hash = node_hash;
+ node_last = node_last;
+ }
+ | _ -> assert false
+ ) (String.split nodes_txt '\n');
+ nodes := List.rev !nodes;
+ save_nodes ()
+
+let connected_to_node id ip port =
+ try
+ let n = Hashtbl.find nodes_by_ip ip in
+ n.node_hash <- Some id;
+ n.node_port <- port;
+ n.node_last <- Some (Date.DASHED.to_string (Date.current ()))
+ with Not_found ->
+ register_node {
+ node_name = "---";
+ node_ip = Some ip;
+ node_port = port;
+ node_hash = Some id;
+ node_last = Some (Date.DASHED.to_string (Date.current ()));
+ }
+
+let old_binaries_map = ref StringMap.empty
+
+let _ =
+ List.iter (fun (basename, sizeL) ->
+ old_binaries_map := StringMap.add basename sizeL !old_binaries_map
+ ) !!old_binaries;
+ old_binaries =:= List.sort compare !!old_binaries
+
+let save_old_binaries () =
+ let binaries = ref [] in
+ StringMap.iter (fun basename sizeL ->
+ binaries := (basename, sizeL) :: !binaries) !old_binaries_map;
+ let binaries = List.sort compare !binaries in
+ if binaries <> !!old_binaries then begin
+ old_binaries =:= binaries;
+ must_save_options ();
+ save_options ()
+ end
+
+let peer_ncandidates = ref 0
+let candidate_round = ref 1
+
+let get_candidate () =
+ let rec iter i =
+ if i <= max_distance then
+ if Fifo.empty candidates.(i) then iter (i+1)
+ else begin
+ decr peer_ncandidates;
+ Some (Fifo.take candidates.(i))
+ end
+ else
+ None
+ in
+ iter 0
+
+let add_candidate p =
+ if p.peer_candidate < !candidate_round then begin
+ Fifo.put candidates.(p.peer_distance) p;
+ incr peer_ncandidates;
+ p.peer_candidate <- !candidate_round
+ end
+
+module Rsa = struct
+
+ type t = unit
+
+ let generate _ = ()
+ let string_of_public _ = String.create 450
+ let string_of_private _ = String.create 128
+ let public_of_string _ = ()
+
+ let sign string () = String.create 256
+ let verify string signature () = true
+ end
+
+let server_key = Rsa.generate 1024 (* this one is normally not available *)
+let server_key_public = server_key
+
+let sample_key = Rsa.generate 1024
+let sample_key_public = Rsa.string_of_public sample_key
+let sample_key_private = Rsa.string_of_private sample_key
+
+
+let observed_by_id = ref Sha1Map.empty
+let add_observed h ip port =
+ if not (Sha1Map.mem h !observed_by_id) then begin
+ observed =:= (h, ip, port) :: !!observed;
+ must_save_options ();
+ save_options ()
+ end;
+ observed_by_id := Sha1Map.add h (ip,port) !observed_by_id
diff --git a/sources/fabrice/pacemaker/pMHandlers.ml b/sources/fabrice/pacemaker/pMHandlers.ml
new file mode 100644
index 0000000..09bd232
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMHandlers.ml
@@ -0,0 +1,709 @@
+open SafeCaml
+open Pervasives
+
+open Int64ops
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+open PMTypes
+open PMNetwork
+open PMConst
+open PMOptions
+open PMGlobals
+
+
+let declare_handler msg f = PaceMaker.declare_handler msg (fun p m ->
+ PMLog.peer_log (Printf.sprintf "recv %s" msg.message_name) p;
+ f p m)
+
+let send p msg m =
+ PMLog.peer_log (Printf.sprintf "send %s" msg.message_name) p;
+ try
+ PaceMaker.send p msg m
+ with e ->
+ lprintf "Exception %s while sending to peer %s"
+ (Printexc2.to_string e) (Sha1.to_string p.peer_id)
+
+let connect p =
+ p.peer_last_try <- Time.offset_time ();
+ PMLog.peer_log "connect" p;
+ PaceMaker.connect p
+
+let refill_candidates _ =
+(* Try to refill using the peer table: NetP2P.iter_peers *)
+ if !peer_ncandidates < 10 then begin
+ incr candidate_round;
+ List.iter (fun p ->
+ add_candidate p
+ ) servers_list
+ end
+
+let rec connect_candidate i =
+ match get_candidate () with
+ None ->
+(* wait 30 seconds before refilling *)
+ BasicSocket.add_timer 30 refill_candidates
+ | Some p ->
+
+ match p.peer_status with
+ PEER_UNKNOWN when p.peer_id <> my_uid ->
+ if Time.offset_time () - p.peer_last_try < 600 then
+(* Don't reconnect to a peer within 5 minutes *)
+ connect_candidate i
+ else begin
+ try
+ p.peer_last_try <- Time.offset_time ();
+ connect p;
+ parents.(i) <- Some p;
+ p.peer_status <- PEER_CANDIDATE i;
+ with e ->
+ lprintf "Exception %s while connecting peer %s"
+ (Printexc2.to_string e)
+ (string_of_peer p)
+ end
+
+
+ | _ -> connect_candidate i
+
+
+let peer_distance = ref (if !!run_as_server then 0 else max_distance)
+let peer_server = ref Sha1.null
+
+
+let distance_msg () =
+ {
+ DistanceMsg.distance = !peer_distance;
+ server = !peer_server;
+ }
+
+
+let send_distance p msg = send p DistanceMsg.msg msg
+
+let broadcast_message msg m =
+ let send_message o = match o with
+ None -> ()
+ | Some p ->
+ match p.peer_status with
+ PEER_CHILD _ | PEER_PARENT _ ->
+ send p msg m
+ | PEER_UNKNOWN ->
+ lprintf "WARNING: attempt to send heartbeat to unknown peer"
+ | PEER_CANDIDATE _ ->
+ lprintf "Dropping heartbeat for candidate"
+ | PEER_MASTER -> assert false
+ in
+ Array.iter send_message children;
+ Array.iter send_message parents
+
+
+let update_distance () =
+ let last_distance = !peer_distance in
+ if !!run_as_server then begin
+ peer_distance := 0;
+ peer_server := my_uid
+ end else begin
+ peer_distance := max_distance;
+ peer_server := Sha1.null;
+ for i = 0 to ndegree - 1 do
+ match parents.(i) with
+ | Some {
+ peer_status = PEER_PARENT _ ;
+ peer_server = server;
+ peer_distance = distance } ->
+ if distance < !peer_distance then begin
+ peer_distance := distance;
+ peer_server := server;
+ end
+ | _ -> ()
+ done;
+ peer_distance := min (!peer_distance+1) max_distance
+ end;
+ if !peer_distance <> last_distance then
+ broadcast_message DistanceMsg.msg (distance_msg ())
+
+
+let register_heartbeat msg =
+ PMLog.log (Printf.sprintf "heartbeat %s %Ld %d"
+ (Sha1.to_string msg.HeartBeatMsg.server)
+ msg.HeartBeatMsg.time msg.HeartBeatMsg.period);
+ Hashtbl.add heartbeats msg true
+
+let clean_heartbeats () =
+ let to_delete = ref [] in
+ let curtime = Time.int64_time () in
+
+ Hashtbl.iter (fun m _ ->
+ if curtime -- m.HeartBeatMsg.time > 86000L then
+ to_delete := m :: !to_delete
+ ) heartbeats;
+ List.iter (fun m ->
+ Hashtbl.remove heartbeats m
+ ) !to_delete
+
+let set_longpeer p =
+ set_lifetime p 8640000;
+ set_rtimeout p 7200
+
+let set_shortpeer p =
+ set_lifetime p 120;
+ set_rtimeout p 59
+
+let new_sync p dir =
+ let s = {
+ directory = dir;
+ old_files = StringMap.empty;
+ new_files = [];
+ data_queued = 0;
+ } in
+ p.peer_sync <- Some s;
+ set_max_output_buffer p 400000;
+ s
+
+let chunk_sizeL = 65000L
+let chunk = String.create 65000
+
+let rec send_files p s =
+ if s.data_queued < 250000 then
+ match s.new_files with
+ [] ->
+ lprintf "No file to transfer";
+ if !!run_as_master then set_lifetime p 120
+ | (basename, new_sizeL) :: files ->
+
+ let old_sizeL = try
+ StringMap.find basename s.old_files
+ with Not_found ->
+ lprintf "Filename %s not found" basename;
+ 0L in
+
+ if old_sizeL < new_sizeL then begin
+
+ lprintf "File %s : %Ld bytes remaining" basename
+ (new_sizeL -- old_sizeL);
+ let filename = Filename.add_basename s.directory basename in
+ let max_sizeL = new_sizeL -- old_sizeL in
+ let max_sizeL = min chunk_sizeL max_sizeL in
+ let max_size = Int64.to_int max_sizeL in
+ Unix.read_chunk (Unix.create_ro filename) old_sizeL
+ chunk 0 max_size;
+
+ send p BlockMsg.msg {
+ BlockMsg.filename = Filename.to_string filename;
+ file_pos = old_sizeL;
+ file_content = String.sub chunk 0 max_size;
+ };
+
+ s.old_files <- StringMap.add basename (old_sizeL ++ max_sizeL)
+ s.old_files;
+ s.data_queued <- s.data_queued + max_size;
+ send_files p s
+ end else begin
+ lprintf "Finished with file %s" basename;
+
+ begin
+ match p.peer_status with
+ PEER_MASTER ->
+ lprintf "\tFile uploaded to master";
+ if basename <> !PMLog.current_basename then begin
+ lprintf "Deleting log file %s" basename;
+ let filename = Filename.add_basename s.directory basename in
+ (try Sys.remove filename with _ -> ())
+ end
+ | PEER_PARENT _ -> lprintf "\tFile uploaded to parent"
+ | PEER_CHILD _ -> lprintf "\tFile uploaded to child"
+ | _ -> ()
+ end;
+
+ s.new_files <- files;
+ send_files p s
+ end
+ else
+ lprintf "Too much queued data %d" s.data_queued
+
+(*
+let send_files p =
+ match p.peer_sync with
+ None -> ()
+ | Some s -> send_files p s
+ *)
+
+let clean_binaries () =
+ let files = Unix.list_directory info_dir in
+ let best_binary = Sha1.to_string !!best_binary_hash in
+ let must_save_old_binaries = ref false in
+ List.iter (fun basename ->
+ if basename <> best_binary then begin
+ lprintf "Deleting old binary %s" basename;
+ try
+ let filename = Filename.add_basename info_dir basename in
+ let sizeL = Unix.getsize filename in
+ let old_sizeL = try
+ StringMap.find basename !old_binaries_map
+ with Not_found -> 0L
+ in
+ Sys.remove filename;
+ if sizeL > old_sizeL then begin
+ old_binaries_map := StringMap.add basename sizeL
+ !old_binaries_map;
+ must_save_old_binaries := true
+ end
+ with e ->
+ lprintf "Exception %s in clean_binaries %s"
+ (Printexc2.to_string e) basename
+ end
+ ) files;
+ if !must_save_old_binaries then save_old_binaries ()
+
+let start_relationship p =
+ send_distance p (distance_msg ());
+ send p InfoMsg.msg {
+ InfoMsg.best_binary_time = !!best_binary_time;
+ best_binary_hash = !!best_binary_hash;
+ };
+ send p ListDirectoryMsg.msg {
+ ListDirectoryMsg.directory = Filename.to_string info_dir
+ }
+
+
+let main () =
+
+ declare_handler IdentifiedMsg.msg
+ (fun p msg ->
+ let _my_ip = msg.IdentifiedMsg.ip in
+ let _my_port = msg.IdentifiedMsg.port in
+ let other_port = msg.IdentifiedMsg.my_port in
+ p.peer_last_connected <- Time.offset_time ();
+ begin
+ match p.peer_addr with
+ None -> ()
+ | Some (ip,port) ->
+ lprintf "Updating ports %s:%d to %s:%d"
+ (Ip.to_string ip) port (Ip.to_string ip) other_port;
+ p.peer_addr <- Some (ip, other_port)
+ end;
+ p.peer_sync <- None;
+(* This is run when a peer as just been identified *)
+ lprintf "Connected to %s" (string_of_peer p);
+ if !!run_as_master then begin
+ set_rtimeout p 120;
+ match p.peer_addr with
+ None -> ()
+ | Some (other_ip,other_port) ->
+ connected_to_node p.peer_id other_ip other_port
+ end else
+ match p.peer_status with
+ PEER_CANDIDATE i ->
+ set_shortpeer p;
+ send p AskParentMsg.msg
+ { AskParentMsg.distance = !peer_distance;
+ server = !peer_server;
+ nparents = !peer_nparents;
+ }
+ | PEER_MASTER ->
+ set_rtimeout p 120;
+ send p ListDirectoryMsg.msg {
+ ListDirectoryMsg.directory = Filename.to_string data_dir
+ }
+ | _ ->
+ set_shortpeer p
+ );
+
+ declare_handler ByeMsg.msg
+ (fun p msg ->
+ p.peer_sync <- None;
+ lprintf "Disconnecting from %s (%s)"
+ (string_of_peer p)
+ (string_of_state msg.ByeMsg.from_state);
+ match p.peer_status with
+ PEER_UNKNOWN -> ()
+ | PEER_PARENT i ->
+ p.peer_status <- PEER_UNKNOWN;
+ PMLog.log (Printf.sprintf "lost_parent %s"
+ (Sha1.to_string p.peer_id));
+ decr peer_nparents;
+ update_distance ();
+ parents.(i) <- None;
+ connect_candidate i
+ | PEER_CANDIDATE i ->
+ p.peer_status <- PEER_UNKNOWN;
+ parents.(i) <- None;
+ connect_candidate i
+ | PEER_CHILD i ->
+ PMLog.log (Printf.sprintf "lost_child %s"
+ (Sha1.to_string p.peer_id));
+ p.peer_status <- PEER_UNKNOWN;
+ children.(i) <- None
+ | PEER_MASTER -> ()
+ );
+
+
+
+ declare_handler AskParentMsg.msg
+ (fun p msg ->
+
+
+ let distance = msg.AskParentMsg.distance in
+ let parent_ok =
+(* don't accept children if we have no parents *)
+ if !peer_distance = max_distance then false
+ else
+
+(* if our distance is different from the one of this peer, we should drop
+any peer with the same distance as us, or, if the peer is an orphan,
+any peer with a distance smaller to us. *)
+ let _ =
+ if !peer_distance <> distance then begin
+ let compare =
+ if msg.AskParentMsg.nparents = 0 then
+ (<=)
+ else
+ (=)
+ in
+ lprintf "Checking if some child should be dropped";
+ let rec iter compare i can_drop =
+ if i < ndegree then
+ match children.(i) with
+ Some p ->
+ if p.peer_distance < max_distance &&
+ compare p.peer_distance !peer_distance then
+ iter compare (i+1) (Some p)
+ | None -> ()
+ else
+ match can_drop with
+ None ->
+ lprintf "Sorry, all children slots taken by correct peers"
+ | Some p ->
+ lprintf "Disconnecting peer with same distance";
+ disconnect p
+ in
+ iter compare 0 None
+ end;
+ in
+
+(* check if there is an empty slot *)
+ let rec iter i =
+ if i < ndegree then
+ match children.(i) with
+ Some _ -> iter (i+1)
+ | None ->
+ p.peer_status <- PEER_CHILD i;
+ PMLog.log (Printf.sprintf "new_child %s"
+ (Sha1.to_string p.peer_id));
+ children.(i) <- Some p;
+ set_longpeer p;
+ true
+ else false
+ in
+ iter 0
+ in
+
+ let candidates = ref [] in
+ let add_candidate p =
+ match p with
+ Some ({
+ peer_addr = Some (ip, port);
+ peer_status = (PEER_CHILD _ | PEER_PARENT _);
+ } as p) ->
+ candidates := {
+ AskParentReplyMsg.cand_id = p.peer_id;
+ AskParentReplyMsg.cand_ip = ip;
+ cand_port = port;
+ cand_distance = p.peer_distance;
+ cand_server = p.peer_server
+ } :: !candidates
+ | _ -> ()
+ in
+ for i = 0 to ndegree - 1 do
+ add_candidate parents.(i);
+ add_candidate children.(i)
+ done;
+ send p AskParentReplyMsg.msg {
+ AskParentReplyMsg.parent_ok = parent_ok;
+ candidates = !candidates;
+ } ;
+ if parent_ok then
+ start_relationship p;
+ );
+
+
+
+ declare_handler AskParentReplyMsg.msg
+ (fun p msg ->
+
+ begin
+ match p.peer_status with
+ PEER_CANDIDATE i ->
+ if msg.AskParentReplyMsg.parent_ok then begin
+ p.peer_status <- PEER_PARENT i;
+ incr peer_nparents;
+ set_longpeer p;
+ PMLog.log (Printf.sprintf "new_parent %s"
+ (Sha1.to_string p.peer_id));
+ start_relationship p;
+ end else begin
+ p.peer_status <- PEER_UNKNOWN;
+ parents.(i) <- None;
+ connect_candidate i
+ end
+ | _ ->
+ lprintf "AskParentReplyMsg from peer %s in status %s"
+ (string_of_peer p) (string_of_status p.peer_status)
+ end;
+
+ List.iter (fun cand ->
+ let p = new_peer cand.AskParentReplyMsg.cand_id
+ (Some (cand.AskParentReplyMsg.cand_ip,
+ cand.AskParentReplyMsg.cand_port)) in
+ if p.peer_distance > cand.AskParentReplyMsg.cand_distance then begin
+ p.peer_distance <- cand.AskParentReplyMsg.cand_distance;
+ p.peer_server <- cand.AskParentReplyMsg.cand_server;
+ end;
+ add_candidate p
+ ) msg.AskParentReplyMsg.candidates;
+ );
+
+
+
+
+ declare_handler DistanceMsg.msg
+ (fun p msg ->
+ p.peer_distance <- msg.DistanceMsg.distance;
+ p.peer_server <- msg.DistanceMsg.server;
+ update_distance ();
+ );
+
+ declare_handler HeartBeatMsg.msg
+ (fun p msg ->
+
+ if Time.int64_time () -- msg.HeartBeatMsg.time < 86000L then
+
+ if not (Hashtbl.mem heartbeats msg) then begin
+ register_heartbeat msg;
+ broadcast_message HeartBeatMsg.msg msg
+ end
+ );
+
+
+ declare_handler ChallengeMsg.msg
+ (fun p msg ->
+(* since we don't store yet pulses, we use a sample_key just to implement
+ the cryptography. *)
+ let reply = Rsa.sign
+ (Sha1.string (Printf.sprintf "%s-%s-%s"
+ msg.ChallengeMsg.nonce
+ (Sha1.to_string p.peer_id)
+ (Sha1.to_string my_uid)
+ )) sample_key in
+
+(* We sign the key instead of the server, but normally, we would
+find it in the pulse. See comment above. *)
+ let signature = Rsa.sign
+ (Sha1.string (Printf.sprintf "%Ld-%s"
+ msg.ChallengeMsg.time
+ sample_key_public)) server_key in
+
+ send p ProofMsg.msg
+ {
+ ProofMsg.time = msg.ChallengeMsg.time;
+ nonce = msg.ChallengeMsg.nonce;
+ pubkey = sample_key_public;
+ signature = signature;
+ reply = reply;
+ }
+ );
+
+
+ declare_handler ProofMsg.msg
+ (fun p msg ->
+(* We should first verify that, indeed, we sent the challenge ! *)
+
+ let pubkey = Rsa.public_of_string msg.ProofMsg.pubkey in
+ let reply = Rsa.verify
+ (Sha1.string (Printf.sprintf "%s-%s-%s"
+ msg.ProofMsg.nonce
+ (Sha1.to_string my_uid)
+ (Sha1.to_string p.peer_id)
+ )) msg.ProofMsg.reply pubkey in
+
+(* We sign the key instead of the server, but normally, we would
+find it in the pulse. See comment above. *)
+ let signature = Rsa.verify
+ (Sha1.string (Printf.sprintf "%Ld-%s"
+ msg.ProofMsg.time
+ msg.ProofMsg.pubkey)) msg.ProofMsg.signature
+ server_key_public in
+
+ if reply && signature then
+(* Good, this reply is correct *)
+ ()
+ else
+(* Bad, incorrect reply, ban this peer *)
+ ()
+ );
+
+
+
+ declare_handler ListDirectoryMsg.msg
+ (fun p m ->
+ let directory = m.ListDirectoryMsg.directory in
+ let dir = Filename.of_string directory in
+ Unix.safe_mkdir dir;
+ let files = Unix.list_directory dir in
+ let old_files = ref (
+ if directory = Filename.to_string info_dir then
+ !old_binaries_map
+ else
+ StringMap.empty) in
+
+ let add_file basename sizeL =
+ try
+ let old_sizeL = StringMap.find basename !old_files in
+ if old_sizeL < sizeL then raise Not_found
+ with Not_found ->
+ old_files := StringMap.add basename sizeL !old_files
+ in
+ List.iter (fun basename ->
+ let filename = Filename.add_basename dir basename in
+ let sizeL = Unix.getsize filename in
+ add_file basename sizeL
+ ) files;
+ let files = ref [] in
+ StringMap.iter (fun basename sizeL ->
+ files := (basename, sizeL) :: !files
+ ) !old_files;
+ send p ListDirectoryReplyMsg.msg {
+ ListDirectoryReplyMsg.directory = directory;
+ files = !files;
+ }
+ );
+
+
+
+ declare_handler ListDirectoryReplyMsg.msg
+ (fun p m ->
+ let directory = m.ListDirectoryReplyMsg.directory in
+ let dir = Filename.of_string directory in
+
+ let s = new_sync p dir in
+
+ List.iter (fun (basename, sizeL) ->
+ s.old_files <- StringMap.add basename sizeL s.old_files
+ ) m.ListDirectoryReplyMsg.files;
+
+ let files = Unix.list_directory dir in
+ let files = List.map (fun basename ->
+ let filename = Filename.add_basename dir basename in
+ let sizeL = Unix.getsize filename in
+ (basename, sizeL)
+ ) files in
+ s.new_files <- files;
+ send_files p s
+ );
+
+
+ declare_handler BlockMsg.msg
+ (fun p m ->
+
+ let filename = m.BlockMsg.filename in
+ let filenameF = Filename.of_string filename in
+ let file_pos = m.BlockMsg.file_pos in
+ let file_content = m.BlockMsg.file_content in
+ let file_content_size = String.length file_content in
+ Unix.write_chunk (Unix.create_rw filenameF) file_pos
+ file_content 0 file_content_size;
+
+ send p BlockReplyMsg.msg {
+ BlockReplyMsg.filename = filename;
+ file_pos = file_pos;
+ file_content_size = file_content_size;
+ }
+
+ );
+
+
+
+ declare_handler BlockReplyMsg.msg
+ (fun p m ->
+
+ let filename = m.BlockReplyMsg.filename in
+ let _filenameF = Filename.of_string filename in
+ let _file_pos = m.BlockReplyMsg.file_pos in
+ let file_content_size = m.BlockReplyMsg.file_content_size in
+
+ match p.peer_sync with
+ None -> ()
+ | Some s ->
+ s.data_queued <- s.data_queued - file_content_size;
+ send_files p s
+ );
+
+
+ declare_handler InfoMsg.msg
+ (fun p m ->
+
+ if m.InfoMsg.best_binary_time > !!best_binary_time then begin
+ best_binary_time =:= m.InfoMsg.best_binary_time;
+ best_binary_hash =:= m.InfoMsg.best_binary_hash;
+ must_save_options ();
+ save_options ();
+
+ clean_binaries ()
+ end
+ );
+
+
+ ()
+
+let udp_sock = ref None
+
+let udp_send msg ip port =
+ match !udp_sock with
+ None -> assert false
+ | Some udp_sock ->
+ UdpSocket.write udp_sock msg ip port
+
+
+let start_udp udp_port =
+ let packet_handler p =
+ let ip, _port =
+ match p.UdpSocket.udp_addr with
+ Unix.ADDR_INET (ip, port) -> Ip.of_inet_addr ip, port
+ | _ -> Ip.localhost, 0
+ in
+ let m = p.UdpSocket.udp_content in
+ match String.split_simplify m '|' with
+ [ "PING"; time; uid; port ] ->
+
+ PMLog.log (Printf.sprintf "udpr PING %s %s" uid time);
+ let uid = Sha1.of_string uid in
+ let port = int_of_string port in
+ add_observed uid ip port;
+ udp_send (Printf.sprintf "PONG|%s|%s|%d" time
+ (Sha1.to_string my_uid) !!my_port) ip port
+
+ | [ "PONG"; time; uid; port ] ->
+
+ PMLog.log (Printf.sprintf "udpr PONG %s %s" uid time);
+ let uid = Sha1.of_string uid in
+ let port = int_of_string port in
+ add_observed uid ip port
+
+ | _ -> ()
+
+ in
+ let sock =
+ UdpSocket.create Unix.inet_addr_any udp_port (fun sock event ->
+ match event with
+ UdpSocket.READ_DONE ->
+ UdpSocket.read_packets sock packet_handler
+ | _ -> ()
+ )
+ in
+ udp_sock := Some sock
+
+
+
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/pMLog.ml b/sources/fabrice/pacemaker/pMLog.ml
new file mode 100644
index 0000000..4418d35
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMLog.ml
@@ -0,0 +1,53 @@
+open SafeCaml
+
+open Pervasives
+
+open Int64ops
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+open PMTypes
+open PMConst
+open PMNetwork
+open PMGlobals
+
+let oc_ref = ref None
+
+let current_basename = ref ""
+
+let rec get_oc curtime =
+ match !oc_ref with
+ Some (oc, ctime) ->
+ if curtime -- ctime > 86400L then begin
+ Pervasives.OLD.close_out oc;
+ oc_ref := None;
+ get_oc curtime
+ end else
+ oc
+ | None ->
+ let basename = Printf.sprintf "%s-%Ld.txt" (Sha1.to_string my_uid) curtime
+ in
+ current_basename := basename;
+ let filename = Filename.add_basename data_dir basename in
+ let oc = open_out_gen [Open_append; Open_creat;Open_binary ]
+ 0o644 (Filename.to_string filename) in
+ Pervasives.OLD.output_char oc '\n';
+ oc_ref := Some (oc, curtime);
+ oc
+
+
+
+let log s =
+ let curtime = Time.int64_time () in
+ let oc = get_oc curtime in
+ let s = Printf.sprintf "%Ld %s\n" curtime s in
+ lprintf "LOG: %s" s;
+ Pervasives.OLD.output_string oc s;
+ Pervasives.OLD.flush oc
+
+let peer_log s p =
+ log (Printf.sprintf "%s %s" s (Sha1.to_string p.peer_id))
+
diff --git a/sources/fabrice/pacemaker/pMNetwork.ml b/sources/fabrice/pacemaker/pMNetwork.ml
new file mode 100644
index 0000000..59fb618
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMNetwork.ml
@@ -0,0 +1,435 @@
+open Checksum
+
+open PMTypes
+open PMConst
+
+module PaceMaker = NetP2P.MakeNetwork (TcpSocket)(struct
+ type peer = peer_info
+
+ let new_peer peer_id peer_addr =
+ {
+ peer_id = peer_id;
+ peer_addr = peer_addr;
+ peer_conn = None;
+
+ peer_sync = None;
+ peer_distance = max_distance;
+ peer_server = Sha1.null;
+(* peer_type = PEER_NORMAL; *)
+ peer_candidate = 0;
+ peer_status = PEER_UNKNOWN;
+ peer_last_try = - 86400;
+ peer_last_connected = - 86400;
+ }
+ let peer_id p = p.peer_id
+ let peer_address p = p.peer_addr
+ let peer_connection p = p.peer_conn
+ let set_peer_connection p c = p.peer_conn <- c
+
+ let protocol_name = "pace-maker"
+ end)
+
+include PaceMaker
+
+(* these ones are redefined in PMHandlers, so prevent other modules from
+using them directly *)
+let send = ()
+let declare_handler = ()
+let connect = ()
+
+
+module AskParentMsg = struct
+
+ type msg = {
+ distance : int;
+ server: Sha1.t;
+ nparents : int;
+ }
+
+ let msg = declare_message "ASK_PARENT"
+ (fun b m ->
+ AnyEndian.buf_int8 b m.distance;
+ AnyEndian.buf_sha1 b m.server;
+ AnyEndian.buf_int8 b m.nparents
+ )
+ (fun s pos ->
+ try
+ let distance = AnyEndian.get_uint8 s pos in
+ let server,pos = AnyEndian.get_sha1_pos s (pos+1) in
+ let nparents = try
+ AnyEndian.get_uint8 s pos
+ with _ -> 1 in
+ { distance = distance;
+ server = server;
+ nparents = nparents;
+ }
+ with _ -> { distance = 10; server = Sha1.null; nparents = 1; }
+ )
+ (fun msg ->
+ Printf.sprintf "ASK_PARENT {\n\tdistance = %d\n\tserver = %s\n\tnparents = %d }\n"
+ msg.distance (Sha1.to_string msg.server) msg.nparents)
+
+ end
+
+module AskParentReplyMsg = struct
+
+ type candidate = {
+ cand_id : Sha1.t;
+ cand_ip : Ip.t;
+ cand_port : int;
+ cand_distance : int;
+ cand_server : Sha1.t;
+ }
+
+ type msg = {
+ parent_ok : bool;
+ candidates : candidate list
+ }
+
+ let msg = declare_message "ASK_PARENT_REPLY"
+ (fun b m ->
+ AnyEndian.buf_bool b m.parent_ok;
+ AnyEndian.buf_list8 (fun b c ->
+ AnyEndian.buf_sha1 b c.cand_id;
+ LittleEndian.buf_ip b c.cand_ip;
+ LittleEndian.buf_int16 b c.cand_port;
+ AnyEndian.buf_int8 b c.cand_distance;
+ AnyEndian.buf_sha1 b c.cand_server
+ ) b m.candidates;
+ )
+ (fun s pos ->
+ let parent_ok = AnyEndian.get_bool s pos in
+ let candidates, pos = AnyEndian.get_list8
+ (fun s pos ->
+ let id,pos = AnyEndian.get_sha1_pos s pos in
+ let ip,pos = LittleEndian.get_ip_pos s pos in
+ let port, pos = LittleEndian.get_int16 s pos in
+ let distance = AnyEndian.get_uint8 s pos in
+ let server,pos = AnyEndian.get_sha1_pos s (pos+1) in
+ { cand_id = id;
+ cand_ip = ip;
+ cand_port = port;
+ cand_distance = distance;
+ cand_server = server
+ }, pos
+ ) s (pos+1) in
+ {
+ parent_ok = parent_ok;
+ candidates = candidates;
+ }
+ )
+ (fun m ->
+ let b = Buffer.create 10000 in
+ Printf.bprintf b "ASK_PARENT_REPLY {\n\tparent_ok = %b\n\tcandidates:\n" m.parent_ok;
+ List.iter (fun cand ->
+ Printf.bprintf b "\t\t%s %s:%d %d\n"
+ (Sha1.to_string cand.cand_id)
+ (Ip.to_string cand.cand_ip) cand.cand_port
+ cand.cand_distance
+ ) m.candidates;
+ Printf.bprintf b " }\n";
+ Buffer.contents b)
+
+
+ end
+
+
+
+module DistanceMsg = struct
+
+ type msg = {
+ distance : int;
+ server: Sha1.t;
+ }
+
+ let msg = declare_message "DISTANCE"
+ (fun b m ->
+ AnyEndian.buf_int8 b m.distance;
+ AnyEndian.buf_sha1 b m.server)
+ (fun s pos ->
+ let distance = AnyEndian.get_uint8 s pos in
+ let server,pos = AnyEndian.get_sha1_pos s (pos+1) in
+ { distance = distance; server = server }
+ )
+ (fun msg ->
+ Printf.sprintf "DISTANCE {\n\tdistance = %d\n\tserver = %s\n }\n"
+ msg.distance (Sha1.to_string msg.server))
+
+ end
+
+module InfoMsg = struct
+
+ type msg = {
+ best_binary_time : int64;
+ best_binary_hash: Sha1.t;
+ }
+
+ let msg = declare_message "INFO"
+ (fun b m ->
+ AnyEndian.buf_sha1 b m.best_binary_hash;
+ LittleEndian.buf_int64 b m.best_binary_time;
+ )
+ (fun s pos ->
+ let best_binary_hash,pos = AnyEndian.get_sha1_pos s pos in
+ let best_binary_time, pos = LittleEndian.get_int64 s pos in
+ { best_binary_time = best_binary_time;
+ best_binary_hash = best_binary_hash }
+ )
+ (fun msg ->
+ Printf.sprintf "INFO {\n\tbest_binary_time = %Ld\n\tbest_binary_hash = %s\n }\n"
+ msg.best_binary_time (Sha1.to_string msg.best_binary_hash))
+
+ end
+
+
+module HeartBeatMsg = struct
+
+ type msg = {
+ time : int64;
+ server: Sha1.t;
+ period : int;
+ pubkey : string;
+ privkey : string;
+ signature : string;
+ }
+
+ let msg = declare_message "HEARTBEAT"
+ (fun b m ->
+ LittleEndian.buf_int64 b m.time;
+ AnyEndian.buf_sha1 b m.server;
+ AnyEndian.buf_int8 b m.period;
+ LittleEndian.buf_string31 b m.pubkey;
+ LittleEndian.buf_string31 b m.privkey;
+ LittleEndian.buf_string31 b m.signature;
+ )
+ (fun s pos ->
+ let time, pos = LittleEndian.get_int64 s pos in
+ let server,pos = AnyEndian.get_sha1_pos s pos in
+ let period = AnyEndian.get_uint8 s pos in let pos = pos + 1 in
+ let (pubkey, privkey, signature) =
+ try
+ let pubkey, pos = LittleEndian.get_string31 s pos in
+ let privkey, pos = LittleEndian.get_string31 s pos in
+ let signature, _pos = LittleEndian.get_string31 s pos in
+ (pubkey, privkey, signature)
+ with _ ->
+ let payload, _pos = LittleEndian.get_string31 s pos in
+ "","", payload
+ in
+ { time = time;
+ server = server;
+ period = period;
+ pubkey = pubkey;
+ privkey = privkey;
+ signature = signature;
+ }
+ )
+ (fun msg ->
+ Printf.sprintf "HEARTBEAT {\n\ttime = %Ld\n\tserver = %s\n\tperiod = %d\n }\n"
+ msg.time (Sha1.to_string msg.server) msg.period)
+
+ end
+
+module AvailabilityMsg = struct
+
+ type msg = {
+ time : int64;
+ availability : string;
+ signature : string;
+ }
+
+
+ let msg = declare_message "AVAILABILITY"
+ (fun b m ->
+ LittleEndian.buf_int64 b m.time;
+ LittleEndian.buf_string31 b m.availability;
+ LittleEndian.buf_string31 b m.signature;
+ )
+ (fun s pos ->
+ let time, pos = LittleEndian.get_int64 s pos in
+ let availability, pos = LittleEndian.get_string31 s pos in
+ let signature, _pos = LittleEndian.get_string31 s pos in
+ { time = time;
+ availability = availability;
+ signature = signature }
+ )
+ (fun msg ->
+ Printf.sprintf "AVAILABILITY {\n\ttime = %Ld\n }\n"
+ msg.time)
+ end
+
+module ChallengeMsg = struct
+
+ type msg = {
+ time : int64;
+ nonce : string;
+ }
+
+ let msg = declare_message "CHALLENGE"
+ (fun b m ->
+ LittleEndian.buf_int64 b m.time;
+ LittleEndian.buf_string31 b m.nonce;
+ )
+ (fun s pos ->
+ let time, pos = LittleEndian.get_int64 s pos in
+ let nonce, _pos = LittleEndian.get_string31 s pos in
+ { time = time;
+ nonce = nonce;
+ }
+ )
+ (fun msg ->
+ Printf.sprintf "CHALLENGE {\n\ttime = %Ld\n }\n"
+ msg.time)
+ end
+
+module ProofMsg = struct
+
+ type msg = {
+ time : int64;
+ nonce : string;
+ pubkey : string;
+ signature : string;
+ reply : string;
+ }
+
+ let msg = declare_message "PROOF"
+ (fun b m ->
+ LittleEndian.buf_int64 b m.time;
+ LittleEndian.buf_string31 b m.nonce;
+ LittleEndian.buf_string31 b m.pubkey;
+ LittleEndian.buf_string31 b m.signature;
+ LittleEndian.buf_string31 b m.reply;
+ )
+ (fun s pos ->
+ let time, pos = LittleEndian.get_int64 s pos in
+ let nonce, pos = LittleEndian.get_string31 s pos in
+ let pubkey, pos = LittleEndian.get_string31 s pos in
+ let signature, pos = LittleEndian.get_string31 s pos in
+ let reply, _pos = LittleEndian.get_string31 s pos in
+ { time = time;
+ nonce = nonce;
+ pubkey = pubkey;
+ signature = signature;
+ reply = reply;
+ }
+ )
+ (fun msg ->
+ Printf.sprintf "PROOF {\n\ttime = %Ld\n }\n"
+ msg.time)
+ end
+
+
+module ListDirectoryMsg = struct
+
+ type msg = {
+ directory : string;
+ }
+
+ let msg = declare_message "LIST_DIRECTORY"
+ (fun b m ->
+ LittleEndian.buf_string31 b m.directory)
+ (fun s pos ->
+ let directory, _pos = LittleEndian.get_string31 s pos in
+ { directory = directory }
+ )
+ (fun msg ->
+ Printf.sprintf "LIST_DIRECTORY {\n\tdirectory = %s\n }\n"
+ msg.directory)
+
+ end
+
+module ListDirectoryReplyMsg = struct
+
+ type msg = {
+ directory : string;
+ files : (string * int64) list;
+ }
+
+ let msg = declare_message "LIST_DIRECTORY_REPLY"
+ (fun b m ->
+ LittleEndian.buf_string31 b m.directory;
+ LittleEndian.buf_list16 (fun b (filename, sizeL) ->
+ LittleEndian.buf_string31 b filename;
+ LittleEndian.buf_int64 b sizeL
+ ) b m.files
+ )
+ (fun s pos ->
+ let directory, pos = LittleEndian.get_string31 s pos in
+ let files, pos = LittleEndian.get_list16 (fun s pos ->
+ let filename, pos = LittleEndian.get_string31 s pos in
+ let sizeL, pos = LittleEndian.get_int64 s pos in
+ (filename, sizeL), pos) s pos in
+ { directory = directory;
+ files = files }
+ )
+ (fun msg ->
+ let b = Buffer.create 1000 in
+ Printf.bprintf b "LIST_DIRECTORY_REPLY {\n\tdirectory = %s\nfiles = [\n"
+ msg.directory;
+ List.iter (fun (file,size) ->
+ Printf.bprintf b "\t\t%s : %Ld\n" file size
+ ) msg.files;
+ Printf.bprintf b "]\n }\n";
+ Buffer.contents b)
+
+ end
+
+module BlockMsg = struct
+
+ type msg = {
+ filename : string;
+ file_pos : int64;
+ file_content : string;
+ }
+
+ let msg = declare_message "BLOCK"
+ (fun b m ->
+ LittleEndian.buf_string31 b m.filename;
+ LittleEndian.buf_int64 b m.file_pos;
+ LittleEndian.buf_string31 b m.file_content;
+ )
+ (fun s pos ->
+ let filename, pos = LittleEndian.get_string31 s pos in
+ let file_pos, pos = LittleEndian.get_int64 s pos in
+ let file_content, pos = LittleEndian.get_string31 s pos in
+
+ { filename = filename;
+ file_pos = file_pos;
+ file_content = file_content;
+ }
+ )
+ (fun msg ->
+ Printf.sprintf "BLOCK {\n\tfilename = %s\nfile_pos = %Ld\n\tfile_content_size = %d }\n"
+ msg.filename msg.file_pos (String.length msg.file_content))
+
+ end
+
+module BlockReplyMsg = struct
+
+ type msg = {
+ filename : string;
+ file_pos : int64;
+ file_content_size : int;
+ }
+
+
+ let msg = declare_message "BLOCK_REPLY"
+ (fun b m ->
+ LittleEndian.buf_string31 b m.filename;
+ LittleEndian.buf_int64 b m.file_pos;
+ LittleEndian.buf_int31 b m.file_content_size;
+ )
+ (fun s pos ->
+ let filename, pos = LittleEndian.get_string31 s pos in
+ let file_pos, pos = LittleEndian.get_int64 s pos in
+ let file_content_size, pos = LittleEndian.get_int31 s pos in
+ { filename = filename;
+ file_pos = file_pos;
+ file_content_size = file_content_size;
+ }
+ )
+ (fun msg ->
+ Printf.sprintf "BLOCK_REPLY {\n\tfilename = %s\nfile_pos = %Ld\n\tfile_size = %d\n }\n"
+ msg.filename msg.file_pos msg.file_content_size)
+
+ end \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/pMOptions.ml b/sources/fabrice/pacemaker/pMOptions.ml
new file mode 100644
index 0000000..1babbd5
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMOptions.ml
@@ -0,0 +1,140 @@
+open SafeCaml
+open Pervasives
+
+open Checksum
+open Sets
+open Options
+
+open NetP2P
+
+open PMTypes
+open PMConst
+open PMNetwork
+
+
+let binary_name = Sys.argv.(0)
+let _ =
+ if not (String.starts_with binary_name "/home/irisa_pacemaker/pacemaker/bin/") then
+ begin
+ lprintf "Bad binary location";
+ exit 2
+ end
+
+let binary_filename = Filename.of_string binary_name
+let binary_basename = Filename.basename binary_filename
+
+
+let filename = Filename.add_basename config_dir (Printf.sprintf "%s.ini" binary_basename)
+let config = Options.create_options_file filename
+let options = Options.file_section config ["Options"] ""
+
+let must_save_options = ref false
+
+let save_options () =
+ if !must_save_options then begin
+ Options.save_with_help config;
+ must_save_options := false
+ end
+
+let must_save_options () = must_save_options := true
+
+let master = define_option options ["master"] ""
+ (tuple3_option
+ (Sha1.option, Ip.option, int_option))
+ (Sha1.of_string "F56I34NIUJEXAIMPLEHX4J3SQXBWYIMS",
+ Ip.of_string "195.83.212.149", 7008)
+
+
+let version = define_option options ["version"] ""
+ int_option 0
+
+let servers = define_option options ["server"] ""
+ (list_option (tuple3_option
+ (Sha1.option, Ip.option, int_option))) [
+
+(* peerolyse *)
+ (Sha1.of_string "KLQCLYRUP3NMDOH3LNAEPX3L4QBGA6HQ",
+ Ip.of_string "195.83.212.155", 7001);
+
+(* peerformance *)
+ (Sha1.of_string "V7T52VJ7WIQWP4T5UXH2E7XLUJXDJ6C7",
+ Ip.of_string "195.83.212.149", 7001);
+
+ ]
+
+let observed = define_option options ["observed"] ""
+ (list_option (tuple3_option
+ (Sha1.option, Ip.option, int_option))) []
+
+let observers = define_option options ["observers"] ""
+ (list_option (tuple3_option
+ (Sha1.option, Ip.option, int_option))) []
+
+
+let old_binaries = define_option options ["old_binaries"] ""
+ (list_option (tuple2_option (string_option, int64_option))) []
+
+let ndegree = define_option options ["ndegree"] ""
+ int_option 5
+
+let min_port = define_option options ["min_port"] ""
+ int_option 7000
+
+let my_port = define_option options ["port"] ""
+ int_option 0
+
+let verbosity = define_option options ["verbosity"] ""
+ string_option "PPP"
+
+let uid = define_option options ["uid"] ""
+ Sha1.option (Sha1.random ())
+
+let auto_update = define_option options ["auto_update"] ""
+ bool_option true
+
+let run_as_server = define_option options ["run_as_server"] ""
+ bool_option false
+
+let run_as_master = define_option options ["run_as_master"] ""
+ bool_option false
+
+
+let best_binary_hash = define_option options ["best_binary_hash"] ""
+ Sha1.option Sha1.null
+
+let best_binary_time = define_option options ["best_binary_time"] ""
+ int64_option 0L
+
+
+
+
+
+let load () =
+ try
+ Options.load config
+ with e ->
+ Printf.fprintf stderr "Exception %s while loading option file\n%!"
+ (Printexc2.to_string e) ;
+ exit 2
+
+let _ =
+ if Sys.file_exists filename then load () else must_save_options ();
+
+ if !!version = 0 then begin
+
+ let x =
+ (Sha1.of_string "V7T52VJ7WIQWP4T5UXH2E7XLUJXDJ6C7",
+ Ip.of_string "195.83.212.149", 7001) in
+ if not (List.mem x !!servers) then
+ servers =:= x :: !!servers;
+
+ version =:= 1;
+ must_save_options ()
+ end;
+
+ if !!run_as_server && !!ndegree = 5 then begin
+ must_save_options ();
+ ndegree =:= 10
+ end
+
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/pMTypes.ml b/sources/fabrice/pacemaker/pMTypes.ml
new file mode 100644
index 0000000..a483714
--- /dev/null
+++ b/sources/fabrice/pacemaker/pMTypes.ml
@@ -0,0 +1,67 @@
+open SafeCaml
+open Pervasives
+
+open Sets
+open Checksum
+open NetP2P
+
+
+type peer_status =
+ PEER_CANDIDATE of int
+| PEER_PARENT of int
+| PEER_CHILD of int
+| PEER_UNKNOWN
+| PEER_MASTER
+
+(*
+type peer_type =
+ PEER_SERVER
+| PEER_MASTER
+| PEER_NORMAL
+ *)
+
+type sync_dir = {
+ mutable directory : Filename.t;
+ mutable old_files : int64 StringMap.t;
+ mutable new_files : (string * int64) list;
+ mutable data_queued : int;
+ }
+
+type peer_info = {
+ (* These fields are for NetP2P *)
+ mutable peer_conn : (peer_info, TcpSocket.t) connection option;
+ mutable peer_id : Sha1.t;
+ mutable peer_addr : (Ip.t * int) option;
+
+(* These fields are for our personal use *)
+(* mutable peer_type : peer_type; *)
+
+(* What can we do with this peer *)
+ mutable peer_status : peer_status;
+
+ mutable peer_candidate : int;
+(* never connect to the same peer in less than 10 minutes *)
+ mutable peer_last_try : int;
+ mutable peer_last_connected : int;
+
+(* minimal distance to server *)
+ mutable peer_distance : int;
+ mutable peer_server : Sha1.t;
+
+ mutable peer_sync : sync_dir option;
+ }
+
+let string_of_peer p =
+ (Sha1.to_string p.peer_id) ^ (match p.peer_addr with
+ None -> ""
+ | Some (ip,port) ->
+ Printf.sprintf "(%s:%d)" (Ip.to_string ip) port)
+
+let string_of_status s =
+ match s with
+ PEER_CANDIDATE int -> Printf.sprintf "PEER_CANDIDATE %d" int
+ | PEER_PARENT int -> Printf.sprintf "PEER_PARENT %d" int
+ | PEER_CHILD int -> Printf.sprintf "PEER_CHILD %d" int
+ | PEER_UNKNOWN -> "PEER_UNKNOWN"
+ | PEER_MASTER -> "PEER_MASTER"
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/pM_pl_plot.ml b/sources/fabrice/pacemaker/pM_pl_plot.ml
new file mode 100644
index 0000000..b1e1e4a
--- /dev/null
+++ b/sources/fabrice/pacemaker/pM_pl_plot.ml
@@ -0,0 +1,442 @@
+open SafeCaml
+open Pervasives
+
+open Int64ops
+open Checksum
+open Sets
+
+type peer = {
+ peer_id : Sha1.t;
+ peer_ups : int array;
+ peer_heartbeats : (int * int64 *int * int) array;
+ peer_pongs : (int * int * string * string) ref Sha1Map.t;
+ }
+
+type observed = {
+ o_id : Sha1.t;
+ bitmap : string;
+ mutable observers : (Sha1.t * string) list;
+ }
+
+let peers_by_id = ref Sha1Map.empty
+let server1 = "V7T52VJ7WIQWP4T5UXH2E7XLUJXDJ6C7"
+let server2 = "KLQCLYRUP3NMDOH3LNAEPX3L4QBGA6HQ"
+let master = "F56I34NIUJEXAIMPLEHX4J3SQXBWYIMS"
+
+
+let min_timeL = 1223358964L
+let min_time_abs = Int64.to_int (min_timeL // 60L) - 240
+let max_time_abs = min_time_abs + 1440 + 480
+
+let min_timeM = Int64.to_int (min_timeL // 60L)
+let max_timeM = min_timeM + 1440
+let time_rangeM = 1442
+
+let server1_id = Sha1.of_string server1
+let server2_id = Sha1.of_string server2
+let master_id = Sha1.of_string master
+let starters = [| []; [] |]
+
+let int_of_server s =
+ if s = server1 then 0 else
+ if s = server2 then 1 else
+ -1
+
+module Sha1 = struct
+
+ let set = ref Sha1Map.empty
+
+ let of_string s =
+ let s = Sha1.of_string s in
+ try
+ Sha1Map.find s !set
+ with Not_found ->
+ set := Sha1Map.add s s !set;
+ s
+
+ let to_string s = Sha1.to_string s
+
+ end
+
+let sha1_len = String.length "55SQEF3S5S6UH7D2FUSB24ORVTELVN32"
+
+let current_directory = Filename.of_string "."
+
+let peers = List.sort compare (Unix.list_directory current_directory)
+
+let min_time = ref max_int
+let max_time = ref 0
+
+let logs_iter f peer_id =
+ let dir = Filename.add_basename current_directory
+ (Sha1.to_string peer_id) in
+ let logs = List.sort compare (Unix.list_directory dir) in
+ List.iter (fun log ->
+ let s = File.to_string (Filename.add_basename dir log) in
+ let lines = String.split s '\n' in
+ List.iter (fun line ->
+ f (String2.split_simplify line ' ')
+ ) lines
+ ) logs
+
+let analyse_peer_logs peer_id_s =
+ let peer_id = Sha1.of_string peer_id_s in
+ if peer_id <> master_id then
+ let ups = ref [] in
+ let heartbeats = ref [] in
+ let pongs = ref Sha1Map.empty in
+(* let pongs = ref [] in
+ let pings = ref [] in *)
+ logs_iter (fun tokens ->
+ try
+ match tokens with
+ [] -> ()
+ | timeS :: "up" :: args ->
+ let timeL = Int64.of_string timeS in
+ let time = Int64.to_int (Int64.div timeL 60L) in
+ if time < !min_time then min_time := time
+ else if time > !max_time then max_time := time;
+ if time >= min_time_abs && time <= max_time_abs then
+ ups := time :: !ups
+ | [ timeS ; "heartbeat" ; server ; ptimeS ; period ] ->
+ let timeL = Int64.of_string timeS in
+ let time = Int64.to_int (Int64.div timeL 60L) in
+ let ptimeL = Int64.of_string ptimeS in
+ let period = int_of_string period in
+ let server = int_of_server server in
+ if time >= min_time_abs && time <= max_time_abs then
+ heartbeats := (time, ptimeL, server,period) :: !heartbeats
+ | timeS :: "started" :: _ ->
+ let server = int_of_server peer_id_s in
+ if server >= 0 then
+ let timeL = Int64.of_string timeS in
+ starters.(server) <- timeL :: starters.(server)
+ | [ timeS ; "udpr" ; "PONG" ; hash ; timeP ] ->
+ let timeL = Int64.of_string timeS in
+ let timePL = Int64.of_string timeP in
+ let delay = Int64.to_int (timeL -- timePL) in
+ let p2 = Sha1.of_string hash in
+ let time = Int64.to_int (Int64.div timeL 60L) in
+ if time >= min_timeM && time <= max_timeM then
+ let time = time - min_timeM in
+ let x = try
+ Sha1Map.find p2 !pongs
+ with Not_found ->
+ let x = ref (0,0,
+ String.make time_rangeM '0',
+ String.make time_rangeM '0') in
+ pongs := Sha1Map.add p2 x !pongs;
+ x
+ in
+ let (xx,nn,pings,pongs) = !x in
+ pongs.[time] <- '1';
+ x := (xx+delay, nn+1,pings,pongs)
+
+ | [ timeS ; "udps" ; "PING" ; hash ] ->
+ let timeL = Int64.of_string timeS in
+ let p2 = Sha1.of_string hash in
+ let time = Int64.to_int (Int64.div timeL 60L) in
+ if time >= min_timeM && time <= max_timeM then
+ let time = time - min_timeM in
+ let x = try
+ Sha1Map.find p2 !pongs
+ with Not_found ->
+ let x = ref (0,0,
+ String.make time_rangeM '0',
+ String.make time_rangeM '0') in
+ pongs := Sha1Map.add p2 x !pongs;
+ x
+ in
+ let (xx,nn,pings, pongs) = !x in
+ pings.[time] <- '1'
+
+ | _ -> ()
+ with e ->
+ Printf.printf "Exception %s while reading log\n"
+ (Printexc2.to_string e)
+ ) peer_id;
+
+ let p = {
+ peer_id = peer_id;
+ peer_ups = Array.of_list !ups;
+ peer_heartbeats = Array.of_list !heartbeats;
+ peer_pongs = !pongs;
+ } in
+
+ if peer_id_s <> server1 && peer_id_s <> server2 then
+ peers_by_id := Sha1Map.add peer_id p !peers_by_id
+
+
+let _ =
+
+ let cache = Filename.of_string "cache.dat" in
+ if Sys.file_exists cache then
+ let ic = OLD.open_in "cache.dat" in
+ let (a,b,c,d,e) = input_value ic in
+ OLD.close_in ic;
+ peers_by_id := a;
+ min_time := b;
+ max_time := c;
+ starters.(0) <- d;
+ starters.(1) <- e;
+ else
+ let npeers = ref 0 in
+ List.iter (fun s ->
+ if String.length s = sha1_len then begin
+ incr npeers;
+ Printf.printf "Processing peer %s (%d)\n%!" s !npeers;
+ analyse_peer_logs s;
+ end
+ ) peers;
+ for i = 0 to 1 do
+ starters.(i) <- List.rev (List.sort compare starters.(i))
+ done;
+ Printf.printf "Saving cache\n%!";
+ let oc = OLD.open_out "cache.dat" in
+ output_value oc (!peers_by_id, !min_time, !max_time, starters.(0), starters.(1));
+ OLD.close_out oc
+
+let _ =
+ let _min_time = !min_time in
+ let _max_time = !max_time in
+
+ let min_time = Int64.to_int (min_timeL // 60L) in
+ let max_time = min_time + 1440 in
+
+(* let min_time = min_time + 4 * 1440 in *)
+ let time_range = max_time - min_time + 2 in
+
+ Printf.printf "Min time : %d\n%!" min_time;
+ Printf.printf "Max time : %d (%d)\n%!" max_time ((max_time - min_time) / 1440);
+ let oc = OLD.open_out "trace.txt" in
+
+ let count_bitmap bitmap =
+ let count = ref 0 in
+ for i = 0 to String.length bitmap-1 do
+ if bitmap.[i] = '1' then incr count
+ done;
+ !count
+ in
+
+ let lines = Array.create 16 [] in
+ let bitmaps = ref Sha1Map.empty in
+ Printf.printf "Y\n%!";
+ Sha1Map.iter (fun _ p ->
+ Printf.printf "Peer %s\n%!" (Sha1.to_string p.peer_id);
+
+ let bitmap = String.make time_range '-' in
+ Array.iter (fun time ->
+ if time - min_time >= 0 && time < max_time then
+ if bitmap.[time - min_time] = '1' then
+ bitmap.[time - min_time + 1 ] <- '1'
+ else
+ bitmap.[time - min_time] <- '1'
+ ) p.peer_ups;
+
+ bitmaps := Sha1Map.add p.peer_id bitmap !bitmaps;
+ let avail = count_bitmap bitmap in
+
+ if avail > 0 then
+ let _ = () in
+ Printf.fprintf oc "%s" (Sha1.to_string p.peer_id);
+ Printf.fprintf oc "\t%d" avail;
+
+ let rec find_starter list ptimeL period =
+ match list with
+ [] -> ptimeL
+ | startL :: tail ->
+ if startL <= ptimeL then
+
+ let periodL = (Int64.of_int period) ** 60L in
+ startL ++ ((ptimeL -- startL) // periodL) ** periodL
+
+ else find_starter tail ptimeL period
+ in
+
+ let measures = ref 0 in
+ List.iter (fun period ->
+
+ for server = 0 to 1 do
+(* Printf.fprintf oc "{%d,%d} = " server period; *)
+ let bitmap = String.make time_range '-' in
+ Array.iter (fun (_, ptimeL, ss, pp) ->
+ if ss = server && pp = period then
+ let ptimeL = find_starter starters.(server) ptimeL period in
+ let ptime = Int64.to_int (Int64.div ptimeL 60L) in
+ let time = (ptime - min_time) / period in
+(* Printf.fprintf oc "[%d <- %Ld,%d]" ptime ptimeL time; *)
+ let time = time * period in
+ for x = 0 to period - 1 do
+ if time + x >= 0 && time + x < time_range then
+ if bitmap.[time + x] = '1' then
+
+(* For each server, we need to find the starting times (log "started"), so
+that we can find, for a given heartbeat the period of time to which it is
+referring... *)
+(* Printf.fprintf oc " XXX " *) ()
+ else
+ bitmap.[time + x] <- '1'
+ done
+ ) p.peer_heartbeats;
+ let eval_avail = count_bitmap bitmap in
+ Printf.fprintf oc "\t%d %.2f" eval_avail
+ ((float_of_int (abs (avail - eval_avail)))/.
+ (float_of_int avail))
+ ;
+
+ let abs_error = float_of_int (abs (avail - eval_avail)) in
+ let rel_error = abs_error /. float_of_int avail in
+ Printf.printf "measures: %d\n%!" !measures;
+ lines.(!measures) <- (abs_error /. 1440.) :: lines.(!measures);
+ incr measures;
+ lines.(!measures) <- rel_error :: lines.(!measures);
+ incr measures;
+
+ done;
+
+ ) [10; 30; 60; 120];
+
+ Printf.fprintf oc "\n";
+ ) !peers_by_id;
+
+
+ OLD.close_out oc;
+
+ let lines = Array.map (fun list ->
+ Array.of_list (List.sort compare list)) lines in
+ let oc = OLD.open_out "error.txt" in
+ for i = 0 to Array.length lines.(0) - 1 do
+ for j = 0 to Array.length lines - 1 do
+ Printf.fprintf oc "%f " lines.(j).(i);
+ done;
+ Printf.fprintf oc "\n";
+ done;
+ OLD.close_out oc;
+
+ let merge_bitmaps b1 b2 =
+ let b1 = String.copy b1 in
+ for i = 0 to String.length b1 - 1 do
+ if b2.[i] <> '1' then b1.[i] <- '0'
+ done;
+ b1
+ in
+
+ let observed = ref Sha1Map.empty in
+
+ Printf.printf "pongs now\n%!";
+ let oc2 = OLD.open_out "delays.txt" in
+ Sha1Map.iter (fun _ p ->
+ let p1 = p.peer_id in
+ Printf.fprintf oc2 "%s:\n" (Sha1.to_string p1);
+ Sha1Map.iter (fun p2 x ->
+ if p1 <> p2 then
+ let (xx,nn,pings,pongs) = !x in
+ Printf.fprintf oc2 "\t%s %d\n" (Sha1.to_string p2) (
+ if nn > 0 then xx/nn else 0);
+ let bitmap = try
+ Sha1Map.find p2 !bitmaps
+ with _ -> "---" in
+ Printf.fprintf oc2 "\t\t%s\n" bitmap;
+ Printf.fprintf oc2 "\t\t%s\n" pings;
+ Printf.fprintf oc2 "\t\t%s\n" pongs;
+
+ let bitmap = String.sub bitmap 1 1440 in
+ let pings = String.sub pings 1 1440 in
+ let pongs = String.sub pongs 1 1440 in
+
+ let availability = count_bitmap bitmap in
+ let ping_avail = merge_bitmaps bitmap pings in
+ let ping_avail = count_bitmap ping_avail in
+ begin
+ try
+ let o = Sha1Map.find p2 !observed in
+ o.observers <- (p1, pongs) :: o.observers
+ with Not_found ->
+ observed := Sha1Map.add p2
+ {
+ o_id = p2;
+ bitmap = bitmap;
+ observers = [p1 ,pongs] } !observed
+ end;
+ let pongs = count_bitmap pongs in
+ if ping_avail > pongs then
+ Printf.fprintf oc2 "\t\t\tNO REPLIES: %d > %d \n" ping_avail pongs;
+
+ if availability > 0 then
+(* min: there might be more pongs that pings ? *)
+ let pongs = float_of_int (min availability pongs) in
+ let availability = float_of_int availability in
+
+
+ let availability = availability /. 1440. in
+ let pongs = (min 1440. pongs) /. 1440. in
+
+ Printf.fprintf oc2 "%f %f ERROR\n"
+ (abs_float (availability -. pongs))
+ (abs_float (availability -. pongs) /. availability);
+ ) p.peer_pongs;
+ Printf.fprintf oc2 "\n"
+ ) !peers_by_id;
+ OLD.close_out oc2;
+
+ let oc = OLD.open_out "pings_errors.txt" in
+ Sha1Map.iter (fun p1 o ->
+
+ let availability = count_bitmap o.bitmap in
+ if availability > 0 then
+ let availabilityF = float_of_int availability in
+
+ let t = Array.of_list o.observers in
+
+(* shuffle it *)
+ let len = Array.length t in
+ for i = 0 to 100 do
+ let x1 = Random.int len in
+ let x2 = Random.int len in
+ let x = t.(x1) in
+ t.(x1) <- t.(x2);
+ t.(x2) <- x;
+ done;
+
+ let observation = String.make 1440 '0' in
+ for i = 1 to 25 do
+
+ begin
+ if i < len then
+ let (p2,b) = t.(i) in
+ for j = 0 to 1440 - 1 do
+ if b.[j] = '1' then observation.[j] <- '1'
+ done
+ end;
+ if i mod 5 = 0 then
+ let observed = count_bitmap observation in
+ let error = abs (observed - availability) in
+ let errorF = float_of_int error /. 1440. in
+ Printf.fprintf oc "%f %f " errorF (errorF /. availabilityF)
+ done;
+ Printf.fprintf oc "\n"
+ ) !observed;
+
+ OLD.close_out oc;
+
+
+ let nmessages = ref 0 in
+ let f tokens =
+ match tokens with
+ timeS :: "recv" :: "ASK_PARENT" :: _ ->
+ let timeL = Int64.of_string timeS in
+ let time = Int64.to_int (Int64.div timeL 60L) in
+ if time >= min_time && time < max_time then
+ incr nmessages
+ | _ -> ()
+ in
+ logs_iter f server1_id;
+ Printf.printf "ASK_PARENT server 1: %d (%.04f)\n"
+ !nmessages (float_of_int !nmessages /. float_of_int time_range);
+ nmessages := 0;
+ logs_iter f server2_id;
+ Printf.printf "ASK_PARENT server 2: %d (%.04f)\n"
+ !nmessages (float_of_int !nmessages /. float_of_int time_range);
+ ()
+
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/pingtrace.ml b/sources/fabrice/pacemaker/pingtrace.ml
new file mode 100644
index 0000000..0460994
--- /dev/null
+++ b/sources/fabrice/pacemaker/pingtrace.ml
@@ -0,0 +1,147 @@
+open SimulTrace
+open SimulTypes
+open SimulGraphes
+
+let day = 60 * 24
+
+let degree = ref 5
+let anon_args = ref [ Sys.argv.(0) ]
+let ndays = ref 0
+let subdir = ref None
+
+let _ =
+ Arg.parse [
+ "-subdir", Arg.String (fun s ->
+ subdir := Some s), "<subdir> : set subdir for data files";
+ "-ndays", Arg.Int ((:=) ndays), " <n> : number of days";
+ "-dist", Arg.Set print_distribution, " : print distribution";
+ "-degree", Arg.Int ((:=)degree), " <n> : peer degree";
+ ]
+ (fun t -> anon_args := t :: !anon_args) ""
+
+
+let subdir =
+ match !subdir with
+ None -> failwith "You must specify a subdirectory for data files"
+ | Some dir ->
+ Unix2.safe_mkdir (Filename2.of_string dir);
+ dir
+
+let degree = !degree
+
+
+let argv = Array.of_list (List.rev !anon_args)
+let trace = argv.(1)
+
+
+let _ =
+ if trace = "" then
+ failwith "You must at least specify the name of the trace file";
+ Random.self_init ()
+
+let peers, nrounds, do_round = trace_read trace
+let nrounds =
+ if !ndays <> 0 then
+ day * !ndays
+ else nrounds
+
+let npeers = Array.length peers
+
+type peer2 = {
+ mutable observers : int list;
+
+ mutable availabilities : int array;
+ mutable ping : bool;
+ }
+
+
+let rec find_observer i p =
+ let x = Random.int npeers in
+ if x = i || List.mem x p.observers then find_observer i p
+ else
+ p.observers <- x :: p.observers
+
+let nrounds =
+ if Array.length argv = 3 then
+ day * int_of_string argv.(2)
+ else nrounds
+
+let _ =
+
+ let peers2 = Array.init npeers (fun i ->
+ let p = {
+ observers = [];
+ availabilities = [| 0; 0 |];
+ ping = false;
+ } in
+
+ for x = 1 to degree do
+ find_observer i p
+ done;
+
+ p)
+ in
+ let rec iter_observers p list =
+ match list with
+ [] -> ()
+ | o :: tail ->
+ let po = peers.(o) in
+ if po.state = ON then
+ p.availabilities.(1) <- p.availabilities.(1) + 1
+ else
+ iter_observers p tail
+ in
+
+ for round = 0 to nrounds - 1 do
+ do_round round;
+
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if p.state = ON then begin
+ p2.availabilities.(0) <- p2.availabilities.(0) + 1;
+ iter_observers p2 p2.observers
+ end
+ done
+ done;
+
+ let avail_error =
+ Printf.printf "availability...\n%!";
+ let avail = Array.create npeers (0,0,false) in
+ for i = 0 to npeers - 1 do
+ let a = (
+ peers2.(i).availabilities.(0),
+ peers2.(i).availabilities.(1),
+ false) in
+ avail.(i) <- a
+ done;
+ Array.sort compare avail;
+ let nrounds = float_of_int nrounds in
+
+ let avail_error = ref [] in
+ let oc = open_out (
+ Printf.sprintf "%s/ping_availability_%d.txt" subdir degree) in
+ for i = 0 to npeers - 1 do
+ let (a0,a1,selfish) = avail.(i) in
+ let a0 = float_of_int a0 in
+ let a1 = float_of_int a1 in
+ let a = (a0,a1,selfish) in
+ avail_error := (abs_float (a0 -. a1) /. nrounds) :: !avail_error;
+ let print oc (a0,a1,_) =
+
+ output_string oc (Printf.sprintf "%d " i);
+ output_string oc (Printf.sprintf "%.3f " (a0 /. nrounds));
+ output_string oc (Printf.sprintf "%.3f " (a1 /. nrounds));
+ output_string oc "\n"
+ in
+ print oc a
+ done;
+ close_out oc;
+ !avail_error
+
+ in
+ cdf_of_list string_of_float
+ (Printf.sprintf "%s/ping_error_avail_%d" subdir degree) avail_error
+ "set yrange [0:0.1]" "CDF of peers" "Error in measured availability"
+ " title 'error'";
+ ()
diff --git a/sources/fabrice/pacemaker/userand.ml b/sources/fabrice/pacemaker/userand.ml
new file mode 100644
index 0000000..c4e8958
--- /dev/null
+++ b/sources/fabrice/pacemaker/userand.ml
@@ -0,0 +1,7 @@
+open BigEndian
+
+let random filename =
+ let ic = open_in filename in
+ let s = String.create (4*4096) in
+
+ \ No newline at end of file
diff --git a/sources/fabrice/pacemaker/usetrace.ml b/sources/fabrice/pacemaker/usetrace.ml
new file mode 100644
index 0000000..fa88581
--- /dev/null
+++ b/sources/fabrice/pacemaker/usetrace.ml
@@ -0,0 +1,783 @@
+open SafeCaml
+open Pervasives
+
+open Sets
+open SimulTrace
+open SimulTypes
+open SimulGraphes
+
+let _ =
+ Printf.printf "VERSION 2.2\n%!"
+
+let day = 60 * 24
+(* Compute peers_per_round *)
+
+type parent_state =
+| AskRoot
+| Parent of int
+| AskPeer of int
+
+type peer_com =
+ Idle of int
+| Ticket of int
+| ReceivingTicket of int
+
+module Bitmap : sig
+
+ type t
+
+ val create : unit -> t
+ val mem : t -> int -> bool
+ val add : t -> int -> unit
+
+ end = struct
+
+ type t = {
+ bitmap : string;
+ mutable min_time : int;
+ }
+
+ let size = 100
+
+ let create () = {
+ bitmap = String.make size '0';
+ min_time = 0;
+ }
+
+ let mem t pos =
+ if pos < t.min_time then true else
+ if pos < t.min_time + size then t.bitmap.[
+ pos mod size
+ ] = '1' else
+ false
+
+ let rec add t pos =
+ if pos < t.min_time then () else
+ if pos < t.min_time + size then
+ t.bitmap.[
+ pos mod size
+ ] <- '1' else
+ begin
+ t.min_time <- t.min_time + 1;
+ t.bitmap.[
+ (t.min_time + size - 1) mod size
+ ] <- '0';
+ add t pos
+ end
+
+ end
+
+
+let _ =
+ let t = Bitmap.create () in
+ Bitmap.add t 30;
+ assert (Bitmap.mem t 30);
+ assert (not (Bitmap.mem t 31));
+ Bitmap.add t 150;
+ assert (Bitmap.mem t 150);
+ assert (not (Bitmap.mem t 151));
+ assert (not (Bitmap.mem t 149));
+ assert (Bitmap.mem t 30);
+ assert (Bitmap.mem t 31);
+ ()
+
+type peer = {
+ mutable incoming : IntSet.t;
+ mutable tickets : IntSet.t;
+ bitmap : Bitmap.t;
+ mutable availabilities : int array;
+ parents : parent_state array;
+ children : ChildrenArray.t;
+ mutable rooted : (int list * int) option;
+ mutable distance : int;
+ mutable ncandidates : int;
+ mutable candidates : (int * peer * int) list;
+ mutable selfish : bool;
+ }
+
+let accuracy = ref 60
+let root_degree = ref 10
+let ndays = ref 0
+let degree = ref 5
+let nselfish = ref 0
+let subdir = ref None
+
+let anon_args = ref [ Sys.argv.(0) ]
+
+let _ =
+ Arg.parse [
+ "-subdir", Arg.String (fun s ->
+ subdir := Some s), "<subdir> : set subdir for data files";
+ "-ndays", Arg.Int ((:=) ndays), " <n> : number of days";
+ "-accuracy", Arg.Int ((:=) accuracy), " <n>: period between heartbeats";
+ "-root_degree", Arg.Int ((:=)root_degree), " <n> : root degree";
+ "-degree", Arg.Int ((:=)degree), " <n> : peer degree";
+ "-nselfish", Arg.Int ((:=)nselfish), " <n> : number of selfish nodes";
+ ]
+ (fun t -> anon_args := t :: !anon_args) ""
+
+let subdir =
+ match !subdir with
+ None -> failwith "You must specify a subdirectory for data files"
+ | Some dir ->
+ Unix2.safe_mkdir (Filename2.of_string dir);
+ dir
+let accuracy = !accuracy
+let root_degree = !root_degree
+let degree = !degree
+
+let argv = Array.of_list (List.rev !anon_args)
+let trace = if Array.length argv > 1 then argv.(1) else "trace.dat"
+
+
+let _ =
+ if trace = "" then failwith "You must at least specify the name of the trace file";
+ Random.self_init ()
+
+let peers, nrounds, do_round = trace_read trace
+
+let npeers = Array.length peers
+
+let nselfish = !nselfish * npeers / 100
+
+let nrounds =
+ if !ndays <> 0 then
+ day * !ndays
+ else nrounds
+
+let peers_per_round = Array.create nrounds 0
+let sessions = ref []
+let first_connection = ref []
+
+let peers2 = Array.init npeers (fun _ ->
+ {
+ incoming = IntSet.empty;
+ tickets = IntSet.empty;
+ bitmap = Bitmap.create ();
+ availabilities = [| 0; 0 |];
+ parents = Array.create degree AskRoot;
+ children = ChildrenArray.create degree;
+ rooted = None;
+ distance = 10000;
+ candidates = [];
+ ncandidates = 0;
+ selfish = false;
+ })
+
+let _ =
+ let rec iter () =
+ let n = Random.int npeers in
+ if peers2.(n).selfish then iter () else
+ peers2.(n).selfish <- true
+ in
+ for i = 1 to nselfish do
+ iter ()
+ done
+
+let cursor = ref 0
+let root_nchildren = ref 0
+let root_children = Array.create root_degree None
+
+
+let ask_peer i p p2 c x =
+(* Printf.printf "ask_peer: %d -> %d\n" i x; *)
+(* let px = peers.(x) in *)
+ let px2 = peers2.(x) in
+
+ if ChildrenArray.length px2.children < degree then
+ if (ChildrenArray.mem px2.children i) then
+ p2.parents.(c) <- AskRoot
+ else begin
+(* Printf.printf " Setting as parent\n"; *)
+ if px2.ncandidates < 100 then begin
+ px2.candidates <- (i, p2,c) :: px2.candidates;
+ px2.ncandidates <- px2.ncandidates + 1;
+ end
+
+ end else begin
+ let rec retry () =
+(* Printf.printf " Already full\n"; *)
+ let y = ChildrenArray.random px2.children in
+ if y = i then
+ retry ()
+ else
+ p2.parents.(c) <- AskPeer y
+ in
+ retry ()
+ end
+
+let max_distances = Array.create nrounds 0
+let ask_root_msgs = Array.create nrounds 0
+
+let ask_root round i p p2 =
+ ask_root_msgs.(round) <- ask_root_msgs.(round) + 1;
+ let n = min !root_nchildren degree in
+ let rec iter n list =
+ if n > 0 then begin
+ if !cursor >= !root_nchildren then cursor := 0;
+ let c = match root_children.(!cursor) with
+ None -> assert false
+ | Some c -> c
+ in
+
+ incr cursor;
+ iter (n-1) (c :: list)
+ end else list
+ in
+ let list = iter n [] in
+ if !root_nchildren < root_degree then
+ (-1) :: list
+ else list
+
+let ndistances = 10
+let mean_avail = Array.init (1+ndistances) (fun _ ->
+ Array.create nrounds 0)
+
+let root_ncandidates = ref 0
+let root_candidates = ref []
+let current_ticket = ref (-1)
+
+let print_graph round =
+
+ Printf.printf "graph %d...\n%!" round;
+ let filename = Filename.of_string (Printf.sprintf "%s/graph_%06d.dot" subdir round) in
+ let oc = open_out filename in
+ output_string oc "digraph \"Network\" {\n";
+
+ output_string oc " root [ label = \"Root\" ];\n";
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+ if p.state = ON then
+ output_string oc (Printf.sprintf
+(* " p%d [ label = \"%d (%d/%d)\" ];\n" i i p2.distance *)
+ " p%d [ label = \"%d/%d\" ];\n" i
+ p2.distance p.session );
+ done;
+
+ for k = 0 to !root_nchildren - 1 do
+ match root_children.(k) with
+ None -> assert false
+ | Some x ->
+ output_string oc (Printf.sprintf " root -> p%d\n" x)
+ done;
+
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if p.state = ON then
+ ChildrenArray.iteri (fun _ x ->
+ output_string oc (Printf.sprintf " p%d -> p%d\n" i x) )
+ p2.children
+ done;
+
+ output_string oc "}\n";
+ close_out oc
+
+
+
+let lost_tickets = Array.create (2+nrounds/accuracy) 0
+
+let _ =
+ let hour = ref 0 in
+ let next_ticket = ref (Random.int accuracy) in
+ let peers_on = Array.create npeers 0 in
+
+ for round = 0 to nrounds - 1 do
+
+ do_round round;
+
+ let rec iter_children i =
+ if i < !root_nchildren then
+ match root_children.(i) with
+ Some x ->
+ if peers.(x).state <> ON then begin
+ root_children.(i) <- root_children.(!root_nchildren-1);
+ root_nchildren := !root_nchildren - 1;
+ iter_children i
+ end else
+ iter_children (i+1)
+ | _ -> iter_children (i+1)
+ in
+ iter_children 0;
+
+ let npeers_on = ref 0 in
+ for i = 0 to npeers -1 do
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+
+
+ (*
+ Printf.printf "PEER: %d %d %d %d %d - %d %d %d\n"
+ (IntSet.cardinal p2.incoming)
+ (IntSet.cardinal p2.tickets)
+ (String.length p2.bitmap)
+ (Array.length p2.availabilities)
+ (Array.length p2.parents)
+
+ (match p2.rooted with
+ None -> 0 | Some (list,_) -> List.length list)
+ p2.ncandidates
+ (List.length p2.candidates);
+*)
+
+(*
+type peer = {
+ mutable incoming : IntSet.t;
+ mutable tickets : IntSet.t;
+ bitmap : string;
+ mutable availabilities : int array;
+ parents : parent_state array;
+ children : ChildrenArray.t;
+ mutable rooted : (int list * int) option;
+ mutable distance : int;
+ mutable ncandidates : int;
+ mutable candidates : (int * peer * int) list;
+ mutable selfish : bool;
+ }
+*)
+
+
+ if p.state = ON then begin
+ p2.availabilities.(0) <- p2.availabilities.(0) + 1;
+ p.session <- p.session + 1;
+ peers_on.(!npeers_on) <- i;
+ incr npeers_on;
+
+ if p2.distance < 10000 then p2.distance <- 1000;
+
+ for i = 0 to degree - 1 do
+ match p2.parents.(i) with
+ | Parent (-1) -> ()
+ | Parent x | AskPeer x ->
+ if peers.(x).state <> ON then
+ p2.parents.(i) <- AskRoot
+ | _ -> ()
+ done;
+
+ ChildrenArray.iteri (fun i x ->
+ if peers.(x).state <> ON then
+ ChildrenArray.remove p2.children i)
+ p2.children;
+
+ end else
+ if p.session > 0 then begin
+ sessions := p.session :: !sessions;
+ p.session <- 0;
+ for i = 0 to degree - 1 do
+ p2.parents.(i) <- AskRoot;
+ done;
+ p2.rooted <- None;
+ ChildrenArray.clear p2.children;
+ p2.distance <- 10000;
+ end;
+
+(* Clean the tables *)
+
+
+ done;
+ peers_per_round.(round) <- !npeers_on;
+
+(* Printf.printf "ROUND %d\n" round; *)
+ let to_do = Fifo.create () in
+ let max_distance = ref 0 in
+ for i = 0 to !root_nchildren - 1 do
+ match root_children.(i) with
+ None -> ()
+ | Some x ->
+(* Printf.printf "ROOT->%d\n" x; *)
+ if peers2.(x).distance = 10000 then
+ first_connection := peers.(x).session :: !first_connection;
+ peers2.(x).distance <- 1;
+ Fifo.put to_do x
+ done;
+
+ let rec iter () =
+ if not (Fifo.empty to_do) then
+ let x = Fifo.take to_do in
+ let p2 = peers2.(x) in
+(* Printf.printf "PEER %d\n" x; *)
+ let distance = p2.distance + 1 in
+ max_distance := max distance !max_distance;
+ ChildrenArray.iteri (fun _ x ->
+ let p2 = peers2.(x) in
+(* Printf.printf " CHILD %d\n" x; *)
+ if p2.distance > distance then begin
+(* Printf.printf " ->%d\n" x; *)
+ if peers2.(x).distance = 10000 then
+ first_connection := peers.(x).session :: !first_connection;
+
+ p2.distance <- distance;
+ Fifo.put to_do x
+ end
+ ) p2.children;
+ iter ()
+
+ in
+ iter ();
+ max_distances.(round) <- !max_distance;
+(* Printf.printf "Max distance: %d\n" !max_distance; *)
+
+
+ let _one_ticket = ref (-1) in
+ let _another_ticket = ref false in
+ for x = 0 to !npeers_on - 1 do
+ let i = peers_on.(x) in
+
+ let p2 = peers2.(i) in
+
+ let waiting_tickets = p2.tickets in
+ p2.tickets <- p2.incoming;
+ p2.incoming <- IntSet.empty;
+
+ IntSet.iter (fun hour ->
+ if not (Bitmap.mem p2.bitmap hour) then begin
+ Bitmap.add p2.bitmap hour;
+ p2.availabilities.(1) <- p2.availabilities.(1) + accuracy;
+ if p2.selfish then () else begin
+ ChildrenArray.iteri (fun _ x ->
+ if x <= i then begin
+ if not (Bitmap.mem peers2.(x).bitmap hour) then
+ peers2.(x).tickets <-
+ IntSet.add hour peers2.(x).tickets
+ end else begin
+ if not (Bitmap.mem peers2.(x).bitmap hour) then
+ peers2.(x).incoming <-
+ IntSet.add hour peers2.(x).incoming
+ end
+ ) p2.children
+ end
+ end
+ ) waiting_tickets;
+
+ (*
+ match p2.com with
+ Ticket hour ->
+ one_ticket := max hour !one_ticket;
+ p2.com <- Idle hour;
+
+
+ | ReceivingTicket hour ->
+ p2.com <- Ticket hour;
+ another_ticket := true
+| _ -> ()
+ *)
+ done;
+
+(*
+ if !one_ticket >= 0 && not !another_ticket then begin
+ for x = 0 to !npeers_on - 1 do
+ let i = peers_on.(x) in
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+ if round - p.session <= !current_ticket then
+ match p2.com with
+ Idle n when n < !one_ticket ->
+ lost_tickets.(!hour) <- lost_tickets.(!hour) + 1
+ | _ -> ()
+ done
+ end;
+*)
+
+(* Printf.printf ".%!"; *)
+(* Build the network:
+- We should use Bittorrent optimistic policy: we keep 4/5*degree slots
+for peers p with avail(p) > avail(me)/2, and 1/5*degree slots for other
+peers.
+- A first step would at least to sort connecting peers _before_ accepting
+one.
+*)
+
+ root_ncandidates := 0;
+ root_candidates := [];
+
+ for n = 1 to !npeers_on do
+ let x = Random.int !npeers_on in
+ let i = peers_on.(x) in
+ peers_on.(x) <- peers_on.(!npeers_on-1);
+ decr npeers_on;
+
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+ for c = 0 to degree-1 do
+ match p2.parents.(c) with
+ Parent _ -> ()
+ | AskRoot ->
+ let rec retry () =
+ match p2.rooted with
+ None ->
+ let list = ask_root round i p p2 in
+ p2.rooted <- Some (list, round);
+ retry ()
+ | Some ([], r) when r = round -> ()
+ | Some ([],_) ->
+ let list = ask_root round i p p2 in
+ p2.rooted <- Some (list, round);
+ retry ()
+ | Some (x :: tail,r) ->
+ p2.rooted <- Some (tail, r);
+
+ let found = ref (x = i) in
+ for k = 0 to degree - 1 do
+ match p2.parents.(k) with
+ AskPeer y when y = x -> found := true
+ | Parent y when y = x -> found := true
+ | _ -> ()
+ done;
+ if !found then
+ retry ()
+ else
+ if x = -1 then begin
+ let found = ref false in
+ List.iter (fun (ii,_,_) ->
+ if ii = i then found := true) !root_candidates;
+ if not !found then begin
+(* Printf.printf "adding %d\n" i; *)
+ if !root_ncandidates < 100 then begin
+ incr root_ncandidates;
+ root_candidates := (i,p2,c) :: !root_candidates
+ end;
+ end
+ end else
+ if r = round then
+ p2.parents.(c) <- AskPeer x
+ else
+ ask_peer i p p2 c x
+ in
+ retry ()
+ | AskPeer x ->
+ ask_peer i p p2 c x
+
+ done;
+
+ ChildrenArray.iteri (fun i x ->
+ if peers2.(x).distance = p2.distance then begin
+ ChildrenArray.remove p2.children i;
+ for k = 0 to degree - 1 do
+ if peers2.(x).parents.(k) = Parent p.i then
+ peers2.(x).parents.(k) <- AskRoot
+ done
+ end
+ ) p2.children
+
+ done;
+
+
+ root_candidates := List.sort (fun (_,p1,_) (_,p2,_) ->
+ p2.availabilities.(1) - p1.availabilities.(1)) !root_candidates;
+(* List.iter (fun (i,p,_) ->
+ Printf.printf " Cand %d %d\n" i p.availabilities.(1)) !root_candidates;
+*)
+
+ let rec iter list =
+ if !root_nchildren < root_degree then
+ match list with
+ [] -> ()
+ | (i1,_,_) :: ( ( (i2,_,_) :: _ ) as tail) when i1 = i2 ->
+ iter tail
+ | (i,p2,c) :: tail ->
+ p2.parents.(c) <- Parent (-1);
+ root_children.(!root_nchildren) <- Some i;
+ incr root_nchildren;
+ iter tail
+ in
+ iter !root_candidates;
+
+
+ for i = 0 to npeers - 1 do
+ let p = peers.(i) in
+ if p.state = ON then
+ let px2 = peers2.(i) in
+ if px2.candidates <> [] then
+ let candidates = px2.candidates in
+ px2.ncandidates <- 0;
+ px2.candidates <- [];
+ let candidates = List.sort (fun (_,p1,_) (_,p2,_) ->
+ p2.availabilities.(1) - p1.availabilities.(1))
+ candidates in
+
+ let rec iter list =
+ if ChildrenArray.length px2.children < degree then
+ match list with
+ [] -> ()
+ | (i1,_,_) :: ( ( (i2,_,_) :: _ ) as tail) when i1 = i2 ->
+ iter tail
+ | (i,p2,c) :: tail ->
+ ChildrenArray.add px2.children i;
+ p2.parents.(c) <- Parent p.i;
+ iter tail
+ else
+ List.iter (fun (i,p2,c) ->
+ let rec retry () =
+ let y = ChildrenArray.random px2.children in
+ if y = i then
+ retry ()
+ else
+ p2.parents.(c) <- AskPeer y
+ in
+ retry ()
+
+ ) list
+ in
+ iter candidates
+
+ done;
+
+ if round = !next_ticket then begin
+ current_ticket := round;
+ incr hour;
+ next_ticket := accuracy * !hour + Random.int accuracy;
+
+ for i = 0 to !root_nchildren - 1 do
+ match root_children.(i) with
+ None -> ()
+ | Some x ->
+ peers2.(x).tickets <- IntSet.add !hour peers2.(x).tickets
+ done;
+ end;
+
+
+ let avail = Array.create (ndistances + 1) 0 in
+ let npeers_per_dist = Array.create (ndistances + 1) 0 in
+ for i = 0 to npeers - 1 do
+
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+ if p.state = ON && p2.distance <= ndistances then begin
+
+ avail.(p2.distance) <- avail.(p2.distance) + p2.availabilities.(0);
+ npeers_per_dist.(p2.distance) <- npeers_per_dist.(p2.distance) + 1;
+
+ end
+
+ done;
+
+ for i = 1 to ndistances do
+ if npeers_per_dist.(i) <> 0 then
+ let x = 1000. *. float_of_int avail.(i)
+ /. float_of_int npeers_per_dist.(i)
+ /. float_of_int (1+round) in
+(* Printf.printf "avail %d = %.4f\n" i x; *)
+ mean_avail.(i).(round) <-
+
+ int_of_float (x);
+ done;
+(* print_graph round *)
+ done
+
+let _ =
+ print_graph 0
+
+
+let _ =
+ value_per_time string_of_int
+ (Printf.sprintf "%s/peers_per_round" subdir)
+ peers_per_round "available peers";
+ value_per_time string_of_int
+ (Printf.sprintf "%s/ask_root_msgs" subdir)
+ ask_root_msgs "ask root msgs";
+ value_per_time string_of_int
+ (Printf.sprintf "%s/max_distance_per_round" subdir)
+ max_distances "maximal distance";
+ let max_distance = ref 0 in
+ for i = 0 to nrounds - 1 do
+ max_distance := max !max_distance max_distances.(i)
+ done;
+ let max_distance = min !max_distance ndistances in
+ for i = 1 to max_distance do
+ value_per_time string_of_int (Printf.sprintf "%s/mean_avail_distance%d" subdir i)
+ mean_avail.(i)
+ (Printf.sprintf "mean availability at distance %d" i);
+ done;
+ ()
+
+
+
+let avail_error =
+ Printf.printf "availability...\n%!";
+ let avail = Array.create npeers (0,0,false) in
+ for i = 0 to npeers - 1 do
+ let a = (
+ peers2.(i).availabilities.(0),
+ peers2.(i).availabilities.(1),
+ peers2.(i).selfish) in
+ avail.(i) <- a
+ done;
+ Array.sort compare avail;
+
+ let avail_error = ref [] in
+ let filename = Filename.of_string
+ (Printf.sprintf "%s/availability.txt" subdir
+ ) in
+ let oc = open_out filename in
+(* let oc1 = open_out "availabilityS.txt" in (* selfish *) *)
+(* let oc2 = open_out "availabilityC.txt" in (* correct *) *)
+ for i = 0 to npeers - 1 do
+ let (a0,a1,selfish) = avail.(i) in
+ let nrounds = float_of_int nrounds in
+ let a0 = float_of_int a0 in
+ let a1 = float_of_int a1 in
+ let a = (a0,a1,selfish) in
+ avail_error := (abs_float (a0 -. a1) /. nrounds) :: !avail_error;
+ let print oc (a0,a1,_) =
+
+ output_string oc (Printf.sprintf "%d " i);
+ output_string oc (Printf.sprintf "%.3f " (a0 /. nrounds));
+ output_string oc (Printf.sprintf "%.3f " (a1 /. nrounds));
+ output_string oc "\n"
+ in
+ print oc a;
+(* if selfish then print oc1 a else print oc2 a *)
+ done;
+ close_out oc;
+(* close_out oc1;
+ close_out oc2; *)
+ !avail_error
+
+let _ =
+ cdf_of_list string_of_int
+ (Printf.sprintf "%s/sessions" subdir) !sessions
+ "set logscale y\n"
+ "CDF of sessions" "Session Length (minutes)"
+ " title 'Sessions', 60 title '1 hour'";
+ cdf_of_list string_of_int
+ (Printf.sprintf "%s/connections" subdir)
+ !first_connection "" "CDF of connections"
+ "Time to first connection (minutes)"
+ " title 'Time (minutes)'";
+
+(* value_per_time "lost_tickets" lost_tickets "lost heartbeats"; *)
+ cdf_of_list string_of_int (Printf.sprintf "%s/lost_tickets" subdir)
+ (Array.to_list lost_tickets) "" "CDF of rounds"
+ "Number of lost heartbeats"
+ " title ' heartbeats'";
+ cdf_of_list string_of_float
+ (Printf.sprintf "%s/error_avail" subdir) avail_error
+ "set yrange [0:0.1]" "CDF of peers" "Error in measured availability"
+ " title 'error'";
+
+
+
+(*
+let _ =
+ for i = 0 to npeers - 1 do
+
+ let p = peers.(i) in
+ let p2 = peers2.(i) in
+
+
+ if p.state then begin
+ let nparents = ref 0 in
+ for i = 0 to degree - 1 do
+ match p2.parents.(i) with
+ Parent x -> incr nparents
+ | _ -> ()
+ done;
+ Printf.printf "PEER %d %d %d %d\n" i p.session p2.distance !nparents
+ end
+ done
+ *)
diff --git a/sources/fabrice/simulator/build.ocp b/sources/fabrice/simulator/build.ocp
new file mode 100644
index 0000000..d2beede
--- /dev/null
+++ b/sources/fabrice/simulator/build.ocp
@@ -0,0 +1,13 @@
+ pp = "camlp4o.opt"
+
+begin "simul"
+ files = [
+ "randomArray.ml";
+ "simulTypes.ml";
+ "simulGraphes.ml";
+ "simulTrace.ml";
+ ]
+ requires = [ "cdk"; "net" ]
+end
+
+
diff --git a/sources/fabrice/simulator/notes.txt b/sources/fabrice/simulator/notes.txt
new file mode 100644
index 0000000..fb8bdc8
--- /dev/null
+++ b/sources/fabrice/simulator/notes.txt
@@ -0,0 +1,15 @@
+ peerolyse:~/devel/onzego% time ./research/p2p_avail/gentrace trace_10000x1000_1 10000 1000
+./research/p2p_avail/gentrace trace_10000x1000_1 10000 1000 1183.25s user 2.83s system 99% cpu 19:46.89 total
+
+
+
+ peerolyse:~/articles/p2p_avail_metro/simulation% time gentrace trace_500x365_1 500 365
+gentrace trace_500x365_1 500 365 22.19s user 0.05s system 99% cpu 22.267 total
+
+
+In the current implementation of gentrace, all the timezones are in the
+first 12 hours.
+
+
+To obtain big graphs, don't use -Tps, but Tjpg with display
+ dot -Tjpg graph_000000.dot -o graph.jpg
diff --git a/sources/fabrice/simulator/randomArray.ml b/sources/fabrice/simulator/randomArray.ml
new file mode 100644
index 0000000..4f5ddf9
--- /dev/null
+++ b/sources/fabrice/simulator/randomArray.ml
@@ -0,0 +1,73 @@
+
+module type INTERFACE = sig
+
+ type 'a t
+
+ val init : int -> (int -> 'a) -> 'a t
+ val length : 'a t -> int
+ val of_list : 'a list -> 'a t
+ val add : 'a t -> 'a -> unit
+ val random : 'a t -> 'a
+ val reset : 'a t -> unit
+ val set_state : 'a t -> Random.State.t -> unit
+ end
+
+module IMPLEMENTATION = struct
+
+ type 'a t = {
+ mutable length : int;
+ mutable left : int;
+ array : 'a array;
+ mutable state : Random.State.t;
+ }
+
+ let init len f =
+ let array = Array.init len f in
+ {
+ array = array;
+ length = len;
+ left = len;
+ state = Random.get_state ();
+ }
+
+ let of_list list =
+ let array = Array.of_list list in
+ let len = Array.length array in
+ {
+ array = array;
+ length = len;
+ left = len;
+ state = Random.get_state ();
+ }
+
+ let length t = t.length
+
+ let add t x =
+ let len = t.length in
+ t.array.(len) <- x;
+ t.length <- len + 1;
+ if len = t.left then
+ t.left <- len + 1
+
+ let random t =
+ if t.left <= 0 then raise Not_found;
+ let pos = Random.State.int t.state t.left in
+ let tab = t.array in
+ let len = t.left-1 in
+(* Printf.fprintf stderr "SWAP(%d)(%d)%!" pos len; *)
+ let x = tab.(pos) in
+ tab.(pos) <- tab.(len);
+ tab.(len) <- x;
+ t.left <- len;
+ x
+
+ let reset t =
+ t.left <- t.length
+
+ let set_state t state = t.state <- state
+
+ end
+
+include (IMPLEMENTATION : INTERFACE)
+
+ \ No newline at end of file
diff --git a/sources/fabrice/simulator/simulGraphes.ml b/sources/fabrice/simulator/simulGraphes.ml
new file mode 100644
index 0000000..e179d48
--- /dev/null
+++ b/sources/fabrice/simulator/simulGraphes.ml
@@ -0,0 +1,129 @@
+
+let int_of_string s =
+ try
+ int_of_string s
+ with e ->
+ failwith (Printf.sprintf "int_of_string: error with [%s]" (String.escaped s))
+
+let on_file filename =
+ let ic = open_in filename in
+ let count = ref 0 in
+ let mins = ref [||] in
+ let maxs = ref [||] in
+ (try
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ mins := Array.create (List.length line) 0.;
+ maxs := Array.create (List.length line) 0.;
+ let mins = !mins in
+ let maxs = !maxs in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ mins.(i) <- x;
+ maxs.(i) <- x) line;
+ while true do
+ let line = input_line ic in
+ incr count;
+ let line = String2.split_simplify line ' ' in
+ List2.iteri (fun i x ->
+ let x = float_of_string x in
+ mins.(i) <- min x mins.(i);
+ maxs.(i) <- max x maxs.(i)) line;
+ done
+
+ with End_of_file -> ());
+ !count, !mins, !maxs
+
+
+let value_per_time x_of_y filename int_table element =
+ Printf.printf "%s...\n%!" filename;
+ let oc = open_out (Printf.sprintf "%s.txt" filename) in
+ let maximum = ref int_table.(0) in
+ let nrounds = Array.length int_table in
+ for round = 0 to nrounds - 1 do
+ maximum := max !maximum int_table.(round);
+ output_string oc (Printf.sprintf "%d %s\n" round
+ (x_of_y int_table.(round)))
+ done;
+ close_out oc;
+
+ let oc = open_out (Printf.sprintf "%s.plot" filename) in
+ output_string oc (Printf.sprintf "
+set out '%s.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out '%s.eps'
+set yrange [0:%s+1]
+set xrange [0:%d]
+set ylabel 'Number of %s'
+set xlabel 'Time (minutes)'
+
+set data style lines
+
+plot \"%s.txt\" using ($1):($2) title '%s'
+ " filename filename (x_of_y !maximum) nrounds element filename element);
+ close_out oc
+
+
+
+ let npoints = 1000
+
+let cdf_of_list x_of_y filename int_list options xlabel ylabel end_plot =
+ Printf.printf "%s...\n%!" filename;
+ match int_list with
+ [] -> Printf.printf " not enough data\n"
+ | init :: _ ->
+ let int_list = List.sort compare int_list in
+ let nints = List.length int_list in
+
+ let oc = open_out (Printf.sprintf "%s.txt" filename) in
+ let maximum = ref init in
+ List2.iteri (fun i x ->
+ maximum := max !maximum x;
+ output_string oc (Printf.sprintf "%d %s\n" i
+ (x_of_y x))
+ ) int_list;
+ close_out oc;
+
+ let every =
+ if nints > npoints then
+ Printf.sprintf " every %d " (nints / npoints) else "" in
+
+ let oc = open_out (Printf.sprintf "%s.plot" filename) in
+ output_string oc (Printf.sprintf "
+set out '%s.eps'
+set terminal postscript eps enhanced \"Helvetica\" 14
+set out '%s.eps'
+set yrange [1:%s+1]
+set xrange [0:%d]
+set ylabel '%s'
+set xlabel '%s'
+set data style lines
+
+%s
+
+plot \"%s.txt\" %s using ($1):($2) %s
+ " filename filename (x_of_y !maximum) (nints+2) ylabel xlabel options filename every end_plot);
+ close_out oc
+
+
+let for_every every filename =
+ let ic = open_in filename in
+ let nlines = ref 0 in
+ let line = ref "" in
+ try
+ while true do
+ line := input_line ic;
+ incr nlines
+ done
+ with End_of_file ->
+ close_in ic;
+ if !nlines > 0 then
+ let x = (!nlines - 1) mod every in
+ if x > 0 then
+ let oc = open_out_gen [Open_append] 0o644 filename in
+ for i = x to every-1 do
+ Printf.printf "adding line\n";
+ Printf.fprintf oc "%s\n" !line
+ done;
+ close_out oc
diff --git a/sources/fabrice/simulator/simulTrace.ml b/sources/fabrice/simulator/simulTrace.ml
new file mode 100644
index 0000000..b58bf41
--- /dev/null
+++ b/sources/fabrice/simulator/simulTrace.ml
@@ -0,0 +1,162 @@
+open SimulTypes
+open SimulGraphes
+
+type trace_event =
+ Peers of int
+| Days of int * int
+| Peer of int * float * string
+| Round of int
+| On of int
+| Off of int
+| Dead of int
+| End
+| Exponential
+
+let trace_output oc trace_event =
+ output_string oc (match trace_event with
+ Peers npeers -> Printf.sprintf "Peers %d\n" npeers
+ | Days (ndays, day) -> Printf.sprintf "Days %d %d\n" ndays day
+ | Peer (i,avail,s) ->
+ Printf.sprintf "Peer %d %.3f %s\n" i avail s
+ | Round round -> Printf.sprintf "Round %d\n" round
+ | On i -> Printf.sprintf "On %d\n" i
+ | Off i -> Printf.sprintf "Off %d\n" i
+ | Dead i -> Printf.sprintf "Dead %d\n" i
+ | End -> "End\n"
+ | Exponential -> "Exponential\n"
+ )
+
+let trace_input ic =
+ let line = input_line ic in
+ match String2.split line ' ' with
+ ["Peers"; npeers] -> Peers (int_of_string npeers)
+ | ["Days"; ndays] -> Days (int_of_string ndays, 24 * 60)
+ | ["Days"; ndays; day] -> Days (int_of_string ndays, int_of_string day)
+ | "Peer" :: i :: avail :: tail ->
+ Peer (int_of_string i, float_of_string avail, String2.unsplit tail ' ')
+ | ["End"] -> End
+ | ["Exponential"] -> Exponential
+ | ["Round"; round] -> Round (int_of_string round)
+ | ["On"; i] -> On (int_of_string i)
+ | ["Dead"; i] -> Dead (int_of_string i)
+ | ["Off"; i] -> Off (int_of_string i)
+
+ | _ -> failwith (Printf.sprintf "Bad line [%s]" (String.escaped line))
+
+let print_distribution = ref false
+(* gnuplot> plot exp(1-log(2+65*x)), 1.0/12 *)
+
+let exponential = ref false
+let distribution = ref []
+let availability = ref []
+
+let trace_read filename =
+ let ic = open_in filename in
+ let npeers = match trace_input ic with
+ Peers npeers -> npeers
+ | _ -> assert false
+ in
+ let (ndays, day) = match trace_input ic with
+ Days (ndays, day) -> ndays, day
+ | _ -> assert false
+ in
+
+ let rec read_peer ii =
+ match trace_input ic with
+ Exponential -> exponential := true;
+ read_peer ii
+ | Peer (i, avail, s) ->
+ assert (i=ii);
+(*
+ let x = float_of_int avail /. 900000. in
+
+ let avail = (if !exponential then
+ max 0.02 (min 1. (exp(1. -. log(2. +. 65. *. x))))
+ else
+ 0.02 +. 0.98 *. x
+ )
+ in
+ if !print_distribution then begin
+ distribution := x :: !distribution;
+ availability := avail :: !availability;
+ end;
+ let lambda = float_of_int decs /. (60. *. 24.) in
+ let mu = avail *. lambda /. (1. -. avail) in
+ *)
+ let p = {
+ i = i;
+ avail = avail;
+ descr = s;
+ session = 0;
+ day = true;
+ state = OFF;
+ real_avail = 0;
+ real_decs = 0;
+ } in
+ p
+ | _ -> assert false
+ in
+ let peers = Array.init npeers read_peer in
+ let event = ref None in
+ let get_event () =
+ let ev = trace_input ic in
+ event := Some ev
+ in
+
+ let next_day = ref 0 in
+ let begin_time = (Int64.of_float (Unix.gettimeofday ())) in
+ let rec iter_round round =
+ match !event with
+ None ->
+ next_event round
+ | Some ev ->
+ match ev with
+ Round rr ->
+ if rr = round then begin
+ if !next_day = round then begin
+ let time = Unix.gettimeofday () in
+ let time = Int64.of_float time in
+ Printf.printf "Day %d (%Ld)\n%!" (round / day)
+ (Int64.sub time begin_time);
+ next_day := !next_day + day
+ end;
+ next_event round
+ end else
+ assert (rr > round)
+ | On i ->
+ event := None;
+ let p = peers.(i) in
+ p.state <- ON;
+ next_event round
+ | Off i ->
+ event := None;
+ let p = peers.(i) in
+ p.state <- OFF;
+ p.real_decs <- p.real_decs + 1;
+ next_event round
+ | Dead i ->
+ event := None;
+ let p = peers.(i) in
+ p.state <- DEAD;
+ peers.(i) <- {
+ p with state = OFF;
+ };
+ next_event round
+ | End -> ()
+ | _ -> assert false
+
+ and next_event round =
+ get_event ();
+ iter_round round
+ in
+ if !print_distribution then begin
+ cdf_of_list string_of_float "dist_random" !distribution
+ "set yrange [0:1]" "CDF of peers" "Distribution"
+ " title 'random'";
+ cdf_of_list string_of_float "dist_availability" !availability
+ "set yrange [0:1]" "CDF of peers" "Distribution"
+ " title 'avail'";
+ distribution := [];
+ availability := [];
+ end;
+ peers, ndays * day, iter_round
diff --git a/sources/fabrice/simulator/simulTypes.ml b/sources/fabrice/simulator/simulTypes.ml
new file mode 100644
index 0000000..7d76049
--- /dev/null
+++ b/sources/fabrice/simulator/simulTypes.ml
@@ -0,0 +1,91 @@
+
+type state = ON | OFF | DEAD
+
+type peer = {
+ i : int;
+
+ descr : string;
+
+ avail : float;
+ mutable session : int;
+ mutable day : bool;
+ mutable state : state;
+ mutable real_avail : int;
+ mutable real_decs : int;
+ }
+
+
+let _ = Random.self_init ()
+
+
+module ChildrenArray : sig
+
+ type t
+
+ val length : t -> int
+ val create : int -> t
+ val mem : t -> int -> bool
+ val add : t -> int -> unit
+ val iteri : (int -> int -> unit) -> t -> unit
+ val remove : t -> int -> unit
+ val random : t -> int
+ val clear : t -> unit
+
+ val of_list : int list -> t
+
+ end = struct
+
+ type t = {
+ mutable length : int;
+ array : int array;
+ }
+
+ let create n = {
+ length = 0;
+ array = Array.create n 0;
+ }
+
+ let clear t = t.length <- 0
+
+ let add t i =
+ let len = t.length in
+ t.array.(len) <- i;
+ t.length <- len + 1
+
+ let remove t pos =
+ let tab = t.array in
+ let len = t.length-1 in
+ tab.(pos) <- tab.(len);
+ t.length <- len
+
+ let length t = t.length
+
+ let iteri f t =
+ let rec iter i t =
+ let len = t.length in
+ if i < len then begin
+ f i t.array.(i);
+ if len > t.length then iter i t else
+ iter (i+1) t
+ end
+ in
+ iter 0 t
+
+ let mem t v =
+ let rec iter i t =
+ (i < t.length) &&
+ (t.array.(i) = v || iter (i+1) t)
+ in
+ iter 0 t
+
+ let random t =
+ t.array.(Random.int t.length)
+
+ let of_list list =
+ let array = Array.of_list list in
+ {
+ array = array;
+ length = Array.length array;
+ }
+
+ end