:py:mod:`oioioi.rankings.models` ================================ .. py:module:: oioioi.rankings.models Module Contents --------------- Classes ~~~~~~~ .. autoapisummary:: oioioi.rankings.models.RankingRecalc oioioi.rankings.models.Ranking oioioi.rankings.models.RankingPage Functions ~~~~~~~~~ .. autoapisummary:: oioioi.rankings.models.clamp oioioi.rankings.models.choose_for_recalculation oioioi.rankings.models.save_pages oioioi.rankings.models.save_recalc_results oioioi.rankings.models.recalculate .. py:class:: RankingRecalc(*args, **kwargs) Bases: :py:obj:`django.db.models.Model` Make subclasses preserve the alters_data attribute on overridden methods. .. py:class:: Ranking(*args, **kwargs) Bases: :py:obj:`django.db.models.Model` Represents the state (i.e. is it up to date) and data (both in serialized and html formats) for a single ranking. For the purposes of this class, we identify the ranking by its contest and key. The generated ranking must NOT depend on the request or any other ranking. This class is responsible only for dealing with WHEN to recalculate and to store the serialized data and html for the ranking. Anything beyond that should be delegated to RankingController. Invalidation is handled explicitly. We assume our ranking is valid, until someone else (probably ContestController and friends) tells us that something changed. Then the ranking is marked as invalid (not up to date) with the help of invalidate_* methods. We use _cooldown_ strategy of recalculation. Anytime we regenerate ranking we set a cooldown, based on how much time the previous recalculation took. If the ranking is invalidated during the cooldown period, we don't recalculate until the cooldown period is over. Consider the following example of how cooldowns work: 1) 00:01 - First invalidation event. The ranking is invalid. 2) 00:02 - The recalculation starts. It didn't start immediately at the time of invalidation, because daemon polls for the rankings needing regeneration so it needed some time to notice. 3) 00:12 - The recalculation ends, duration was 10 seconds. Ranking is up to date now. 4) 01:00 - Second invalidation event. Ranking is invalid. 5) 01:01 - Second recalculation starts. Let's assume RANKING_COOLDOWN_FACTOR = 2. Then the cooldown is 20 seconds, until 01:21 6) 01:03 - Third invalidation event. 7) 01:05 - Fourth invalidation event. 7) 01:08 - Ranking recalculation initiated by the second event ends. Ranking is still invalid, because of the third event. It took 7 seconds. 8) 01:21 - Cooldown is over. We recalculate ranking because of 3rd and 4th events. The new cooldown is set for 14 seconds, until 01:35. 9) 01:30 - The recalculation ends. The cooldowns can be configured by setting: RANKING_COOLDOWN_FACTOR - how long should the cooldown be, related to the last recalculation. RANKING_MIN_COOLDOWN - minimum cooldown duration (safety limit) RANKING_MAX_COOLDOWN - maximum cooldown duration (safety limit) NOTE: We use the local time (and not the database time), for all time calculations, including the cooldowns, so be careful about drastic changes of system time on the generating machine. .. py:class:: Meta Bases: :py:obj:`object` .. py:attribute:: unique_together :annotation: = ['contest', 'key'] .. py:property:: serialized Serialized data of this ranking .. py:attribute:: contest .. py:attribute:: key .. py:attribute:: invalidation_date .. py:attribute:: last_recalculation_date .. py:attribute:: last_recalculation_duration .. py:attribute:: serialized_data .. py:attribute:: needs_recalculation .. py:attribute:: cooldown_date .. py:attribute:: recalc_in_progress .. py:method:: controller() RankingController of the contest .. py:method:: invalidate_queryset(qs) :classmethod: Marks queryset of rankings as invalid .. py:method:: invalidate_contest(contest) :classmethod: Marks all the keys in the constest as invalid .. py:method:: is_up_to_date() Is all the data for this contest up to date (i.e. not invalidated since the last recalculation succeeded)? If it is not up_to_date we still guarantee that the data is in consistent state from the last recalculation. .. py:class:: RankingPage(*args, **kwargs) Bases: :py:obj:`django.db.models.Model` Single page of a ranking .. py:attribute:: ranking .. py:attribute:: nr .. py:attribute:: data .. py:function:: clamp(minimum, x, maximum) .. py:function:: choose_for_recalculation() .. py:function:: save_pages(ranking, pages_list) .. py:function:: save_recalc_results(recalc, date_before, date_after, serialized, pages_list) .. py:function:: recalculate(recalc)