peer-selection: if we must loop, send a minimal number of queries (by asking for more than one share per peer on the second pass)
This commit is contained in:
parent
7123ff82c1
commit
24e6ccddce
|
@ -78,6 +78,7 @@ class FakeStorageServer:
|
||||||
def __init__(self, mode):
|
def __init__(self, mode):
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.allocated = []
|
self.allocated = []
|
||||||
|
self.queries = 0
|
||||||
def callRemote(self, methname, *args, **kwargs):
|
def callRemote(self, methname, *args, **kwargs):
|
||||||
def _call():
|
def _call():
|
||||||
meth = getattr(self, methname)
|
meth = getattr(self, methname)
|
||||||
|
@ -89,6 +90,7 @@ class FakeStorageServer:
|
||||||
def allocate_buckets(self, storage_index, renew_secret, cancel_secret,
|
def allocate_buckets(self, storage_index, renew_secret, cancel_secret,
|
||||||
sharenums, share_size, canary):
|
sharenums, share_size, canary):
|
||||||
#print "FakeStorageServer.allocate_buckets(num=%d, size=%d)" % (len(sharenums), share_size)
|
#print "FakeStorageServer.allocate_buckets(num=%d, size=%d)" % (len(sharenums), share_size)
|
||||||
|
self.queries += 1
|
||||||
if self.mode == "full":
|
if self.mode == "full":
|
||||||
return (set(), {},)
|
return (set(), {},)
|
||||||
elif self.mode == "already got them":
|
elif self.mode == "already got them":
|
||||||
|
@ -304,6 +306,7 @@ class PeerSelection(unittest.TestCase):
|
||||||
for p in self.node.last_peers:
|
for p in self.node.last_peers:
|
||||||
allocated = p.ss.allocated
|
allocated = p.ss.allocated
|
||||||
self.failUnlessEqual(len(allocated), 1)
|
self.failUnlessEqual(len(allocated), 1)
|
||||||
|
self.failUnlessEqual(p.ss.queries, 1)
|
||||||
d.addCallback(_check)
|
d.addCallback(_check)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -319,6 +322,7 @@ class PeerSelection(unittest.TestCase):
|
||||||
for p in self.node.last_peers:
|
for p in self.node.last_peers:
|
||||||
allocated = p.ss.allocated
|
allocated = p.ss.allocated
|
||||||
self.failUnlessEqual(len(allocated), 2)
|
self.failUnlessEqual(len(allocated), 2)
|
||||||
|
self.failUnlessEqual(p.ss.queries, 2)
|
||||||
d.addCallback(_check)
|
d.addCallback(_check)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -337,14 +341,33 @@ class PeerSelection(unittest.TestCase):
|
||||||
allocated = p.ss.allocated
|
allocated = p.ss.allocated
|
||||||
self.failUnless(len(allocated) in (1,2), len(allocated))
|
self.failUnless(len(allocated) in (1,2), len(allocated))
|
||||||
if len(allocated) == 1:
|
if len(allocated) == 1:
|
||||||
|
self.failUnlessEqual(p.ss.queries, 1)
|
||||||
got_one.append(p)
|
got_one.append(p)
|
||||||
else:
|
else:
|
||||||
|
self.failUnlessEqual(p.ss.queries, 2)
|
||||||
got_two.append(p)
|
got_two.append(p)
|
||||||
self.failUnlessEqual(len(got_one), 49)
|
self.failUnlessEqual(len(got_one), 49)
|
||||||
self.failUnlessEqual(len(got_two), 1)
|
self.failUnlessEqual(len(got_two), 1)
|
||||||
d.addCallback(_check)
|
d.addCallback(_check)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def test_four_each(self):
|
||||||
|
# if we have 200 shares, and there are 50 peers, then each peer gets
|
||||||
|
# 4 shares. The design goal is to accomplish this with only two
|
||||||
|
# queries per peer.
|
||||||
|
|
||||||
|
data = self.get_data(SIZE_LARGE)
|
||||||
|
self.u.DEFAULT_ENCODING_PARAMETERS = (100, 150, 200)
|
||||||
|
d = self.u.upload_data(data)
|
||||||
|
d.addCallback(self._check_large, SIZE_LARGE)
|
||||||
|
def _check(res):
|
||||||
|
for p in self.node.last_peers:
|
||||||
|
allocated = p.ss.allocated
|
||||||
|
self.failUnlessEqual(len(allocated), 4)
|
||||||
|
self.failUnlessEqual(p.ss.queries, 2)
|
||||||
|
d.addCallback(_check)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
# upload with exactly 75 peers (shares_of_happiness)
|
# upload with exactly 75 peers (shares_of_happiness)
|
||||||
|
|
|
@ -124,7 +124,7 @@ class Tahoe2PeerSelector:
|
||||||
|
|
||||||
self.homeless_shares = range(total_shares)
|
self.homeless_shares = range(total_shares)
|
||||||
# self.uncontacted_peers = list() # peers we haven't asked yet
|
# self.uncontacted_peers = list() # peers we haven't asked yet
|
||||||
self.contacted_peers = list() # peers worth asking again
|
self.contacted_peers = ["start"] # peers worth asking again
|
||||||
self.use_peers = set() # PeerTrackers that have shares assigned to them
|
self.use_peers = set() # PeerTrackers that have shares assigned to them
|
||||||
self.preexisting_shares = {} # sharenum -> PeerTracker holding the share
|
self.preexisting_shares = {} # sharenum -> PeerTracker holding the share
|
||||||
|
|
||||||
|
@ -191,13 +191,19 @@ class Tahoe2PeerSelector:
|
||||||
d = peer.query(shares_to_ask)
|
d = peer.query(shares_to_ask)
|
||||||
d.addBoth(self._got_response, peer, shares_to_ask)
|
d.addBoth(self._got_response, peer, shares_to_ask)
|
||||||
return d
|
return d
|
||||||
elif self.contacted_peers:
|
elif len(self.contacted_peers) > 1:
|
||||||
# ask a peer that we've already asked.
|
# ask a peer that we've already asked.
|
||||||
num_shares = mathutil.div_ceil(len(self.homeless_shares),
|
|
||||||
len(self.contacted_peers))
|
|
||||||
shares_to_ask = set(self.homeless_shares[:num_shares])
|
|
||||||
self.homeless_shares[:num_shares] = []
|
|
||||||
peer = self.contacted_peers.pop(0)
|
peer = self.contacted_peers.pop(0)
|
||||||
|
if peer == "start":
|
||||||
|
# we're at the beginning of the list, so re-calculate
|
||||||
|
# shares_per_peer
|
||||||
|
num_shares = mathutil.div_ceil(len(self.homeless_shares),
|
||||||
|
len(self.contacted_peers))
|
||||||
|
self.shares_per_peer = num_shares
|
||||||
|
self.contacted_peers.append("start")
|
||||||
|
peer = self.contacted_peers.pop(0)
|
||||||
|
shares_to_ask = set(self.homeless_shares[:self.shares_per_peer])
|
||||||
|
self.homeless_shares[:self.shares_per_peer] = []
|
||||||
self.query_count += 1
|
self.query_count += 1
|
||||||
d = peer.query(shares_to_ask)
|
d = peer.query(shares_to_ask)
|
||||||
d.addBoth(self._got_response, peer, shares_to_ask)
|
d.addBoth(self._got_response, peer, shares_to_ask)
|
||||||
|
@ -231,7 +237,7 @@ class Tahoe2PeerSelector:
|
||||||
log.msg("%s got error during peer selection: %s" % (peer, res))
|
log.msg("%s got error during peer selection: %s" % (peer, res))
|
||||||
self.error_count += 1
|
self.error_count += 1
|
||||||
self.homeless_shares = list(shares_to_ask) + self.homeless_shares
|
self.homeless_shares = list(shares_to_ask) + self.homeless_shares
|
||||||
if self.uncontacted_peers or self.contacted_peers:
|
if self.uncontacted_peers or len(self.contacted_peers) > 1:
|
||||||
# there is still hope, so just loop
|
# there is still hope, so just loop
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue