mirror of https://github.com/zulip/zulip.git
Remove subscriptions using bulk queries.
This improves the performance of unsubscribing to N streams by more than a factor of 10 for large N. (imported from commit a529e6d3ac4452f49c2294908d275280019bbd05)
This commit is contained in:
parent
7f3fded612
commit
74fd508b2f
|
@ -635,6 +635,50 @@ def do_add_subscription(user_profile, stream, no_log=False):
|
|||
notify_new_subscription(user_profile, stream, subscription, no_log)
|
||||
return did_subscribe
|
||||
|
||||
def notify_subscription_removed(user_profile, stream, no_log=False):
|
||||
if not no_log:
|
||||
log_event({'type': 'subscription_removed',
|
||||
'user': user_profile.email,
|
||||
'name': stream.name,
|
||||
'domain': stream.realm.domain})
|
||||
|
||||
notice = dict(event=dict(type="subscription", op="remove",
|
||||
subscription=dict(name=stream.name)),
|
||||
users=[user_profile.id])
|
||||
tornado_callbacks.send_notification(notice)
|
||||
|
||||
def bulk_remove_subscriptions(users, streams):
|
||||
recipients_map = bulk_get_recipients(Recipient.STREAM,
|
||||
[stream.id for stream in streams])
|
||||
stream_map = {}
|
||||
for stream in streams:
|
||||
stream_map[recipients_map[stream.id].id] = stream
|
||||
|
||||
subs_by_user = dict((user_profile.id, []) for user_profile in users)
|
||||
for sub in Subscription.objects.select_related("user_profile").filter(user_profile__in=users,
|
||||
recipient__in=recipients_map.values(),
|
||||
active=True):
|
||||
subs_by_user[sub.user_profile_id].append(sub)
|
||||
|
||||
subs_to_deactivate = []
|
||||
not_subscribed = []
|
||||
for user_profile in users:
|
||||
recipients_to_unsub = set([recipient.id for recipient in recipients_map.values()])
|
||||
for sub in subs_by_user[user_profile.id]:
|
||||
recipients_to_unsub.remove(sub.recipient_id)
|
||||
subs_to_deactivate.append((sub, stream_map[sub.recipient_id]))
|
||||
for recipient_id in recipients_to_unsub:
|
||||
not_subscribed.append((user_profile, stream_map[recipient_id]))
|
||||
|
||||
Subscription.objects.filter(id__in=[sub.id for (sub, stream_name) in
|
||||
subs_to_deactivate]).update(active=False)
|
||||
|
||||
for (sub, stream) in subs_to_deactivate:
|
||||
notify_subscription_removed(sub.user_profile, stream)
|
||||
|
||||
return ([(sub.user_profile, stream) for (sub, stream) in subs_to_deactivate],
|
||||
not_subscribed)
|
||||
|
||||
def do_remove_subscription(user_profile, stream, no_log=False):
|
||||
recipient = get_recipient(Recipient.STREAM, stream.id)
|
||||
maybe_sub = Subscription.objects.filter(user_profile=user_profile,
|
||||
|
@ -646,16 +690,7 @@ def do_remove_subscription(user_profile, stream, no_log=False):
|
|||
subscription.active = False
|
||||
subscription.save(update_fields=["active"])
|
||||
if did_remove:
|
||||
if not no_log:
|
||||
log_event({'type': 'subscription_removed',
|
||||
'user': user_profile.email,
|
||||
'name': stream.name,
|
||||
'domain': stream.realm.domain})
|
||||
|
||||
notice = dict(event=dict(type="subscription", op="remove",
|
||||
subscription=dict(name=stream.name)),
|
||||
users=[user_profile.id])
|
||||
tornado_callbacks.send_notification(notice)
|
||||
notify_subscription_removed(user_profile, stream, no_log)
|
||||
|
||||
return did_remove
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ from zephyr.models import Message, UserProfile, Stream, Subscription, \
|
|||
MAX_SUBJECT_LENGTH, get_stream, bulk_get_streams, UserPresence, \
|
||||
get_recipient, valid_stream_name, to_dict_cache_key, to_dict_cache_key_id, \
|
||||
extract_message_dict, stringify_message_dict, parse_usermessage_flags
|
||||
from zephyr.lib.actions import do_remove_subscription, \
|
||||
from zephyr.lib.actions import do_remove_subscription, bulk_remove_subscriptions, \
|
||||
do_change_password, create_mit_user_if_needed, do_change_full_name, \
|
||||
do_change_enable_desktop_notifications, do_change_enter_sends, do_change_enable_sounds, \
|
||||
do_send_confirmation_email, do_activate_user, do_create_user, check_send_message, \
|
||||
|
@ -1240,12 +1240,11 @@ def remove_subscriptions_backend(request, user_profile,
|
|||
streams = list_to_streams(streams_raw, user_profile)
|
||||
|
||||
result = dict(removed=[], not_subscribed=[])
|
||||
for stream in streams:
|
||||
did_remove = do_remove_subscription(user_profile, stream)
|
||||
if did_remove:
|
||||
result["removed"].append(stream.name)
|
||||
else:
|
||||
result["not_subscribed"].append(stream.name)
|
||||
(removed, not_subscribed) = bulk_remove_subscriptions([user_profile], streams)
|
||||
for (subscriber, stream) in removed:
|
||||
result["removed"].append(stream.name)
|
||||
for (subscriber, stream) in not_subscribed:
|
||||
result["not_subscribed"].append(stream.name)
|
||||
|
||||
return json_success(result)
|
||||
|
||||
|
|
Loading…
Reference in New Issue