]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
new feature: preferred storage servers
authorLeif Ryge <leif@synthesize.us>
Tue, 16 Apr 2013 06:59:10 +0000 (06:59 +0000)
committerLeif Ryge <leif@synthesize.us>
Sat, 22 Nov 2014 20:01:11 +0000 (20:01 +0000)
docs/configuration.rst
src/allmydata/client.py
src/allmydata/storage_client.py
src/allmydata/test/test_client.py

index 26d8c58bb92c280322440898ece65184e9492a57..79272a41ca8355ffef47759df3bbf447bb096a82 100644 (file)
@@ -386,6 +386,24 @@ Client Configuration
 .. _performance.rst: performance.rst
 .. _mutable.rst: specifications/mutable.rst
 
+``peers.preferred = (string, optional)``
+
+    This is an optional comma-separated list of storage server node IDs that
+    will be tried first when selecting storage servers for reading or writing.
+
+    Every selected node, 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
 ======================
 
index 64b09c076c2b06d8f8963b383eef2c0941367cad..e06dad667fbf580ee82bfe55fe64aa9f59df3767 100644 (file)
@@ -342,7 +342,8 @@ class Client(node.Node, pollmixin.PollMixin):
     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)
+        preferred_peers = [p.strip() for p in self.get_config("client", "peers.preferred", "").split(",") 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.
index 39753e0cb79396dceb16f1b6c1cc2d16f6110794..4a6d6928b37cdfdbe26d7bc5c7c08dda3b8beb27 100644 (file)
@@ -62,10 +62,11 @@ class StorageFarmBroker:
     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
@@ -124,7 +125,10 @@ class StorageFarmBroker:
         def _permuted(server):
             seed = server.get_permutation_seed()
             return sha1(peer_selection_index + seed).digest()
-        return sorted(self.get_connected_servers(), key=_permuted)
+        connected_servers = self.get_connected_servers()
+        preferred_servers = frozenset([s for s in connected_servers if s.get_longname() in self.preferred_peers])
+        unpreferred_servers = connected_servers - preferred_servers
+        return sorted(preferred_servers, key=_permuted) + sorted(unpreferred_servers, key=_permuted)
 
     def get_all_serverids(self):
         return frozenset(self.servers.keys())
index 531215f6129cfbf53f1c1bbe96e3be15a410b0e1..104f064f135a746a6d32598c3f402ea8876ea294 100644 (file)
@@ -6,7 +6,7 @@ import allmydata
 from allmydata.node import Node, OldConfigError, OldConfigOptionError, MissingConfigEntry, UnescapedHashError
 from allmydata import client
 from allmydata.storage_client import StorageFarmBroker
-from allmydata.util import base32, fileutil
+from allmydata.util import base32, fileutil, idlib
 from allmydata.interfaces import IFilesystemNode, IFileNode, \
      IImmutableFileNode, IMutableFileNode, IDirectoryNode
 from foolscap.api import flushEventualQueue
@@ -177,7 +177,7 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase):
         return [ s.get_longname() for s in sb.get_servers_for_psi(key) ]
 
     def test_permute(self):
-        sb = StorageFarmBroker(None, True)
+        sb = StorageFarmBroker(None, True, [])
         for k in ["%d" % i for i in range(5)]:
             ann = {"anonymous-storage-FURL": "pb://abcde@nowhere/fake",
                    "permutation-seed-base32": base32.b2a(k) }
@@ -188,6 +188,16 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase):
         sb.servers.clear()
         self.failUnlessReallyEqual(self._permute(sb, "one"), [])
 
+    def test_permute_with_preferred(self):
+        sb = StorageFarmBroker(None, True, map(idlib.nodeid_b2a, ['1','4']))
+        for k in ["%d" % i for i in range(5)]:
+            sb.test_add_rref(k, "rref")
+
+        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)