From 4e5b9ee63eb63f186ab7d03201359be4b3ece18e Mon Sep 17 00:00:00 2001 From: Brian Warner Date: Wed, 18 Jun 2008 17:04:41 -0700 Subject: [PATCH] introducer: move the relevant interfaces out to introducer/interfaces.py --- src/allmydata/interfaces.py | 135 ----------------------- src/allmydata/introducer/client.py | 3 +- src/allmydata/introducer/interfaces.py | 141 +++++++++++++++++++++++++ src/allmydata/introducer/old.py | 5 +- src/allmydata/introducer/server.py | 3 +- 5 files changed, 147 insertions(+), 140 deletions(-) create mode 100644 src/allmydata/introducer/interfaces.py diff --git a/src/allmydata/interfaces.py b/src/allmydata/interfaces.py index 8dac6fb6..64650472 100644 --- a/src/allmydata/interfaces.py +++ b/src/allmydata/interfaces.py @@ -24,141 +24,6 @@ ReadSize = int # the 'int' constraint is 2**31 == 2Gib -- large files are proces LeaseRenewSecret = Hash # used to protect bucket lease renewal requests LeaseCancelSecret = Hash # used to protect bucket lease cancellation requests -# Announcements are (FURL, service_name, remoteinterface_name, -# nickname, my_version, oldest_supported) -# the (FURL, service_name, remoteinterface_name) refer to the service being -# announced. The (nickname, my_version, oldest_supported) refer to the -# client as a whole. The my_version/oldest_supported strings can be parsed -# by an allmydata.util.version.Version instance, and then compared. The -# first goal is to make sure that nodes are not confused by speaking to an -# incompatible peer. The second goal is to enable the development of -# backwards-compatibility code. - -Announcement = TupleOf(FURL, str, str, - str, str, str) - -class RIIntroducerSubscriberClient(RemoteInterface): - __remote_name__ = "RIIntroducerSubscriberClient.tahoe.allmydata.com" - - def announce(announcements=SetOf(Announcement)): - """I accept announcements from the publisher.""" - return None - - def set_encoding_parameters(parameters=(int, int, int)): - """Advise the client of the recommended k-of-n encoding parameters - for this grid. 'parameters' is a tuple of (k, desired, n), where 'n' - is the total number of shares that will be created for any given - file, while 'k' is the number of shares that must be retrieved to - recover that file, and 'desired' is the minimum number of shares that - must be placed before the uploader will consider its job a success. - n/k is the expansion ratio, while k determines the robustness. - - Introducers should specify 'n' according to the expected size of the - grid (there is no point to producing more shares than there are - peers), and k according to the desired reliability-vs-overhead goals. - - Note that setting k=1 is equivalent to simple replication. - """ - return None - -# When Foolscap can handle multiple interfaces (Foolscap#17), the -# full-powered introducer will implement both RIIntroducerPublisher and -# RIIntroducerSubscriberService. Until then, we define -# RIIntroducerPublisherAndSubscriberService as a combination of the two, and -# make everybody use that. - -class RIIntroducerPublisher(RemoteInterface): - """To publish a service to the world, connect to me and give me your - announcement message. I will deliver a copy to all connected subscribers.""" - __remote_name__ = "RIIntroducerPublisher.tahoe.allmydata.com" - - def publish(announcement=Announcement): - # canary? - return None - -class RIIntroducerSubscriberService(RemoteInterface): - __remote_name__ = "RIIntroducerSubscriberService.tahoe.allmydata.com" - - def subscribe(subscriber=RIIntroducerSubscriberClient, service_name=str): - """Give me a subscriber reference, and I will call its new_peers() - method will any announcements that match the desired service name. I - will ignore duplicate subscriptions. - """ - return None - -class RIIntroducerPublisherAndSubscriberService(RemoteInterface): - __remote_name__ = "RIIntroducerPublisherAndSubscriberService.tahoe.allmydata.com" - def publish(announcement=Announcement): - return None - def subscribe(subscriber=RIIntroducerSubscriberClient, service_name=str): - return None - -class IIntroducerClient(Interface): - """I provide service introduction facilities for a node. I help nodes - publish their services to the rest of the world, and I help them learn - about services available on other nodes.""" - - def publish(furl, service_name, remoteinterface_name): - """Once you call this, I will tell the world that the Referenceable - available at FURL is available to provide a service named - SERVICE_NAME. The precise definition of the service being provided is - identified by the Foolscap 'remote interface name' in the last - parameter: this is supposed to be a globally-unique string that - identifies the RemoteInterface that is implemented.""" - - def subscribe_to(service_name): - """Call this if you will eventually want to use services with the - given SERVICE_NAME. This will prompt me to subscribe to announcements - of those services. You can pick up the announcements later by calling - get_all_connections_for() or get_permuted_peers(). - """ - - def get_all_connections(): - """Return a frozenset of (nodeid, service_name, rref) tuples, one for - each active connection we've established to a remote service. This is - mostly useful for unit tests that need to wait until a certain number - of connections have been made.""" - - def get_all_connectors(): - """Return a dict that maps from (nodeid, service_name) to a - RemoteServiceConnector instance for all services that we are actively - trying to connect to. Each RemoteServiceConnector has the following - public attributes:: - - service_name: the type of service provided, like 'storage' - announcement_time: when we first heard about this service - last_connect_time: when we last established a connection - last_loss_time: when we last lost a connection - - version: the peer's version, from the most recent connection - oldest_supported: the peer's oldest supported version, same - - rref: the RemoteReference, if connected, otherwise None - remote_host: the IAddress, if connected, otherwise None - - This method is intended for monitoring interfaces, such as a web page - which describes connecting and connected peers. - """ - - def get_all_peerids(): - """Return a frozenset of all peerids to whom we have a connection (to - one or more services) established. Mostly useful for unit tests.""" - - def get_all_connections_for(service_name): - """Return a frozenset of (nodeid, service_name, rref) tuples, one - for each active connection that provides the given SERVICE_NAME.""" - - def get_permuted_peers(service_name, key): - """Returns an ordered list of (peerid, rref) tuples, selecting from - the connections that provide SERVICE_NAME, using a hash-based - permutation keyed by KEY. This randomizes the service list in a - repeatable way, to distribute load over many peers. - """ - - def connected_to_introducer(): - """Returns a boolean, True if we are currently connected to the - introducer, False if not.""" - class RIStubClient(RemoteInterface): """Each client publishes a service announcement for a dummy object called the StubClient. This object doesn't actually offer any services, but the diff --git a/src/allmydata/introducer/client.py b/src/allmydata/introducer/client.py index 008aff10..59a74341 100644 --- a/src/allmydata/introducer/client.py +++ b/src/allmydata/introducer/client.py @@ -4,7 +4,8 @@ from base64 import b32decode from zope.interface import implements from twisted.application import service from foolscap import Referenceable -from allmydata.interfaces import RIIntroducerSubscriberClient, IIntroducerClient +from allmydata.introducer.interfaces import RIIntroducerSubscriberClient, \ + IIntroducerClient from allmydata.util import log, idlib from allmydata.introducer.common import make_index diff --git a/src/allmydata/introducer/interfaces.py b/src/allmydata/introducer/interfaces.py new file mode 100644 index 00000000..d084f498 --- /dev/null +++ b/src/allmydata/introducer/interfaces.py @@ -0,0 +1,141 @@ + +from zope.interface import Interface +from foolscap.schema import StringConstraint, TupleOf, SetOf +from foolscap import RemoteInterface +FURL = StringConstraint(1000) + +# Announcements are (FURL, service_name, remoteinterface_name, +# nickname, my_version, oldest_supported) +# the (FURL, service_name, remoteinterface_name) refer to the service being +# announced. The (nickname, my_version, oldest_supported) refer to the +# client as a whole. The my_version/oldest_supported strings can be parsed +# by an allmydata.util.version.Version instance, and then compared. The +# first goal is to make sure that nodes are not confused by speaking to an +# incompatible peer. The second goal is to enable the development of +# backwards-compatibility code. + +Announcement = TupleOf(FURL, str, str, + str, str, str) + +class RIIntroducerSubscriberClient(RemoteInterface): + __remote_name__ = "RIIntroducerSubscriberClient.tahoe.allmydata.com" + + def announce(announcements=SetOf(Announcement)): + """I accept announcements from the publisher.""" + return None + + def set_encoding_parameters(parameters=(int, int, int)): + """Advise the client of the recommended k-of-n encoding parameters + for this grid. 'parameters' is a tuple of (k, desired, n), where 'n' + is the total number of shares that will be created for any given + file, while 'k' is the number of shares that must be retrieved to + recover that file, and 'desired' is the minimum number of shares that + must be placed before the uploader will consider its job a success. + n/k is the expansion ratio, while k determines the robustness. + + Introducers should specify 'n' according to the expected size of the + grid (there is no point to producing more shares than there are + peers), and k according to the desired reliability-vs-overhead goals. + + Note that setting k=1 is equivalent to simple replication. + """ + return None + +# When Foolscap can handle multiple interfaces (Foolscap#17), the +# full-powered introducer will implement both RIIntroducerPublisher and +# RIIntroducerSubscriberService. Until then, we define +# RIIntroducerPublisherAndSubscriberService as a combination of the two, and +# make everybody use that. + +class RIIntroducerPublisher(RemoteInterface): + """To publish a service to the world, connect to me and give me your + announcement message. I will deliver a copy to all connected subscribers.""" + __remote_name__ = "RIIntroducerPublisher.tahoe.allmydata.com" + + def publish(announcement=Announcement): + # canary? + return None + +class RIIntroducerSubscriberService(RemoteInterface): + __remote_name__ = "RIIntroducerSubscriberService.tahoe.allmydata.com" + + def subscribe(subscriber=RIIntroducerSubscriberClient, service_name=str): + """Give me a subscriber reference, and I will call its new_peers() + method will any announcements that match the desired service name. I + will ignore duplicate subscriptions. + """ + return None + +class RIIntroducerPublisherAndSubscriberService(RemoteInterface): + __remote_name__ = "RIIntroducerPublisherAndSubscriberService.tahoe.allmydata.com" + def publish(announcement=Announcement): + return None + def subscribe(subscriber=RIIntroducerSubscriberClient, service_name=str): + return None + +class IIntroducerClient(Interface): + """I provide service introduction facilities for a node. I help nodes + publish their services to the rest of the world, and I help them learn + about services available on other nodes.""" + + def publish(furl, service_name, remoteinterface_name): + """Once you call this, I will tell the world that the Referenceable + available at FURL is available to provide a service named + SERVICE_NAME. The precise definition of the service being provided is + identified by the Foolscap 'remote interface name' in the last + parameter: this is supposed to be a globally-unique string that + identifies the RemoteInterface that is implemented.""" + + def subscribe_to(service_name): + """Call this if you will eventually want to use services with the + given SERVICE_NAME. This will prompt me to subscribe to announcements + of those services. You can pick up the announcements later by calling + get_all_connections_for() or get_permuted_peers(). + """ + + def get_all_connections(): + """Return a frozenset of (nodeid, service_name, rref) tuples, one for + each active connection we've established to a remote service. This is + mostly useful for unit tests that need to wait until a certain number + of connections have been made.""" + + def get_all_connectors(): + """Return a dict that maps from (nodeid, service_name) to a + RemoteServiceConnector instance for all services that we are actively + trying to connect to. Each RemoteServiceConnector has the following + public attributes:: + + service_name: the type of service provided, like 'storage' + announcement_time: when we first heard about this service + last_connect_time: when we last established a connection + last_loss_time: when we last lost a connection + + version: the peer's version, from the most recent connection + oldest_supported: the peer's oldest supported version, same + + rref: the RemoteReference, if connected, otherwise None + remote_host: the IAddress, if connected, otherwise None + + This method is intended for monitoring interfaces, such as a web page + which describes connecting and connected peers. + """ + + def get_all_peerids(): + """Return a frozenset of all peerids to whom we have a connection (to + one or more services) established. Mostly useful for unit tests.""" + + def get_all_connections_for(service_name): + """Return a frozenset of (nodeid, service_name, rref) tuples, one + for each active connection that provides the given SERVICE_NAME.""" + + def get_permuted_peers(service_name, key): + """Returns an ordered list of (peerid, rref) tuples, selecting from + the connections that provide SERVICE_NAME, using a hash-based + permutation keyed by KEY. This randomizes the service list in a + repeatable way, to distribute load over many peers. + """ + + def connected_to_introducer(): + """Returns a boolean, True if we are currently connected to the + introducer, False if not.""" + diff --git a/src/allmydata/introducer/old.py b/src/allmydata/introducer/old.py index b586b0c1..7aaa345c 100644 --- a/src/allmydata/introducer/old.py +++ b/src/allmydata/introducer/old.py @@ -8,12 +8,11 @@ from base64 import b32decode from zope.interface import implements from twisted.application import service from foolscap import Referenceable -from allmydata.interfaces import RIIntroducerSubscriberClient, IIntroducerClient from allmydata.util import log, idlib +from allmydata.introducer.interfaces import RIIntroducerSubscriberClient, \ + IIntroducerClient, RIIntroducerPublisherAndSubscriberService from allmydata.introducer.common import make_index -from allmydata.interfaces import RIIntroducerPublisherAndSubscriberService - class RemoteServiceConnector: """I hold information about a peer service that we want to connect to. If we are connected, I hold the RemoteReference, the peer's address, and the diff --git a/src/allmydata/introducer/server.py b/src/allmydata/introducer/server.py index 35c1087e..a6d028b8 100644 --- a/src/allmydata/introducer/server.py +++ b/src/allmydata/introducer/server.py @@ -4,8 +4,9 @@ from zope.interface import implements from twisted.application import service from foolscap import Referenceable from allmydata import node -from allmydata.interfaces import RIIntroducerPublisherAndSubscriberService from allmydata.util import log +from allmydata.introducer.interfaces import \ + RIIntroducerPublisherAndSubscriberService from allmydata.introducer.common import make_index class IntroducerNode(node.Node): -- 2.37.2