stats: added IStatsProducer interface, fixed stats provider startup
authorrobk-tahoe <robk-tahoe@allmydata.com>
Fri, 1 Feb 2008 04:10:15 +0000 (21:10 -0700)
committerrobk-tahoe <robk-tahoe@allmydata.com>
Fri, 1 Feb 2008 04:10:15 +0000 (21:10 -0700)
this adds an interface, IStatsProducer, defining the get_stats() method
which the stats provider calls upon and registered producer, and made the
register_producer() method check that interface is implemented.

also refine the startup logic, so that the stats provider doesn't try and
connect out to the stats gatherer until after the node declares the tub
'ready'.  this is to address an issue whereby providers would attach to
the gatherer without providing a valid furl, and hence the gatherer would
be unable to determine the tubid of the connected client, leading to lost
samples.

src/allmydata/client.py
src/allmydata/interfaces.py
src/allmydata/stats.py
src/allmydata/storage.py

index 65a49a58785504da36c1d9c6813a80322aedf3c8..92ea6fa2dd51dc005835c4c0162a3b1b31cd85aa 100644 (file)
@@ -84,8 +84,7 @@ class Client(node.Node, Referenceable, testutil.PollMixin):
     def init_stats_provider(self):
         gatherer_furl = self.get_config('stats_gatherer.furl')
         if gatherer_furl:
-            nickname = self.get_config('nickname')
-            self.stats_provider = StatsProvider(self.tub, nickname, gatherer_furl)
+            self.stats_provider = StatsProvider(self, gatherer_furl)
             self.add_service(self.stats_provider)
         else:
             self.stats_provider = None
index 0ea9d3bdd16b18ae52107119f331822a5e53fb92..c65af491229b5162fbc8cd2c2afaf29613628bb7 100644 (file)
@@ -1341,3 +1341,10 @@ class RIStatsGatherer(RemoteInterface):
         return None
 
 
+class IStatsProducer(Interface):
+    def get_stats():
+        """
+        returns a dictionary, with str keys representing the names of stats
+        to be monitored, and numeric values.
+        """
+
index dbdaf79e5990268c3250b6714102164a1a4cadcc..7e3c64f6fc5a35cb1c4ed3f1f3dc39fd04eba8e2 100644 (file)
@@ -14,9 +14,11 @@ import foolscap
 from foolscap.logging.gatherer import get_local_ip_for
 
 from allmydata.util import log
-from allmydata.interfaces import RIStatsProvider, RIStatsGatherer
+from allmydata.interfaces import RIStatsProvider, RIStatsGatherer, IStatsProducer
 
 class LoadMonitor(service.MultiService):
+    implements(IStatsProducer)
+
     loop_interval = 1
     num_samples = 60
 
@@ -65,8 +67,9 @@ class LoadMonitor(service.MultiService):
 class StatsProvider(foolscap.Referenceable, service.MultiService):
     implements(RIStatsProvider)
 
-    def __init__(self, tub, nickname, gatherer_furl):
+    def __init__(self, node, gatherer_furl):
         service.MultiService.__init__(self)
+        self.node = node
         self.gatherer_furl = gatherer_furl
 
         self.counters = {}
@@ -76,15 +79,20 @@ class StatsProvider(foolscap.Referenceable, service.MultiService):
         self.load_monitor.setServiceParent(self)
         self.register_producer(self.load_monitor)
 
-        if tub:
-            tub.connectTo(gatherer_furl, self._connected_to_gatherer, nickname)
+    def startService(self):
+        if self.node:
+            d = self.node.when_tub_ready()
+            def connect(junk):
+                nickname = self.node.get_config('nickname')
+                self.node.tub.connectTo(self.gatherer_furl, self._connected, nickname)
+            d.addCallback(connect)
 
     def count(self, name, delta):
         val = self.counters.setdefault(name, 0)
         self.counters[name] = val + delta
 
     def register_producer(self, stats_producer):
-        self.stats_producers.append(stats_producer)
+        self.stats_producers.append(IStatsProducer(stats_producer))
 
     def remote_get_stats(self):
         stats = {}
@@ -92,7 +100,7 @@ class StatsProvider(foolscap.Referenceable, service.MultiService):
             stats.update(sp.get_stats())
         return { 'counters': self.counters, 'stats': stats }
 
-    def _connected_to_gatherer(self, gatherer, nickname):
+    def _connected(self, gatherer, nickname):
         gatherer.callRemote('provide', self, nickname or '')
 
 class StatsGatherer(foolscap.Referenceable, service.MultiService):
index b2ac17e8d194adac20c80b05c0fd95d3aa225675..49fa7eae857976040390d91d0a91f280344c250a 100644 (file)
@@ -8,7 +8,7 @@ from twisted.internet import defer
 from zope.interface import implements
 from allmydata.interfaces import RIStorageServer, RIBucketWriter, \
      RIBucketReader, IStorageBucketWriter, IStorageBucketReader, HASH_SIZE, \
-     BadWriteEnablerError
+     BadWriteEnablerError, IStatsProducer
 from allmydata.util import fileutil, idlib, mathutil, log
 from allmydata.util.assertutil import precondition, _assert
 
@@ -666,7 +666,7 @@ def create_mutable_sharefile(filename, my_nodeid, write_enabler, parent):
 
 
 class StorageServer(service.MultiService, Referenceable):
-    implements(RIStorageServer)
+    implements(RIStorageServer, IStatsProducer)
     name = 'storageserver'
 
     def __init__(self, storedir, sizelimit=None, no_storage=False, stats_provider=None):