Example #1
0
    def _save_and_flush_and_response_when_ready(self):
        # need to deactivate cache, in case after_all_players_arrive
        # finished running after the moment set_attributes
        # was called in this request.

        # because in response_when_ready we will call
        # increment_index_in_pages, which does a look-ahead and calls
        # is_displayed() on the following pages. is_displayed() might
        # depend on a field that is set in after_all_players_arrive
        # so, need to clear the cache to ensure
        # that we get fresh data.

        # Note: i was never able to reproduce this myself -- just heard
        # from Anthony N.
        # and it shouldn't happen, because only the last player to visit
        # can set is_ready(). if there is a request coming after that,
        # then it must be someone refreshing the page manually.
        # i guess we should protect against that.

        # is_displayed() could also depend on a field on participant
        # that was set on the wait page, so need to refresh participant,
        # because it is passed as an arg to set_attributes().


        otree.db.idmap.save_objects()
        idmap.flush()
        return self._response_when_ready()
Example #2
0
    def test_flush_db1(self):

        c1 = Category.objects.using('db1').get(pk=1)
        c2 = Category.objects.using('db2').get(pk=1)

        flush(db='db1')

        self.assertIsNot(c1, Category.objects.using('db1').get(pk=1))
        self.assertIs(c2, Category.objects.using('db2').get(pk=1))
Example #3
0
def deactivate_cache():
    '''
    The Idmap cache is always being populated, even if it's not "active"
    We just ignore its contents.
    It doesn't look like idmap has a way to turn it off entirely.
    '''
    _toggle.is_active = False
    # 2017-08-07: flush both in activate and deactivate, just to be sure
    # i was getting some unexpected behavior in tests, when a test without
    # IDmap ran after a test with IDmap
    idmap.flush()
Example #4
0
    def test_flush_all(self):

        # make a list of Articles and SubArticles so that they're in cache
        list(Article.objects.all())
        sub_pks = [sa.pk for sa in SubArticle.objects.all()]

        # should flush Article and SubArticle's caches
        flush()

        for pk in sub_pks:
            self.assertIsNone(SubArticle.get_cached_instance(pk))
Example #5
0
    def test_flush_all(self):

        c0 = Category.objects.get(pk=1)
        c1 = Category.objects.using('db1').get(pk=1)
        c2 = Category.objects.using('db2').get(pk=1)

        flush()

        self.assertIsNot(c0, Category.objects.get(pk=1))
        self.assertIsNot(c1, Category.objects.using('db1').get(pk=1))
        self.assertIsNot(c2, Category.objects.using('db2').get(pk=1))
Example #6
0
def deactivate_cache():
    '''
    The Idmap cache is always being populated, even if it's not "active"
    We just ignore its contents.
    It doesn't look like idmap has a way to turn it off entirely.
    '''
    _toggle.is_active = False
    # 2017-08-07: flush both in activate and deactivate, just to be sure
    # i was getting some unexpected behavior in tests, when a test without
    # IDmap ran after a test with IDmap
    idmap.flush()
Example #7
0
def activate_cache():
    idmap.flush()
    _toggle.is_active = True
Example #8
0
 def _pre_setup(self):
     super(TestCase, self)._pre_setup()
     flush()
Example #9
0
 def test_refresh_from_db_after_flush(self):
     flush()
     self.cat.refresh_from_db()
     cached_c = Category.get_cached_instance(pk=self.cat.pk)
     self.assertIsNotNone(cached_c)
Example #10
0
 def test_flat_values_list_after_flush(self):
     cat_pk = self.cat.pk
     flush()
     self.assertEqual(
         Category.objects.values_list('name', flat=True).get(pk=cat_pk),
         'Category 0')
Example #11
0
    def inner_dispatch(self, *args, **kwargs):
        ## EARLY EXITS
        if self._was_completed():
            return self._save_and_flush_and_response_when_ready()
        is_displayed = self.is_displayed()
        if self.group_by_arrival_time and not is_displayed:
            # in GBAT, either all players should skip a page, or none should.
            # we don't support some players skipping and others not.
            return self._response_when_ready()

        if is_displayed and not self.group_by_arrival_time:
            if self._get_unvisited_ids():
                self.participant.is_on_wait_page = True
                return self._get_wait_page()
        ## END EARLY EXITS

        with get_redis_lock(name='otree_waitpage') or wait_page_thread_lock:
            # setting myself to _gbat_arrived = True should happen inside the lock
            # because otherwise, another player might be able to see that I have arrived
            # before I can run get_players_for_group, and they might end up grouping
            # me. But because I am not in their group, they will not run AAPA for me
            # so I will be considered 'already_grouped' and redirected to a wait page,
            # and AAPA will never be run.

            # also, it's simpler in general to have a broad lock.
            # and easier to explain to users that it will be run as each player
            # arrives.

            if self.group_by_arrival_time:
                self.player._gbat_arrived = True
                # _last_request_timestamp is already set in set_attributes,
                # but set it here just so we can guarantee
                self.participant._last_request_timestamp = time.time()
                # we call save_objects() below

            otree.db.idmap.save_objects()
            idmap.flush()

            # make a clean copy for GBAT and AAPA
            # self.player and self.participant etc are undefined
            # and no objects are cached inside it
            # and it doesn't affect the current instance
            wp = type(self)() # type: WaitPage
            wp.set_attributes_waitpage_clone(original_view=self)


            # needs to happen before calculating participant_pk_set
            # because this can change the group or PK
            if wp.group_by_arrival_time:
                wp._player_access_forbidden = Undefined_GetPlayersForGroup()
                wp._participant_access_forbidden = Undefined_GetPlayersForGroup()
                wp._group_access_forbidden = Undefined_GetPlayersForGroup()

                # check if the player was already grouped.
                # this is a 'check' of the check-then-act, so it needs to be
                # inside the lock.
                # It's possible that the player
                # was grouped, but the Completion object does not exist yet,
                # because aapa was not run.
                already_grouped = type(self.player).objects.filter(
                    id=self.player.id).values_list(
                    '_gbat_grouped', flat=True)[0]
                if already_grouped:
                    regrouped = False
                else:
                    regrouped = wp._gbat_try_to_regroup()

                if not regrouped:
                    self.participant.is_on_wait_page = True
                    return self._get_wait_page()

                wp._player_access_forbidden = None
                wp._participant_access_forbidden = None
                wp._group_access_forbidden = None

            # the group membership might be modified
            # in after_all_players_arrive, so calculate this first
            participant_pk_set = set(
                self._group_or_subsession.player_set
                .values_list('participant__pk', flat=True))

            if not self._was_completed():
                if is_displayed:
                    # if any player can skip the wait page,
                    # then we shouldn't run after_all_players_arrive
                    # because if some players are able to proceed to the next page
                    # before after_all_players_arrive is run,
                    # then after_all_players_arrive is probably not essential.
                    # often, there are some wait pages that all players skip,
                    # because they should only be shown in certain rounds.
                    # maybe the fields that after_all_players_arrive depends on
                    # are null
                    # something to think about: ideally, should we check if
                    # all players skipped, or any player skipped?
                    # as a shortcut, we just check if is_displayed is true
                    # for the last player.

                    wp._player_access_forbidden = Undefined_AfterAllPlayersArrive_Player()
                    wp._participant_access_forbidden = Undefined_AfterAllPlayersArrive_Player()
                    if wp.wait_for_all_groups:
                        wp._group_access_forbidden = Undefined_AfterAllPlayersArrive_Group()
                    else:
                        wp._group_access_forbidden = None
                        wp._group_for_aapa = self.group
                    wp.after_all_players_arrive()
                    # need to save to the results of after_all_players_arrive
                    # to the DB, before sending the completion message to other players
                    # this was causing a race condition on 2016-11-04
                    otree.db.idmap.save_objects()
                # even if this player skips the page and after_all_players_arrive
                # is not run, we need to indicate that the waiting players can advance
                self._mark_completed()
                self.send_completion_message(participant_pk_set)
        return self._save_and_flush_and_response_when_ready()
Example #12
0
def activate_cache():
    idmap.flush()
    _toggle.is_active = True