diff --git a/src/allmydata/client.py b/src/allmydata/client.py
index 1e4479b..239fdc1 100644
a
|
b
|
class Client(node.Node, pollmixin.PollMixin): |
213 | 213 | sk,vk_vs = keyutil.parse_privkey(sk_vs.strip()) |
214 | 214 | self.write_config("node.pubkey", vk_vs+"\n") |
215 | 215 | self._server_key = sk |
| 216 | self.node_key_s = vk_vs |
216 | 217 | |
217 | 218 | def _init_permutation_seed(self, ss): |
218 | 219 | seed = self.get_config_from_file("permutation-seed") |
diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py
index b1c34a7..b925552 100644
a
|
b
|
class IServer(IDisplayableServer): |
444 | 444 | def start_connecting(tub, trigger_cb): |
445 | 445 | pass |
446 | 446 | def get_rref(): |
447 | | pass |
| 447 | """Once a server is connected, I return a RemoteReference. |
| 448 | Before a server is connected for the first time, I return None. |
| 449 | |
| 450 | Note that the rref I return will start producing DeadReferenceErrors |
| 451 | once the connection is lost. |
| 452 | """ |
448 | 453 | |
449 | 454 | |
450 | 455 | class IMutableSlotWriter(Interface): |
diff --git a/src/allmydata/storage_client.py b/src/allmydata/storage_client.py
index 68823f0..b536c67 100644
a
|
b
|
class StorageFarmBroker: |
77 | 77 | def test_add_rref(self, serverid, rref, ann): |
78 | 78 | s = NativeStorageServer(serverid, ann.copy()) |
79 | 79 | s.rref = rref |
| 80 | s._is_connected = True |
80 | 81 | self.servers[serverid] = s |
81 | 82 | |
82 | 83 | def test_add_server(self, serverid, s): |
… |
… |
class StorageFarmBroker: |
129 | 130 | return frozenset(self.servers.keys()) |
130 | 131 | |
131 | 132 | def get_connected_servers(self): |
132 | | return frozenset([s for s in self.servers.values() if s.get_rref()]) |
| 133 | return frozenset([s for s in self.servers.values() if s.is_connected()]) |
133 | 134 | |
134 | 135 | def get_known_servers(self): |
135 | 136 | return frozenset(self.servers.values()) |
… |
… |
class NativeStorageServer: |
215 | 216 | self.last_loss_time = None |
216 | 217 | self.remote_host = None |
217 | 218 | self.rref = None |
| 219 | self._is_connected = False |
218 | 220 | self._reconnector = None |
219 | 221 | self._trigger_cb = None |
220 | 222 | |
… |
… |
class NativeStorageServer: |
254 | 256 | return self.announcement |
255 | 257 | def get_remote_host(self): |
256 | 258 | return self.remote_host |
| 259 | def is_connected(self): |
| 260 | return self._is_connected |
257 | 261 | def get_last_connect_time(self): |
258 | 262 | return self.last_connect_time |
259 | 263 | def get_last_loss_time(self): |
… |
… |
class NativeStorageServer: |
287 | 291 | self.last_connect_time = time.time() |
288 | 292 | self.remote_host = rref.getPeer() |
289 | 293 | self.rref = rref |
| 294 | self._is_connected = True |
290 | 295 | rref.notifyOnDisconnect(self._lost) |
291 | 296 | |
292 | 297 | def get_rref(self): |
… |
… |
class NativeStorageServer: |
296 | 301 | log.msg(format="lost connection to %(name)s", name=self.get_name(), |
297 | 302 | facility="tahoe.storage_broker", umid="zbRllw") |
298 | 303 | self.last_loss_time = time.time() |
299 | | self.rref = None |
| 304 | # self.rref is now stale: all callRemote()s will get a |
| 305 | # DeadReferenceError. We leave the stale reference in place so that |
| 306 | # uploader/downloader code (which received this IServer through |
| 307 | # get_connected_servers() or get_servers_for_psi()) can continue to |
| 308 | # use s.get_rref().callRemote() and not worry about it being None. |
| 309 | self._is_connected = False |
300 | 310 | self.remote_host = None |
301 | 311 | |
302 | 312 | def stop_connecting(self): |
diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
index f3d618d..a9d20ea 100644
a
|
b
|
class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): |
1883 | 1883 | return d |
1884 | 1884 | d.addCallback(_got_lit_filenode) |
1885 | 1885 | return d |
| 1886 | |
| 1887 | class Connections(SystemTestMixin, unittest.TestCase): |
| 1888 | def test_rref(self): |
| 1889 | self.basedir = "system/Connections/rref" |
| 1890 | d = self.set_up_nodes(2) |
| 1891 | def _start(ign): |
| 1892 | self.c0 = self.clients[0] |
| 1893 | for s in self.c0.storage_broker.get_connected_servers(): |
| 1894 | if "pub-"+s.get_longname() != self.c0.node_key_s: |
| 1895 | break |
| 1896 | self.s1 = s # s1 is the server, not c0 |
| 1897 | self.s1_rref = s.get_rref() |
| 1898 | self.failIfEqual(self.s1_rref, None) |
| 1899 | self.failUnless(self.s1.is_connected()) |
| 1900 | d.addCallback(_start) |
| 1901 | |
| 1902 | # now shut down the server |
| 1903 | d.addCallback(lambda ign: self.clients[1].disownServiceParent()) |
| 1904 | # and wait for the client to notice |
| 1905 | def _poll(): |
| 1906 | return len(self.c0.storage_broker.get_connected_servers()) < 2 |
| 1907 | d.addCallback(lambda ign: self.poll(_poll)) |
| 1908 | |
| 1909 | def _down(ign): |
| 1910 | self.failIf(self.s1.is_connected()) |
| 1911 | rref = self.s1.get_rref() |
| 1912 | self.failUnless(rref) |
| 1913 | self.failUnlessIdentical(rref, self.s1_rref) |
| 1914 | d.addCallback(_down) |
| 1915 | return d |