00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
00034 #define TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
00035
00036 #include <map>
00037 #include <utility>
00038
00039 #include <boost/shared_ptr.hpp>
00040
00041 #include "libtorrent/resource_request.hpp"
00042 #include "libtorrent/peer_id.hpp"
00043 #include "libtorrent/socket.hpp"
00044 #include "libtorrent/size_type.hpp"
00045
00046 #ifdef min
00047 #undef min
00048 #endif
00049
00050 #ifdef max
00051 #undef max
00052 #endif
00053
00054 namespace libtorrent
00055 {
00056
00057 int saturated_add(int a, int b);
00058
00059 namespace aux
00060 {
00061
00062
00063 inline int give(resource_request& r, int num_resources)
00064 {
00065 assert(num_resources >= 0);
00066 assert(r.given <= r.max);
00067
00068 int accepted = (std::min)(num_resources, r.max - r.given);
00069 assert(accepted >= 0);
00070
00071 r.given += accepted;
00072 assert(r.given <= r.max);
00073
00074 return accepted;
00075 }
00076
00077 inline int div_round_up(int numerator, int denominator)
00078 {
00079 return (numerator + denominator - 1) / denominator;
00080 }
00081
00082 #ifndef NDEBUG
00083
00084 template<class It, class T>
00085 class allocate_resources_contract_check
00086 {
00087 int m_resources;
00088 It m_start;
00089 It m_end;
00090 resource_request T::* m_res;
00091
00092 public:
00093 allocate_resources_contract_check(
00094 int resources
00095 , It start
00096 , It end
00097 , resource_request T::* res)
00098 : m_resources(resources)
00099 , m_start(start)
00100 , m_end(end)
00101 , m_res(res)
00102 {
00103 assert(m_resources >= 0);
00104 for (It i = m_start, end(m_end); i != end; ++i)
00105 {
00106 assert(((*i).*m_res).max >= 0);
00107 assert(((*i).*m_res).given >= 0);
00108 }
00109 }
00110
00111 ~allocate_resources_contract_check()
00112 {
00113 int sum_given = 0;
00114 int sum_max = 0;
00115 int sum_min = 0;
00116 for (It i = m_start, end(m_end); i != end; ++i)
00117 {
00118 assert(((*i).*m_res).max >= 0);
00119 assert(((*i).*m_res).min >= 0);
00120 assert(((*i).*m_res).max >= ((*i).*m_res).min);
00121 assert(((*i).*m_res).given >= 0);
00122 assert(((*i).*m_res).given <= ((*i).*m_res).max);
00123
00124 sum_given = saturated_add(sum_given, ((*i).*m_res).given);
00125 sum_max = saturated_add(sum_max, ((*i).*m_res).max);
00126 sum_min = saturated_add(sum_min, ((*i).*m_res).min);
00127 }
00128 if (sum_given != (std::min)(std::max(m_resources, sum_min), sum_max))
00129 {
00130 std::cerr << sum_given << " " << m_resources << " " << sum_min << " " << sum_max << std::endl;
00131 assert(false);
00132 }
00133 }
00134 };
00135
00136 #endif
00137
00138 template<class It, class T>
00139 void allocate_resources_impl(
00140 int resources
00141 , It start
00142 , It end
00143 , resource_request T::* res)
00144 {
00145 assert(resources >= 0);
00146 #ifndef NDEBUG
00147 allocate_resources_contract_check<It, T> contract_check(
00148 resources
00149 , start
00150 , end
00151 , res);
00152 #endif
00153
00154 for (It i = start; i != end; ++i)
00155 {
00156 resource_request& r = (*i).*res;
00157 r.leftovers = (std::max)(r.used - r.given, 0);
00158 }
00159
00160 if (resources == resource_request::inf)
00161 {
00162
00163
00164 for (It i = start; i != end; ++i)
00165 {
00166 ((*i).*res).given = ((*i).*res).max;
00167 }
00168 return;
00169 }
00170
00171
00172
00173 int sum_max = 0;
00174 int sum_min = 0;
00175
00176
00177 int num_saturated = 0;
00178
00179
00180
00181
00182 size_type saturated_sum = 0;
00183 for (It i = start; i != end; ++i)
00184 {
00185 resource_request& r = (*i).*res;
00186 sum_max = saturated_add(sum_max, r.max);
00187 assert(r.min < resource_request::inf);
00188 assert(r.min >= 0);
00189 assert(r.min <= r.max);
00190 sum_min += r.min;
00191
00192
00193
00194 size_type used = r.used;
00195 if (r.given == 0) continue;
00196 if (used * 20 / r.given >= 19)
00197 {
00198 ++num_saturated;
00199 saturated_sum += r.given;
00200 }
00201 }
00202
00203 if (sum_max <= resources)
00204 {
00205
00206
00207 for (It i = start; i != end; ++i)
00208 {
00209 ((*i).*res).given = ((*i).*res).max;
00210 }
00211 return;
00212 }
00213
00214 if (sum_min >= resources)
00215 {
00216
00217
00218
00219 for (It i = start; i != end; ++i)
00220 {
00221 ((*i).*res).given = ((*i).*res).min;
00222 }
00223 return;
00224 }
00225
00226
00227
00228
00229
00230
00231 for (It i = start; i != end; ++i)
00232 {
00233 resource_request& r = (*i).*res;
00234
00235 int target;
00236 size_type used = r.used;
00237 if (r.given > 0 && used * 20 / r.given >= 19)
00238 {
00239 assert(num_saturated > 0);
00240 target = div_round_up(saturated_sum, num_saturated);
00241 target += div_round_up(target, 10);
00242 }
00243 else
00244 {
00245 target = r.used;
00246 }
00247 if (target > r.max) target = r.max;
00248 else if (target < r.min) target = r.min;
00249
00250
00251 r.used = r.given + div_round_up(target - r.given, 8);
00252 r.given = r.min;
00253 }
00254
00255
00256 resources = (std::max)(resources, sum_min);
00257 int resources_to_distribute = (std::min)(resources, sum_max) - sum_min;
00258 assert(resources_to_distribute >= 0);
00259 #ifndef NDEBUG
00260 int prev_resources_to_distribute = resources_to_distribute;
00261 #endif
00262 while (resources_to_distribute > 0)
00263 {
00264
00265
00266 size_type total_used = 0;
00267 size_type max_used = 0;
00268 for (It i = start; i != end; ++i)
00269 {
00270 resource_request& r = (*i).*res;
00271 if (r.given == r.max) continue;
00272
00273 assert(r.given < r.max);
00274
00275 max_used = (std::max)(max_used, (size_type)r.used + 1);
00276 total_used += (size_type)r.used + 1;
00277 }
00278
00279
00280 size_type kNumer = resources_to_distribute;
00281 size_type kDenom = total_used;
00282 assert(kNumer >= 0);
00283 assert(kDenom >= 0);
00284 assert(kNumer <= (std::numeric_limits<int>::max)());
00285
00286 if (kNumer * max_used <= kDenom)
00287 {
00288 kNumer = 1;
00289 kDenom = max_used;
00290 assert(kDenom >= 0);
00291 }
00292
00293 for (It i = start; i != end && resources_to_distribute > 0; ++i)
00294 {
00295 resource_request& r = (*i).*res;
00296 if (r.given == r.max) continue;
00297
00298 assert(r.given < r.max);
00299
00300 size_type used = (size_type)r.used + 1;
00301 if (used < 1) used = 1;
00302 size_type to_give = used * kNumer / kDenom;
00303 if (to_give > resources_to_distribute)
00304 to_give = resources_to_distribute;
00305 assert(to_give >= 0);
00306 assert(to_give <= resources_to_distribute);
00307 #ifndef NDEBUG
00308 int tmp = resources_to_distribute;
00309 #endif
00310 resources_to_distribute -= give(r, (int)to_give);
00311 assert(resources_to_distribute <= tmp);
00312 assert(resources_to_distribute >= 0);
00313 }
00314
00315 assert(resources_to_distribute >= 0);
00316 assert(resources_to_distribute < prev_resources_to_distribute);
00317 #ifndef NDEBUG
00318 prev_resources_to_distribute = resources_to_distribute;
00319 #endif
00320 }
00321 assert(resources_to_distribute == 0);
00322 }
00323
00324 }
00325 }
00326
00327
00328 #endif