mirror of
https://github.com/zulip/zulip.git
synced 2025-11-04 22:13:26 +00:00
message_fetch: Take a REPEATABLE READ READ ONLY when fetching messages.
This commit is contained in:
committed by
Tim Abbott
parent
0f521fba41
commit
9a682fb20a
@@ -1,6 +1,8 @@
|
||||
from typing import Dict, Iterable, List, Optional, Tuple, Union
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.db import connection, transaction
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.html import escape as escape_html
|
||||
from django.utils.translation import gettext as _
|
||||
@@ -169,6 +171,31 @@ def get_messages_backend(
|
||||
assert log_data is not None
|
||||
log_data["extra"] = "[{}]".format(",".join(verbose_operators))
|
||||
|
||||
with transaction.atomic(durable=True):
|
||||
# We're about to perform a search, and then get results from
|
||||
# it; this is done across multiple queries. To prevent race
|
||||
# conditions, we want the messages returned to be consistent
|
||||
# with the version of the messages that was searched, to
|
||||
# prevent changes which happened between them from leaking to
|
||||
# clients who should not be able to see the new values, and
|
||||
# when messages are deleted in between. We set up
|
||||
# repeatable-read isolation for this transaction, so that we
|
||||
# prevent both phantom reads and non-repeatable reads.
|
||||
#
|
||||
# In a read-only repeatable-read transaction, it is not
|
||||
# possible to encounter deadlocks or need retries due to
|
||||
# serialization errors.
|
||||
#
|
||||
# You can only set the isolation level before any queries in
|
||||
# the transaction, meaning it must be the top-most
|
||||
# transaction, which durable=True establishes. Except in
|
||||
# tests, where durable=True is a lie, because there is an
|
||||
# outer transaction for each test. We thus skip this command
|
||||
# in tests, since it would fail.
|
||||
if not settings.TEST_SUITE: # nocoverage
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY")
|
||||
|
||||
query_info = fetch_messages(
|
||||
narrow=narrow,
|
||||
user_profile=user_profile,
|
||||
@@ -205,7 +232,9 @@ def get_messages_backend(
|
||||
message_ids = [row[0] for row in rows]
|
||||
|
||||
# TODO: This could be done with an outer join instead of two queries
|
||||
um_rows = UserMessage.objects.filter(user_profile=user_profile, message_id__in=message_ids)
|
||||
um_rows = UserMessage.objects.filter(
|
||||
user_profile=user_profile, message_id__in=message_ids
|
||||
)
|
||||
user_message_flags = {um.message_id: um.flags_list() for um in um_rows}
|
||||
|
||||
for message_id in message_ids:
|
||||
|
||||
Reference in New Issue
Block a user