.. _performance.rst: performance.rst
.. _mutable.rst: specifications/mutable.rst
+``peers.preferred = (string, optional)``
+
+ This is an optional comma-separated list of Node IDs of servers that will
+ be tried first when selecting storage servers for reading or writing.
+
+ Servers should be identified here by their Node ID as it appears in the web
+ ui, underneath the server's nickname. For storage servers running tahoe
+ versions >=1.10 (if the introducer is also running tahoe >=1.10) this will
+ be a "Node Key" (which is prefixed with 'v0-'). For older nodes, it will be
+ a TubID instead. When a preferred server (and/or the introducer) is
+ upgraded to 1.10 or later, clients must adjust their configs accordingly.
+
+ Every node selected for upload, whether preferred or not, will still
+ receive the same number of shares (one, if there are ``N`` or more servers
+ accepting uploads). Preferred nodes are simply moved to the front of the
+ server selection lists computed for each file.
+
+ This is useful if a subset of your nodes have different availability or
+ connectivity characteristics than the rest of the grid. For instance, if
+ there are more than ``N`` servers on the grid, and ``K`` or more of them
+ are at a single physical location, it would make sense for clients at that
+ location to prefer their local servers so that they can maintain access to
+ all of their uploads without using the internet.
+
+
Frontend Configuration
======================
def init_client_storage_broker(self):
# create a StorageFarmBroker object, for use by Uploader/Downloader
# (and everybody else who wants to use storage servers)
- sb = storage_client.StorageFarmBroker(self.tub, permute_peers=True)
+ ps = self.get_config("client", "peers.preferred", "").split(",")
+ preferred_peers = tuple([p.strip() for p in ps if p != ""])
+ sb = storage_client.StorageFarmBroker(self.tub, permute_peers=True, preferred_peers=preferred_peers)
self.storage_broker = sb
# load static server specifications from tahoe.cfg, if any.
I'm also responsible for subscribing to the IntroducerClient to find out
about new servers as they are announced by the Introducer.
"""
- def __init__(self, tub, permute_peers):
+ def __init__(self, tub, permute_peers, preferred_peers=()):
self.tub = tub
assert permute_peers # False not implemented yet
self.permute_peers = permute_peers
+ self.preferred_peers = preferred_peers
# self.servers maps serverid -> IServer, and keeps track of all the
# storage servers that we've heard about. Each descriptor manages its
# own Reconnector, and will give us a RemoteReference when we ask
def get_servers_for_psi(self, peer_selection_index):
# return a list of server objects (IServers)
assert self.permute_peers == True
+ connected_servers = self.get_connected_servers()
+ preferred_servers = frozenset(s for s in connected_servers if s.get_longname() in self.preferred_peers)
def _permuted(server):
seed = server.get_permutation_seed()
- return sha1(peer_selection_index + seed).digest()
- return sorted(self.get_connected_servers(), key=_permuted)
+ is_unpreferred = server not in preferred_servers
+ return (is_unpreferred, sha1(peer_selection_index + seed).digest())
+ return sorted(connected_servers, key=_permuted)
def get_all_serverids(self):
return frozenset(self.servers.keys())
sb.servers.clear()
self.failUnlessReallyEqual(self._permute(sb, "one"), [])
+ def test_permute_with_preferred(self):
+ sb = StorageFarmBroker(None, True, ['1','4'])
+ for k in ["%d" % i for i in range(5)]:
+ ann = {"anonymous-storage-FURL": "pb://abcde@nowhere/fake",
+ "permutation-seed-base32": base32.b2a(k) }
+ sb.test_add_rref(k, "rref", ann)
+
+ self.failUnlessReallyEqual(self._permute(sb, "one"), ['1','4','3','0','2'])
+ self.failUnlessReallyEqual(self._permute(sb, "two"), ['4','1','0','2','3'])
+ sb.servers.clear()
+ self.failUnlessReallyEqual(self._permute(sb, "one"), [])
+
def test_versions(self):
basedir = "test_client.Basic.test_versions"
os.mkdir(basedir)