/
baranovpericpropshare.py
146 lines (116 loc) · 6.27 KB
/
baranovpericpropshare.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/python
# This is a dummy peer that just illustrates the available information your peers
# have available. The setup script will copy it to create the versions you edit
import random
import logging
from messages import Upload, Request
from util import even_split
from peer import Peer
class BaranovPericPropShare(Peer):
def post_init(self):
print("post_init(): %s here!" % self.id)
##################################################################################
# Declare any variables here that you want to be able to access in future rounds #
##################################################################################
#This commented out code is and example of a python dictionsary,
#which is a convenient way to store a value indexed by a particular "key"
#self.dummy_state = dict()
#self.dummy_state["cake"] = "lie"
def requests(self, peers, history):
"""
peers: available info about the peers (who has what pieces)
history: what's happened so far as far as this peer can see
returns: a list of Request() objects
This will be called after update_pieces() with the most recent state.
"""
#Calculate the pieces you still need
needed = lambda i: self.pieces[i] < self.conf.blocks_per_piece
needed_pieces = list(filter(needed, list(range(len(self.pieces)))))
np_set = set(needed_pieces) # sets support fast intersection ops.
logging.debug("%s here: still need pieces %s" % (
self.id, needed_pieces))
#This code shows you what you have access to in peers and history
#You won't need it in your final solution, but may want to uncomment it
#and see what it does to help you get started
"""
logging.debug("%s still here. Here are some peers:" % self.id)
for p in peers:
logging.debug("id: %s, available pieces: %s" % (p.id, p.available_pieces))
logging.debug("And look, I have my entire history available too:")
logging.debug("look at the AgentHistory class in history.py for details")
logging.debug(str(history))
"""
requests = [] # We'll put all the things we want here
# Symmetry breaking is good...
random.shuffle(needed_pieces)
# count frequencies of all pieces that the other peers have
# this will be useful for implementing rarest first
###########################################################
# you'll need to write the code to compute these yourself #
###########################################################
frequencies = {}
# Python syntax to perform a sort using a user defined sort key
# This exact sort is probably not a useful sort, but other sorts might be useful
# peers.sort(key=lambda p: p.id)
# request all available pieces from all peers!
# (up to self.max_requests from each)
#############################################################################
# This code asks for pieces at random, you need to adapt it to rarest first #
#############################################################################
for peer in peers:
av_set = set(peer.available_pieces)
isect = av_set.intersection(np_set)
n = min(self.max_requests, len(isect))
# More symmetry breaking -- ask for random pieces.
# You could try fancier piece-requesting strategies
# to avoid getting the same thing from multiple peers at a time.
for piece_id in random.sample(isect, int(n)):
# aha! The peer has this piece! Request it.
# which part of the piece do we need next?
# (must get the next-needed blocks in order)
#
# If you loop over the piece_ids you want to request above
# you don't need to change the rest of this code
start_block = self.pieces[piece_id]
r = Request(self.id, peer.id, piece_id, start_block)
requests.append(r)
return requests
def uploads(self, requests, peers, history):
"""
requests -- a list of the requests for this peer for this round
peers -- available info about all the peers
history -- history for all previous rounds
returns: list of Upload objects.
In each round, this will be called after requests().
"""
##############################################################################
# The code and suggestions here will get you started for the standard client #
# You'll need to change things for the other clients #
##############################################################################
round = history.current_round()
logging.debug("%s again. It's round %d." % (
self.id, round))
# One could look at other stuff in the history too here.
# For example, history.downloads[round-1] (if round != 0, of course)
# has a list of Download objects for each Download to this peer in
# the previous round.
if len(requests) == 0:
logging.debug("No one wants my pieces!")
chosen = []
bws = []
else:
logging.debug("Still here: uploading to a random peer")
########################################################################
# The dummy client picks a single peer at random to unchoke. #
# You should decide a set of peers to unchoke accoring to the protocol #
########################################################################
request = random.choice(requests)
chosen = [request.requester_id]
# Now that we have chosen who to unchoke, the standard client evenly shares
# its bandwidth among them
bws = even_split(self.up_bw, len(chosen))
# create actual uploads out of the list of peer ids and bandwidths
# You don't need to change this
uploads = [Upload(self.id, peer_id, bw)
for (peer_id, bw) in zip(chosen, bws)]
return uploads