patch #7756
[mldonkey.git] / src / networks / bittorrent / bTChooser.ml
blobfd839e1307d8d318c610d976f90b7ab4bdcd54a5
1 (* Copyright 2003, Denis Fortin
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 open Int64ops
21 open Printf2
22 open BasicSocket
23 open List2
24 open Options
26 open CommonOptions
27 open CommonTypes
28 open CommonGlobals
30 open BTRate
31 open BTTypes
32 open BTOptions
33 open BTGlobals
35 (*given some files choose the next uploaders based on their behavior
36 Will choose max_uploaders_per_torrent uploaders for each file in list
37 fun_comp is the function use to classify clients
39 let choose_next_uploaders files fun_comp =
40 let full_list = ref ([] : BTTypes.client list)
41 and keepn orl l i =
42 (*constructs a list of i items max with all
43 orl items + some l items *)
44 let orig_num = List.length orl in
45 if orig_num < i && i > 0 then
46 let keep,rest = cut (i - orig_num) l in
47 orl@keep,rest
48 else
49 orl,l
51 List.iter (fun f ->
52 let max_list = ref ([] : BTTypes.client list) in
53 (*all clients*)
54 let possible_uploaders = ref ([] : BTTypes.client list) in
55 Hashtbl.iter (fun _ c ->
56 begin
57 possible_uploaders := (c::!possible_uploaders);
58 end ) f.file_clients;
59 if !verbose_upload then
60 lprintf_nl "clients num %d as possible uploaders for file %s" (List.length !possible_uploaders) f.file_name;
61 (*Interested clients with a connection*)
62 let filtl = List.filter (fun c -> c.client_interested == true
63 && (c.client_sock != NoConnection)
64 ) !possible_uploaders in
65 (*sort by biggest contributor*)
66 let sortl = List.sort fun_comp filtl in
67 (*add max_uploaders_per_torrent-1 from the best*)
68 let to_add,next = keepn !max_list sortl (!!max_uploaders_per_torrent - 1) in
69 max_list:= to_add;
70 (* clients in optim are current optimistic uploaders (30 seconds) *)
71 let optim,notoptim = List.partition ( fun a ->
72 (Rate.ratesince a.client_upload_rate) > 0
73 && a.client_last_optimist + 30 > last_time()
74 ) next in
75 let notoptim = List.sort (fun a b -> compare a.client_last_optimist b.client_last_optimist) notoptim in
76 (*add at least one optimistic uploader*)
77 let to_add,next = keepn !max_list (optim) (!!max_uploaders_per_torrent) in
78 max_list := to_add;
79 (*fill up with not optimistic uploaders*)
80 let to_add,_ = keepn !max_list (notoptim) (!!max_uploaders_per_torrent) in
81 full_list := !full_list @ to_add;
82 if !verbose_upload then
83 begin
84 lprintf_n "potential uploaders count: %d list: [" (List.length to_add);
85 List.iter (fun cr ->
86 let (ip,port) = cr.client_host in
87 lprintf " %s:%d" (Ip.to_string ip) port;
88 ) to_add;
89 lprintf " ]\n";
90 end;
92 ) files;
93 !full_list
96 let choose_best_downloaders files =
97 (*sort: left to download, then priority*)
98 let files = List.stable_sort
99 (fun a b -> compare
100 ((file_size a) -- (match a.file_swarmer with
101 | None -> Int64.zero
102 | Some swarmer ->
103 CommonSwarming.downloaded swarmer))
104 ((file_size b) -- (match b.file_swarmer with
105 | None -> Int64.zero
106 | Some swarmer ->
107 CommonSwarming.downloaded swarmer))
108 ) files in
109 let files = List.stable_sort
110 (fun a b -> compare
111 (CommonFile.file_priority (CommonFile.as_file b.file_file))
112 (CommonFile.file_priority (CommonFile.as_file a.file_file))
113 ) files in
114 (*use sort function that puts the client we download best from on top*)
115 choose_next_uploaders files (fun a b -> Rate.compare b.client_downloaded_rate
116 a.client_downloaded_rate)
119 let choose_best_uploaders files =
120 (*use sort function that puts the client we upload best to on top*)
121 choose_next_uploaders files (fun a b -> Rate.compare b.client_upload_rate
122 a.client_upload_rate)
125 let choose_uploaders files =
126 (*list of new uploaders from the files we download and the files we seed*)
127 let next_uploaders =
128 ( (choose_best_downloaders (List.filter
129 (fun f -> file_state f = FileDownloading )
130 !current_files ))
131 @ (choose_best_uploaders (List.filter
132 (fun f -> file_state f = FileShared )
133 !current_files ))
134 ) in
135 (*do some debug output and choose the first max_bt_uploaders from the list*)
136 begin
137 if !verbose_upload then
138 begin
139 lprintf_n "next_uploaders: %d list: [" (List.length next_uploaders);
140 List.iter (fun cr ->
141 let (ip,port) = cr.client_host in
142 lprintf " %s:%d" (Ip.to_string ip) port;
143 ) next_uploaders;
144 lprintf " ]\n";
145 end;
146 if (List.length next_uploaders) > !!max_bt_uploaders then
147 let keep,rest = List2.cut !!max_bt_uploaders next_uploaders in
148 begin
149 if !verbose_upload then
150 begin
151 lprintf_n "cut next_uploaders: %d list: [" (List.length keep);
152 List.iter (fun cr ->
153 let (ip,port) = cr.client_host in
154 lprintf " %s:%d" (Ip.to_string ip) port;
155 ) keep;
156 lprintf " ]\n";
157 end;
158 keep
160 else next_uploaders