| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- from BTL.obsoletepythonsupport import set
- from BitTorrent.TorrentPolicy import Policy
- from BitTorrent.Torrent import *
- class TorrentButler(Policy):
- def __init__(self, multitorrent):
- Policy.__init__(self, multitorrent)
- self.multitorrent = multitorrent
- class EverythingAllOfTheTimeTorrentButler(TorrentButler):
- def __init__(self, multitorrent):
- TorrentButler.__init__(self, multitorrent)
- def butle(self):
- for torrent in self.multitorrent.get_torrents():
- if not self.multitorrent.torrent_running(torrent.metainfo.infohash):
- self.multitorrent.start_torrent(torrent.metainfo.infohash)
- class EverythingOneTimeTorrentButler(TorrentButler):
- def __init__(self, multitorrent):
- TorrentButler.__init__(self, multitorrent)
- self.started_torrents = set()
- def butle(self):
- for torrent in self.multitorrent.get_torrents():
- if ((not self.multitorrent.torrent_running(torrent.metainfo.infohash)) and
- (not torrent.metainfo.infohash in self.started_torrents)):
- self.multitorrent.start_torrent(torrent.metainfo.infohash)
- self.started_torrents.add(torrent.metainfo.infohash)
- class DownloadTorrentButler(TorrentButler):
- # TODO: this one should probably be configurable, once the new choker works
- SIMULTANEOUS = 3
- GOOD_RATE_THRESHOLD = 0.25 # minimal fraction of the average rate
- PURGATORY_TIME = 60 # seconds before we declare an underperformer "bad"
- LIMIT_MARGIN = 0.9 # consider bandwidth maximized at limit * margin
- REFRACTORY_PERIOD = 30 # seconds we wait after falling below the limit
- def __init__(self, multitorrent):
- TorrentButler.__init__(self, multitorrent)
- self.suspects = {}
- self.time_last_pushed_limit = bttime() - self.REFRACTORY_PERIOD
- def butles(self, torrent):
- return torrent.policy == "auto" and (not torrent.completed) and torrent.state in ["initialized", "running"]
- def butle(self):
- going = []
- waiting = []
- finishing = []
- num_initializing = 0
- for torrent in self.multitorrent.get_torrents():
- if self.butles(torrent):
- if self.multitorrent.torrent_running(torrent.metainfo.infohash):
- going.append(torrent)
- elif torrent.is_initialized():
- if torrent.get_percent_complete() < 1.0:
- waiting.append(torrent)
- else:
- finishing.append(torrent)
- elif not torrent.completed:
- if torrent.state in ["created", "initializing"]:
- if (bttime() - torrent.time_created < 10):
- num_initializing += 1
- for t in finishing:
- self.multitorrent.start_torrent(t.metainfo.infohash)
- starting = [t for t in going
- if bttime() - t.time_started < 60]
- transferring = [t for t in going
- if t not in starting
- and t.get_downrate() > 0.0
- and t.get_num_connections() > 0]
- num_good = 0
- num_virtual_good = 0
- if (len(transferring) > 0):
- total_rate = sum([t.get_downrate() for t in transferring])
- good_rate = (total_rate / len(transferring)) * self.GOOD_RATE_THRESHOLD
- if good_rate > 0:
- bad = []
- for t in transferring:
- if t.get_downrate() >= good_rate:
- if self.suspects.has_key(t.metainfo.infohash):
- #print t.working_path + " is good now, popping"
- self.suspects.pop(t.metainfo.infohash)
- else:
- if self.suspects.has_key(t.metainfo.infohash):
- #print t.working_path, bttime() - self.suspects[t.metainfo.infohash]
- if (bttime() - self.suspects[t.metainfo.infohash] >=
- self.PURGATORY_TIME):
- bad.append(t)
- else:
- #print t.working_path + " is bad now, inserting"
- self.suspects[t.metainfo.infohash] = bttime()
- total_bad_rate = sum([t.get_downrate() for t in bad])
- num_virtual_good = total_bad_rate / good_rate
- num_good = len(transferring) - len(bad)
- uprate, downrate = self.multitorrent.get_total_rates()
- downrate_limit = self.multitorrent.config['max_download_rate']
- #print num_initializing, num_good, num_virtual_good, len(starting)
- #print downrate, '/', downrate_limit
- if (downrate >= downrate_limit * self.LIMIT_MARGIN):
- self.time_last_pushed_limit = bttime()
- #print "pushing limit"
- #print bttime() - self.time_last_pushed_limit
- if ((bttime() - self.time_last_pushed_limit >
- self.REFRACTORY_PERIOD) and
- (num_initializing == 0) and
- (num_good + num_virtual_good + len(starting) < self.SIMULTANEOUS)):
- high = []
- norm = []
- low = []
- for torrent in waiting:
- if torrent.priority == "high":
- high.append(torrent)
- elif torrent.priority == "normal":
- norm.append(torrent)
- elif torrent.priority == "low":
- low.append(torrent)
- for p in (high, norm, low):
- best = None
- for torrent in p:
- if ((not best) or
- (best.get_percent_complete() == 0 and
- torrent.total_bytes < best.total_bytes) or
- (torrent.get_percent_complete() >
- best.get_percent_complete())):
- best = torrent
- if best:
- break
- if best:
- self.multitorrent.start_torrent(best.metainfo.infohash)
- class SeedTorrentButler(TorrentButler):
- FREQUENCY = 15
- MIN_RATE = 2000.0
- THRESHOLD = 1.25
- MIN_TRANSFERRING = 1
- def __init__(self, multitorrent):
- TorrentButler.__init__(self, multitorrent)
- self.counter = 0
- def butles(self, torrent):
- return torrent.policy == "auto" and torrent.completed and torrent.state in ["initialized", "running"]
- def butle(self):
- self.counter += 1
- self.counter %= self.FREQUENCY
- if self.counter != 0:
- return
- num_connections = 0
- transferring = []
- stopped = []
- total_rate = 0.0
- for torrent in self.multitorrent.get_torrents():
- if self.butles(torrent):
- if self.multitorrent.torrent_running(torrent.metainfo.infohash):
- #print "found running torrent: ", torrent.get_uprate(), torrent.get_num_connections(), torrent._activity
- if (torrent.get_uprate() > 0.0
- and torrent.get_num_connections() > 0):
- transferring.append(torrent)
- for c in torrent.get_connections():
- total_rate += c.upload.measure.get_rate()
- num_connections += 1
- else:
- #print "found stopped torrent: ", torrent._activity
- stopped.append(torrent)
- #print num_connections, len(transferring), len(stopped)
- if (len(transferring) < self.MIN_TRANSFERRING
- or total_rate / num_connections > self.MIN_RATE * self.THRESHOLD):
- if len(stopped):
- r = random.randint(0, len(stopped) - 1)
- #print "starting torrent"
- self.multitorrent.start_torrent(stopped[r].metainfo.infohash)
- elif total_rate / num_connections < self.MIN_RATE:
- if len(transferring) > self.MIN_TRANSFERRING:
- def lambda_dammit(x, y):
- try:
- x_contribution = x.get_uprate() / x.get_avg_peer_downrate()
- except ZeroDivisionError:
- x_contribution = 1.0
- try:
- y_contribution = y.get_uprate() / y.get_avg_peer_downrate()
- except ZeroDivisionError:
- y_contribution = 1.0
- return cmp(x_contribution, y_contribution)
- transferring.sort(lambda_dammit)
- self.multitorrent.stop_torrent(transferring[0].metainfo.infohash)
|