[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r22556: {arm} added: observed bandwidth fetched from self descriptor fix: (in arm/trunk: interface/graphing util)
Author: atagar
Date: 2010-06-26 22:03:30 +0000 (Sat, 26 Jun 2010)
New Revision: 22556
Modified:
arm/trunk/interface/graphing/bandwidthStats.py
arm/trunk/interface/graphing/graphPanel.py
arm/trunk/util/torTools.py
Log:
added: observed bandwidth fetched from self descriptor
fix: crashing issue when graph collapsed too much
Modified: arm/trunk/interface/graphing/bandwidthStats.py
===================================================================
--- arm/trunk/interface/graphing/bandwidthStats.py 2010-06-26 16:10:01 UTC (rev 22555)
+++ arm/trunk/interface/graphing/bandwidthStats.py 2010-06-26 22:03:30 UTC (rev 22556)
@@ -4,6 +4,7 @@
"""
import time
+from TorCtl import TorCtl
import graphPanel
from util import torTools, uiTools
@@ -19,6 +20,59 @@
DEFAULT_CONFIG = {"features.graph.bw.showAccounting": True, "features.graph.bw.isAccountingTimeLong": False}
+class ObservedBandwidthTracker(TorCtl.PostEventListener):
+ """
+ This keeps track of the relay's current observed bandwidth (the throughput
+ noted by the directory authorities and used by clients for relay selection).
+ This is a parameter of the descriptors and hence is likely to get stale.
+ """
+
+ def __init__(self):
+ TorCtl.PostEventListener.__init__(self)
+ self.observedBandwidth = None
+
+ conn = torTools.getConn()
+ conn.addEventListener(self) # listenes for NEWDESC events
+ conn.addStatusListener(self.resetListener) # listens for new controllers
+
+ self._parseDescriptors()
+
+ def getObservedBandwidth(self):
+ """
+ Reports the observed bandwidth noted in the cached descriptors. This
+ provides None if descriptors are unavailable or otherwise unable to be
+ parsed.
+ """
+
+ return self.observedBandwidth
+
+ def new_desc_event(self, event):
+ self._parseDescriptors()
+
+ def _parseDescriptors(self):
+ conn = torTools.getConn()
+ myFingerprint = conn.getInfo("fingerprint")
+ myDescLines = []
+
+ if myFingerprint:
+ myDesc = conn.getInfo("desc/id/%s" % myFingerprint)
+ if myDesc: myDescLines = myDesc.split("\n")
+
+ for line in myDescLines:
+ if line.startswith("bandwidth"):
+ # line should look something like:
+ # bandwidth 40960 102400 47284
+ comp = line.split()
+
+ if len(comp) == 4 and comp[-1].isdigit():
+ self.observedBandwidth = uiTools.getSizeLabel(int(comp[-1]), 1)
+ return
+
+ self.observedBandwidth = None # no bandwidth desc entry found
+
+ def resetListener(self, conn, eventType):
+ if eventType == torTools.TOR_INIT: self._parseDescriptors()
+
class BandwidthStats(graphPanel.GraphStats):
"""
Uses tor BW events to generate bandwidth usage graph.
@@ -30,6 +84,8 @@
self._config = dict(DEFAULT_CONFIG)
if config: config.update(self._config)
+ self.observedBwTracker = ObservedBandwidthTracker()
+
# accounting data (set by _updateAccountingInfo method)
self.accountingInfo = dict([(arg, "") for arg in ACCOUNTING_ARGS])
@@ -121,24 +177,18 @@
panel.addfstr(10, 0, "<b>Accounting:</b> Connection Closed...")
def getTitle(self, width):
- # provides label, dropping stats if there's not enough room
- capLabel = "cap: %s" % self.bwRate if self.bwRate else ""
- burstLabel = "burst: %s" % self.bwBurst if self.bwBurst else ""
+ stats, observedBw = [], self.observedBwTracker.getObservedBandwidth()
+ if self.bwRate: stats.append("limit: %s" % self.bwRate)
+ if self.bwBurst: stats.append("burst: %s" % self.bwBurst)
+ if observedBw: stats.append("observed: %s" % observedBw)
- if capLabel and burstLabel:
- bwLabel = " (%s, %s)" % (capLabel, burstLabel)
- elif capLabel or burstLabel:
- # only one is set - use whatever's avaialble
- bwLabel = " (%s%s)" % (capLabel, burstLabel)
- else:
- bwLabel = ""
-
- labelContents = "Bandwidth%s:" % bwLabel
- if width < len(labelContents):
- labelContents = "%s):" % labelContents[:labelContents.find(",")] # removes burst measure
- if width < len(labelContents): labelContents = "Bandwidth:" # removes both
-
- return labelContents
+ while True:
+ if not stats: return "Bandwidth:"
+ else:
+ label = "Bandwidth (%s):" % ", ".join(stats)
+
+ if len(label) > width: del stats[-1]
+ else: return label
def getHeaderLabel(self, width, isPrimary):
graphType = "Downloaded" if isPrimary else "Uploaded"
Modified: arm/trunk/interface/graphing/graphPanel.py
===================================================================
--- arm/trunk/interface/graphing/graphPanel.py 2010-06-26 16:10:01 UTC (rev 22555)
+++ arm/trunk/interface/graphing/graphPanel.py 2010-06-26 22:03:30 UTC (rev 22556)
@@ -266,8 +266,12 @@
secondaryMaxBound = param.maxSecondary[self.updateInterval]
else:
# both BOUNDS_LOCAL_MAX and BOUNDS_TIGHT use local maxima
- primaryMaxBound = max(param.primaryCounts[self.updateInterval][1:graphCol + 1])
- secondaryMaxBound = max(param.secondaryCounts[self.updateInterval][1:graphCol + 1])
+ if graphCol < 2:
+ # nothing being displayed
+ primaryMaxBound, secondaryMaxBound = 0, 0
+ else:
+ primaryMaxBound = max(param.primaryCounts[self.updateInterval][1:graphCol + 1])
+ secondaryMaxBound = max(param.secondaryCounts[self.updateInterval][1:graphCol + 1])
primaryMinBound = secondaryMinBound = 0
if self.bounds == BOUNDS_TIGHT:
Modified: arm/trunk/util/torTools.py
===================================================================
--- arm/trunk/util/torTools.py 2010-06-26 16:10:01 UTC (rev 22555)
+++ arm/trunk/util/torTools.py 2010-06-26 22:03:30 UTC (rev 22556)
@@ -256,7 +256,8 @@
TorCtl.PostEventListener.__init__(self)
self.conn = None # None if uninitialized or controller's been closed
self.connLock = threading.RLock()
- self.listeners = [] # callback functions for tor's state changes
+ self.eventListeners = [] # instances listening for tor controller events
+ self.statusListeners = [] # callback functions for tor's state changes
self.controllerEvents = {} # mapping of successfully set controller events to their failure level/msg
self._isReset = False # internal flag for tracking resets
self._status = TOR_CLOSED # current status of the attached control port
@@ -445,6 +446,21 @@
return (self._status, self._statusTime)
+ def addEventListener(self, listener):
+ """
+ Directs further tor controller events to callback functions of the
+ listener. If a new control connection is initialized then this listener is
+ reattached.
+
+ Arguments:
+ listener - TorCtl.PostEventListener instance listening for events
+ """
+
+ self.connLock.acquire()
+ self.eventListeners.append(listener)
+ if self.isAlive(): self.conn.add_event_listener(listener)
+ self.connLock.release()
+
def addStatusListener(self, callback):
"""
Directs further events related to tor's controller status to the callback
@@ -455,7 +471,7 @@
myFunction(controller, eventType)
"""
- self.listeners.append(callback)
+ self.statusListeners.append(callback)
def removeStatusListener(self, callback):
"""
@@ -466,8 +482,8 @@
callback - functor to be removed
"""
- if callback in self.listeners:
- self.listeners.remove(callback)
+ if callback in self.statusListeners:
+ self.statusListeners.remove(callback)
return True
else: return False
@@ -647,6 +663,6 @@
eventType - enum representing tor's new status
"""
- for callback in self.listeners:
+ for callback in self.statusListeners:
callback(self, eventType)