mirror of
https://github.com/codex-storage/deluge.git
synced 2025-02-02 22:53:40 +00:00
[Core] Refactor session status code
Simplify the methods by initialising the session_status dict using libtorrent session_stats_metrics and rate keys. Instead of first looking for deprecated keys use exception then lookup. Added a few more tests.
This commit is contained in:
parent
d8b1e2701c
commit
f93e5e60b5
@ -49,7 +49,7 @@ except ImportError:
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
OLD_SESSION_STATUS_KEYS = {
|
DEPR_SESSION_STATUS_KEYS = {
|
||||||
# 'active_requests': None, # In dht_stats_alert, if required.
|
# 'active_requests': None, # In dht_stats_alert, if required.
|
||||||
'allowed_upload_slots': 'ses.num_unchoke_slots',
|
'allowed_upload_slots': 'ses.num_unchoke_slots',
|
||||||
# 'dht_global_nodes': None,
|
# 'dht_global_nodes': None,
|
||||||
@ -81,9 +81,7 @@ OLD_SESSION_STATUS_KEYS = {
|
|||||||
# 'utp_stats': None
|
# 'utp_stats': None
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: replace with dynamic rate e.g.
|
# Session status rate keys associated with session status counters.
|
||||||
# 'dht.dht_bytes_in'.replace('_bytes', '') + '_rate'
|
|
||||||
# would become 'dht.dht_in_rate'
|
|
||||||
SESSION_RATES_MAPPING = {
|
SESSION_RATES_MAPPING = {
|
||||||
'dht_download_rate': 'dht.dht_bytes_in',
|
'dht_download_rate': 'dht.dht_bytes_in',
|
||||||
'dht_upload_rate': 'dht.dht_bytes_out',
|
'dht_upload_rate': 'dht.dht_bytes_out',
|
||||||
@ -180,11 +178,18 @@ class Core(component.Component):
|
|||||||
self.__new_release = None
|
self.__new_release = None
|
||||||
|
|
||||||
# Session status timer
|
# Session status timer
|
||||||
self.session_status = {}
|
self.session_status = {k.name: 0 for k in lt.session_stats_metrics()}
|
||||||
|
self._session_prev_bytes = {k: 0 for k in SESSION_RATES_MAPPING}
|
||||||
|
# Initiate other session status keys.
|
||||||
|
self.session_status.update(self._session_prev_bytes)
|
||||||
|
hit_ratio_keys = ['write_hit_ratio', 'read_hit_ratio']
|
||||||
|
self.session_status.update({k: 0.0 for k in hit_ratio_keys})
|
||||||
|
|
||||||
self.session_status_timer_interval = 0.5
|
self.session_status_timer_interval = 0.5
|
||||||
self.session_status_timer = task.LoopingCall(self.session.post_session_stats)
|
self.session_status_timer = task.LoopingCall(
|
||||||
self.alertmanager.register_handler('session_stats_alert', self._on_alert_session_stats)
|
self.session.post_session_stats)
|
||||||
self._session_rates = {(k_rate, k_bytes): 0 for k_rate, k_bytes in SESSION_RATES_MAPPING.items()}
|
self.alertmanager.register_handler(
|
||||||
|
'session_stats_alert', self._on_alert_session_stats)
|
||||||
self.session_rates_timer_interval = 2
|
self.session_rates_timer_interval = 2
|
||||||
self.session_rates_timer = task.LoopingCall(self._update_session_rates)
|
self.session_rates_timer = task.LoopingCall(self._update_session_rates)
|
||||||
|
|
||||||
@ -323,38 +328,39 @@ class Core(component.Component):
|
|||||||
|
|
||||||
def _on_alert_session_stats(self, alert):
|
def _on_alert_session_stats(self, alert):
|
||||||
"""The handler for libtorrent session stats alert"""
|
"""The handler for libtorrent session stats alert"""
|
||||||
if not self.session_status:
|
|
||||||
# Empty dict on startup so needs populated with session rate keys and default value.
|
|
||||||
self.session_status.update({key: 0 for key in list(SESSION_RATES_MAPPING)})
|
|
||||||
self.session_status.update(alert.values)
|
self.session_status.update(alert.values)
|
||||||
self._update_session_cache_hit_ratio()
|
self._update_session_cache_hit_ratio()
|
||||||
|
|
||||||
def _update_session_cache_hit_ratio(self):
|
def _update_session_cache_hit_ratio(self):
|
||||||
"""Calculates the cache read/write hit ratios and updates session_status"""
|
"""Calculates the cache read/write hit ratios for session_status."""
|
||||||
try:
|
blocks_written = self.session_status['disk.num_blocks_written']
|
||||||
self.session_status['write_hit_ratio'] = ((self.session_status['disk.num_blocks_written'] -
|
blocks_read = self.session_status['disk.num_blocks_read']
|
||||||
self.session_status['disk.num_write_ops']) /
|
|
||||||
self.session_status['disk.num_blocks_written'])
|
if blocks_written:
|
||||||
except ZeroDivisionError:
|
self.session_status['write_hit_ratio'] = (
|
||||||
|
blocks_written - self.session_status['disk.num_write_ops']
|
||||||
|
) / blocks_written
|
||||||
|
else:
|
||||||
self.session_status['write_hit_ratio'] = 0.0
|
self.session_status['write_hit_ratio'] = 0.0
|
||||||
|
|
||||||
try:
|
if blocks_read:
|
||||||
self.session_status['read_hit_ratio'] = (self.session_status['disk.num_blocks_cache_hits'] /
|
self.session_status['read_hit_ratio'] = (
|
||||||
self.session_status['disk.num_blocks_read'])
|
self.session_status['disk.num_blocks_cache_hits'] / blocks_read
|
||||||
except ZeroDivisionError:
|
)
|
||||||
|
else:
|
||||||
self.session_status['read_hit_ratio'] = 0.0
|
self.session_status['read_hit_ratio'] = 0.0
|
||||||
|
|
||||||
def _update_session_rates(self):
|
def _update_session_rates(self):
|
||||||
"""Calculates status rates based on interval and value difference for session_status"""
|
"""Calculate session status rates.
|
||||||
if not self.session_status:
|
|
||||||
return
|
|
||||||
|
|
||||||
for (rate_key, status_key), prev_bytes in list(self._session_rates.items()):
|
Uses polling interval and counter difference for session_status rates.
|
||||||
new_bytes = self.session_status[status_key]
|
"""
|
||||||
byte_rate = (new_bytes - prev_bytes) / self.session_rates_timer_interval
|
for rate_key, prev_bytes in list(self._session_prev_bytes.items()):
|
||||||
self.session_status[rate_key] = byte_rate
|
new_bytes = self.session_status[SESSION_RATES_MAPPING[rate_key]]
|
||||||
|
self.session_status[rate_key] = (
|
||||||
|
new_bytes - prev_bytes) / self.session_rates_timer_interval
|
||||||
# Store current value for next update.
|
# Store current value for next update.
|
||||||
self._session_rates[(rate_key, status_key)] = new_bytes
|
self._session_prev_bytes[rate_key] = new_bytes
|
||||||
|
|
||||||
def get_new_release(self):
|
def get_new_release(self):
|
||||||
log.debug('get_new_release')
|
log.debug('get_new_release')
|
||||||
@ -600,24 +606,24 @@ class Core(component.Component):
|
|||||||
:rtype: dict
|
:rtype: dict
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not self.session_status:
|
|
||||||
return {key: 0 for key in keys}
|
|
||||||
|
|
||||||
if not keys:
|
if not keys:
|
||||||
return self.session_status
|
return self.session_status
|
||||||
|
|
||||||
status = {}
|
status = {}
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in OLD_SESSION_STATUS_KEYS:
|
|
||||||
new_key = OLD_SESSION_STATUS_KEYS[key]
|
|
||||||
log.warning('Using deprecated session status key %s, please use %s', key, new_key)
|
|
||||||
status[key] = self.session_status[new_key]
|
|
||||||
else:
|
|
||||||
try:
|
try:
|
||||||
status[key] = self.session_status[key]
|
status[key] = self.session_status[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
log.warning('Session status key does not exist: %s', key)
|
if key in DEPR_SESSION_STATUS_KEYS:
|
||||||
|
new_key = DEPR_SESSION_STATUS_KEYS[key]
|
||||||
|
log.debug(
|
||||||
|
'Deprecated session status key %s, please use %s',
|
||||||
|
key,
|
||||||
|
new_key,
|
||||||
|
)
|
||||||
|
status[key] = self.session_status[new_key]
|
||||||
|
else:
|
||||||
|
log.warning('Session status key not valid: %s', key)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
@export
|
@export
|
||||||
|
@ -378,13 +378,33 @@ class CoreTestCase(BaseTestCase):
|
|||||||
self.assertEqual(val[1], ('invalidid2', 'torrent_id invalidid2 not in session.'))
|
self.assertEqual(val[1], ('invalidid2', 'torrent_id invalidid2 not in session.'))
|
||||||
|
|
||||||
def test_get_session_status(self):
|
def test_get_session_status(self):
|
||||||
|
status = self.core.get_session_status(
|
||||||
|
['net.recv_tracker_bytes', 'net.sent_tracker_bytes'])
|
||||||
|
self.assertIsInstance(status, dict)
|
||||||
|
self.assertEqual(status['net.recv_tracker_bytes'], 0)
|
||||||
|
self.assertEqual(status['net.sent_tracker_bytes'], 0)
|
||||||
|
|
||||||
|
def test_get_session_status_all(self):
|
||||||
|
status = self.core.get_session_status([])
|
||||||
|
self.assertIsInstance(status, dict)
|
||||||
|
self.assertIn('upload_rate', status)
|
||||||
|
self.assertIn('net.recv_bytes', status)
|
||||||
|
|
||||||
|
def test_get_session_status_depr(self):
|
||||||
|
status = self.core.get_session_status(['num_peers', 'num_unchoked'])
|
||||||
|
self.assertIsInstance(status, dict)
|
||||||
|
self.assertEqual(status['num_peers'], 0)
|
||||||
|
self.assertEqual(status['num_unchoked'], 0)
|
||||||
|
|
||||||
|
def test_get_session_status_rates(self):
|
||||||
status = self.core.get_session_status(['upload_rate', 'download_rate'])
|
status = self.core.get_session_status(['upload_rate', 'download_rate'])
|
||||||
self.assertEqual(type(status), dict)
|
self.assertIsInstance(status, dict)
|
||||||
self.assertEqual(status['upload_rate'], 0.0)
|
self.assertEqual(status['upload_rate'], 0)
|
||||||
|
|
||||||
def test_get_session_status_ratio(self):
|
def test_get_session_status_ratio(self):
|
||||||
status = self.core.get_session_status(['write_hit_ratio', 'read_hit_ratio'])
|
status = self.core.get_session_status([
|
||||||
self.assertEqual(type(status), dict)
|
'write_hit_ratio', 'read_hit_ratio'])
|
||||||
|
self.assertIsInstance(status, dict)
|
||||||
self.assertEqual(status['write_hit_ratio'], 0.0)
|
self.assertEqual(status['write_hit_ratio'], 0.0)
|
||||||
self.assertEqual(status['read_hit_ratio'], 0.0)
|
self.assertEqual(status['read_hit_ratio'], 0.0)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user