GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Commit c7c91370 authored by juga  's avatar juga 💬

chg: relayprioritizer: Count priorities with timestamps

in RelayPrioritizer:
- Rename recent_priority_list_count to recent_priority_list when
  there is no counting
- Rename recent_priority_relay_count to recent_priority_relay
  when there is no counting
- Use the timestamps class to manage/count priority lists/relays
parent 89801c53
......@@ -6,7 +6,8 @@ import copy
import time
import logging
from ..util import state
from ..globals import MAX_RECENT_PRIORITY_RELAY_COUNT
from ..util import state, timestamps
log = logging.getLogger(__name__)
......@@ -24,30 +25,39 @@ class RelayPrioritizer:
self.fraction_to_return = conf.getfloat(
'relayprioritizer', 'fraction_relays')
self._state = state.State(conf.getpath('paths', 'state_fname'))
if self._state is not None:
# If it was not in previous state versions, initialize it to 0
if self._state.get('recent_priority_list_count', None) is None:
self._state['recent_priority_list_count'] = 0
if self._state.get('recent_priority_relay_count') is None:
self._state['recent_priority_relay_count'] = 0
def increment_priority_lists(self):
self._recent_priority_list = timestamps.DateTimeSeq(
[], 120, self._state, "recent_priority_list"
)
self._recent_priority_relay = timestamps.DateTimeIntSeq(
[], MAX_RECENT_PRIORITY_RELAY_COUNT, self._state,
"recent_priority_relay"
)
def increment_recent_priority_list(self):
"""
Increment the number of times that
:meth:`~sbws.lib.relayprioritizer.RelayPrioritizer.best_priority`
has been run.
"""
# NOTE: blocking, writes to file!
self._state['recent_priority_list_count'] += 1
self._recent_priority_list.update()
def increment_priority_relays(self, relays_count):
@property
def recent_priority_list_count(self):
return len(self._recent_priority_list)
def increment_recent_priority_relay(self, relays_count):
"""
Increment the number of relays that have been "prioritized" to be
measured in a
:meth:`~sbws.lib.relayprioritizer.RelayPrioritizer.best_priority`.
"""
# NOTE: blocking, writes to file!
self._state['recent_priority_relay_count'] += relays_count
self._recent_priority_relay.update(number=relays_count)
@property
def recent_priority_relay_count(self):
return len(self._recent_priority_relay)
def best_priority(self, prioritize_result_error=False,
return_fraction=True):
......@@ -141,11 +151,11 @@ class RelayPrioritizer:
upper_limit = cutoff if return_fraction else len(relays)
# NOTE: these two are blocking, write to disk
# Increment the number of times ``best_priority`` has been run.
self.increment_priority_lists()
self.increment_recent_priority_list()
# Increment the number of relays that have been "prioritized".
# Because in a small testing network the upper limit could be smaller
# than the number of relays in the network, use the length of the list.
self.increment_priority_relays(len(relays[0:upper_limit]))
self.increment_recent_priority_relay(len(relays[0:upper_limit]))
for relay in relays[0:upper_limit]:
log.debug('Returning next relay %s with priority %f',
relay.nickname, relay.priority)
......
......@@ -481,7 +481,7 @@ class V3BWHeader(object):
in the recent (by default 5) days from the state file.
"""
state = State(state_fpath)
return state.get('recent_priority_list_count', None)
return state.count('recent_priority_list')
@staticmethod
def recent_priority_relay_count_from_file(state_fpath):
......@@ -490,7 +490,7 @@ class V3BWHeader(object):
in the recent (by default 5) days from the state file.
"""
state = State(state_fpath)
return state.get('recent_priority_relay_count', None)
return state.count('recent_priority_relay')
@staticmethod
def latest_bandwidth_from_results(results):
......
......@@ -5,6 +5,10 @@ from unittest import mock
from stem import descriptor
from sbws import settings
from sbws.lib import relaylist
from sbws.lib import relayprioritizer
from sbws.lib import resultdump
from sbws.util.parser import create_parser
......@@ -87,3 +91,29 @@ def controller_5days_later(router_statuses_5days_later):
controller = mock.Mock()
controller.get_network_statuses.return_value = router_statuses_5days_later
return controller
# Because of the function scoped `args` in `tests.unit.conftest`, this has to
# be function scoped too.
@pytest.fixture(scope='function')
def relay_list(args, conf, controller):
"""Returns a RelayList containing the Relays in the controller"""
return relaylist.RelayList(args, conf, controller)
@pytest.fixture(scope='function')
def result_dump(args, conf):
"""Returns a ResultDump without Results"""
# To stop the thread that would be waiting for new results
settings.set_end_event()
return resultdump.ResultDump(args, conf)
@pytest.fixture(scope="function")
def relay_prioritizer(args, conf_results, relay_list, result_dump):
"""
Returns a RelayPrioritizer with a RelayList and a ResultDump.
"""
return relayprioritizer.RelayPrioritizer(
args, conf_results, relay_list, result_dump
)
......@@ -187,6 +187,17 @@ def conf(sbwshome_empty, tmpdir):
return conf
@pytest.fixture(scope='function')
def conf_results(sbwshome_success_result_two_relays, conf):
"""Minimal configuration having a datadir
So that `ResultDump` does not raise AssertionError.
"""
conf['paths']['sbws_home'] = sbwshome_success_result_two_relays
return conf
@pytest.fixture()
def result():
return RESULT
......
"""relayprioritizer.py unit tests."""
from freezegun import freeze_time
def test_increment_recent_priority_list(relay_prioritizer):
"""Test that incrementing the priority lists do not go on forever.
And instead it only counts the number of priority lists in the last days.
"""
state = relay_prioritizer._state
assert 0 == relay_prioritizer.recent_priority_list_count
assert not state.get("recent_priority_list", None)
# Pretend that a priority list is made.
with freeze_time("2020-02-29 10:00:00"):
relay_prioritizer.increment_recent_priority_list()
assert 1 == relay_prioritizer.recent_priority_list_count
assert 1 == len(state["recent_priority_list"])
# And a second priority list is made 4 days later.
with freeze_time("2020-03-04 10:00:00"):
relay_prioritizer.increment_recent_priority_list()
assert 2 == relay_prioritizer.recent_priority_list_count
assert 2 == len(state["recent_priority_list"])
# And a third priority list is made 5 days later.
with freeze_time("2020-03-05 10:00:00"):
relay_prioritizer.increment_recent_priority_list()
assert 3 == relay_prioritizer.recent_priority_list_count
assert 3 == len(state["recent_priority_list"])
# And a fourth priority list is made 6 days later. The first one is
# now removed and not counted.
with freeze_time("2020-03-06 10:00:00"):
relay_prioritizer.increment_recent_priority_list()
assert 3 == relay_prioritizer.recent_priority_list_count
assert 3 == len(state["recent_priority_list"])
def test_increment_priority_relay(relay_prioritizer):
"""Test that incrementing the number of relays in the priority lists
do not go on forever.
And instead it only counts number of relays in priority lists in the last
days.
"""
state = relay_prioritizer._state
assert 0 == relay_prioritizer.recent_priority_relay_count
assert not state.get("recent_priority_relay", None)
# Pretend that a priority list is made.
with freeze_time("2020-02-29 10:00:00"):
relay_prioritizer.increment_recent_priority_relay(2)
assert 2 == relay_prioritizer.recent_priority_relay_count
assert 2 == state.count("recent_priority_relay")
# And a second priority list is made 4 days later.
with freeze_time("2020-03-04 10:00:00"):
relay_prioritizer.increment_recent_priority_relay(2)
assert 4 == relay_prioritizer.recent_priority_relay_count
assert 4 == state.count("recent_priority_relay")
# And a third priority list is made 5 days later.
with freeze_time("2020-03-05 10:00:00"):
relay_prioritizer.increment_recent_priority_relay(2)
assert 6 == relay_prioritizer.recent_priority_relay_count
assert 6 == state.count("recent_priority_relay")
# And a fourth priority list is made 6 days later. The first one is
# now removed and the relays are not counted.
with freeze_time("2020-03-06 10:00:00"):
relay_prioritizer.increment_recent_priority_relay(2)
assert 6 == relay_prioritizer.recent_priority_relay_count
assert 6 == state.count("recent_priority_relay")
......@@ -551,3 +551,23 @@ def test_recent_measurement_attempt_count(root_data_path, datadir):
results = load_result_file(str(datadir.join("results.txt")))
header = V3BWHeader.from_results(results, '', '', state_fpath)
assert "15" == header.recent_measurement_attempt_count
def test_recent_priority_list_count(root_data_path, datadir):
# This state has recent_priority_list
state_fpath = os.path.join(root_data_path, '.sbws/state.dat')
assert 1 == V3BWHeader.recent_priority_list_count_from_file(state_fpath)
# `results` does not matter here, using them to don't have an empty list.
results = load_result_file(str(datadir.join("results.txt")))
header = V3BWHeader.from_results(results, '', '', state_fpath)
assert "1" == header.recent_priority_list_count
def test_recent_priority_relay_count(root_data_path, datadir):
# This state has recent_priority_relay_count
state_fpath = os.path.join(root_data_path, '.sbws/state.dat')
assert 15 == V3BWHeader.recent_priority_relay_count_from_file(state_fpath)
# `results` does not matter here, using them to don't have an empty list.
results = load_result_file(str(datadir.join("results.txt")))
header = V3BWHeader.from_results(results, '', '', state_fpath)
assert "15" == header.recent_priority_relay_count
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment