<s> from __future__ import absolute_import <EOL> from __future__ import print_function <EOL> from functools import wraps <EOL> from django . core . cache import cache as djcache <EOL> from django . core . cache import get_cache <EOL> from django . conf import settings <EOL> from django . db . models import Q <EOL> from typing import Any , Callable , Iterable , Optional <EOL> from zerver . lib . utils import statsd , statsd_key , make_safe_digest <EOL> import time <EOL> import base64 <EOL> import random <EOL> import sys <EOL> import os <EOL> import os . path <EOL> import hashlib <EOL> remote_cache_time_start = <NUM_LIT:0.0> <EOL> remote_cache_total_time = <NUM_LIT:0.0> <EOL> remote_cache_total_requests = <NUM_LIT:0> <EOL> def get_remote_cache_time ( ) : <EOL> return remote_cache_total_time <EOL> def get_remote_cache_requests ( ) : <EOL> return remote_cache_total_requests <EOL> def remote_cache_stats_start ( ) : <EOL> global remote_cache_time_start <EOL> remote_cache_time_start = time . time ( ) <EOL> def remote_cache_stats_finish ( ) : <EOL> global remote_cache_total_time <EOL> global remote_cache_total_requests <EOL> global remote_cache_time_start <EOL> remote_cache_total_requests += <NUM_LIT:1> <EOL> remote_cache_total_time += ( time . time ( ) - remote_cache_time_start ) <EOL> def get_or_create_key_prefix ( ) : <EOL> if settings . TEST_SUITE : <EOL> return '<STR_LIT>' + str ( os . getpid ( ) ) + '<STR_LIT::>' <EOL> filename = os . path . join ( settings . DEPLOY_ROOT , "<STR_LIT>" ) <EOL> try : <EOL> fd = os . open ( filename , os . O_CREAT | os . O_EXCL | os . O_RDWR , <NUM_LIT> ) <EOL> prefix = base64 . b16encode ( hashlib . sha256 ( str ( random . getrandbits ( <NUM_LIT> ) ) ) . digest ( ) ) [ : <NUM_LIT:32> ] . lower ( ) + '<STR_LIT::>' <EOL> with os . fdopen ( fd , '<STR_LIT:w>' ) as f : <EOL> f . write ( prefix + "<STR_LIT:\n>" ) <EOL> except OSError : <EOL> tries = <NUM_LIT:1> <EOL> while tries < <NUM_LIT:10> : <EOL> with open ( filename , '<STR_LIT:r>' ) as f : <EOL> prefix = f . readline ( ) [ : - <NUM_LIT:1> ] <EOL> if len ( prefix ) == <NUM_LIT> : <EOL> break <EOL> tries += <NUM_LIT:1> <EOL> prefix = '<STR_LIT>' <EOL> time . sleep ( <NUM_LIT:0.5> ) <EOL> if not prefix : <EOL> print ( "<STR_LIT>" ) <EOL> sys . exit ( <NUM_LIT:1> ) <EOL> return prefix <EOL> KEY_PREFIX = get_or_create_key_prefix ( ) <EOL> def bounce_key_prefix_for_testing ( test_name ) : <EOL> global KEY_PREFIX <EOL> KEY_PREFIX = test_name + '<STR_LIT::>' + str ( os . getpid ( ) ) + '<STR_LIT::>' <EOL> def get_cache_backend ( cache_name ) : <EOL> if cache_name is None : <EOL> return djcache <EOL> return get_cache ( cache_name ) <EOL> def cache_with_key ( keyfunc , cache_name = None , timeout = None , with_statsd_key = None ) : <EOL> """<STR_LIT>""" <EOL> def decorator ( func ) : <EOL> @ wraps ( func ) <EOL> def func_with_caching ( * args , ** kwargs ) : <EOL> key = keyfunc ( * args , ** kwargs ) <EOL> val = cache_get ( key , cache_name = cache_name ) <EOL> extra = "<STR_LIT>" <EOL> if cache_name == '<STR_LIT>' : <EOL> extra = "<STR_LIT>" <EOL> if with_statsd_key is not None : <EOL> metric_key = with_statsd_key <EOL> else : <EOL> metric_key = statsd_key ( key ) <EOL> status = "<STR_LIT>" if val is not None else "<STR_LIT>" <EOL> statsd . incr ( "<STR_LIT>" % ( extra , metric_key , status ) ) <EOL> if val is not None : <EOL> return val [ <NUM_LIT:0> ] <EOL> val = func ( * args , ** kwargs ) <EOL> cache_set ( key , val , cache_name = cache_name , timeout = timeout ) <EOL> return val <EOL> return func_with_caching <EOL> return decorator <EOL> def cache_set ( key , val , cache_name = None , timeout = None ) : <EOL> remote_cache_stats_start ( ) <EOL> cache_backend = get_cache_backend ( cache_name ) <EOL> ret = cache_backend . set ( KEY_PREFIX + key , ( val , ) , timeout = timeout ) <EOL> remote_cache_stats_finish ( ) <EOL> return ret <EOL> def cache_get ( key , cache_name = None ) : <EOL> remote_cache_stats_start ( ) <EOL> cache_backend = get_cache_backend ( cache_name ) <EOL> ret = cache_backend . get ( KEY_PREFIX + key ) <EOL> remote_cache_stats_finish ( ) <EOL> return ret <EOL> def cache_get_many ( keys , cache_name = None ) : <EOL> keys = [ KEY_PREFIX + key for key in keys ] <EOL> remote_cache_stats_start ( ) <EOL> ret = get_cache_backend ( cache_name ) . get_many ( keys ) <EOL> remote_cache_stats_finish ( ) <EOL> return dict ( [ ( key [ len ( KEY_PREFIX ) : ] , value ) for key , value in ret . items ( ) ] ) <EOL> def cache_set_many ( items , cache_name = None , timeout = None ) : <EOL> new_items = { } <EOL> for key in items : <EOL> new_items [ KEY_PREFIX + key ] = items [ key ] <EOL> items = new_items <EOL> remote_cache_stats_start ( ) <EOL> ret = get_cache_backend ( cache_name ) . set_many ( items , timeout = timeout ) <EOL> remote_cache_stats_finish ( ) <EOL> return ret <EOL> def cache_delete ( key , cache_name = None ) : <EOL> remote_cache_stats_start ( ) <EOL> get_cache_backend ( cache_name ) . delete ( KEY_PREFIX + key ) <EOL> remote_cache_stats_finish ( ) <EOL> def cache_delete_many ( items , cache_name = None ) : <EOL> remote_cache_stats_start ( ) <EOL> get_cache_backend ( cache_name ) . delete_many ( <EOL> KEY_PREFIX + item for item in items ) <EOL> remote_cache_stats_finish ( ) <EOL> def generic_bulk_cached_fetch ( cache_key_function , query_function , object_ids , <EOL> extractor = lambda obj : obj , <EOL> setter = lambda obj : obj , <EOL> id_fetcher = lambda obj : obj . id , <EOL> cache_transformer = lambda obj : obj ) : <EOL> cache_keys = { } <EOL> for object_id in object_ids : <EOL> cache_keys [ object_id ] = cache_key_function ( object_id ) <EOL> cached_objects = cache_get_many ( [ cache_keys [ object_id ] <EOL> for object_id in object_ids ] ) <EOL> for ( key , val ) in cached_objects . items ( ) : <EOL> cached_objects [ key ] = extractor ( cached_objects [ key ] [ <NUM_LIT:0> ] ) <EOL> needed_ids = [ object_id for object_id in object_ids if <EOL> cache_keys [ object_id ] not in cached_objects ] <EOL> db_objects = query_function ( needed_ids ) <EOL> items_for_remote_cache = { } <EOL> for obj in db_objects : <EOL> key = cache_keys [ id_fetcher ( obj ) ] <EOL> item = cache_transformer ( obj ) <EOL> items_for_remote_cache [ key ] = ( setter ( item ) , ) <EOL> cached_objects [ key ] = item <EOL> if len ( items_for_remote_cache ) > <NUM_LIT:0> : <EOL> cache_set_many ( items_for_remote_cache ) <EOL> return dict ( ( object_id , cached_objects [ cache_keys [ object_id ] ] ) for object_id in object_ids <EOL> if cache_keys [ object_id ] in cached_objects ) <EOL> def cache ( func ) : <EOL> """<STR_LIT>""" <EOL> func_uniqifier = '<STR_LIT>' % ( func . __code__ . co_filename , func . __name__ ) <EOL> @ wraps ( func ) <EOL> def keyfunc ( * args , ** kwargs ) : <EOL> key = func_uniqifier + repr ( ( args , kwargs ) ) <EOL> return key . replace ( '<STR_LIT:->' , '<STR_LIT>' ) . replace ( '<STR_LIT:U+0020>' , '<STR_LIT>' ) <EOL> return cache_with_key ( keyfunc ) ( func ) <EOL> def message_cache_key ( message_id ) : <EOL> return "<STR_LIT>" % ( message_id , ) <EOL> def display_recipient_cache_key ( recipient_id ) : <EOL> return "<STR_LIT>" % ( recipient_id , ) <EOL> def user_profile_by_email_cache_key ( email ) : <EOL> return '<STR_LIT>' % ( make_safe_digest ( email . strip ( ) ) , ) <EOL> def user_profile_by_id_cache_key ( user_profile_id ) : <EOL> return "<STR_LIT>" % ( user_profile_id , ) <EOL> def cache_save_user_profile ( user_profile ) : <EOL> cache_set ( user_profile_by_id_cache_key ( user_profile . id ) , user_profile , timeout = <NUM_LIT> * <NUM_LIT> * <NUM_LIT:7> ) <EOL> def active_user_dicts_in_realm_cache_key ( realm ) : <EOL> return "<STR_LIT>" % ( realm . id , ) <EOL> def active_bot_dicts_in_realm_cache_key ( realm ) : <EOL> return "<STR_LIT>" % ( realm . id , ) <EOL> def get_stream_cache_key ( stream_name , realm ) : <EOL> from zerver . models import Realm <EOL> if isinstance ( realm , Realm ) : <EOL> realm_id = realm . id <EOL> else : <EOL> realm_id = realm <EOL> return "<STR_LIT>" % ( <EOL> realm_id , make_safe_digest ( stream_name . strip ( ) . lower ( ) ) ) <EOL> def update_user_profile_caches ( user_profiles ) : <EOL> items_for_remote_cache = { } <EOL> for user_profile in user_profiles : <EOL> items_for_remote_cache [ user_profile_by_email_cache_key ( user_profile . email ) ] = ( user_profile , ) <EOL> items_for_remote_cache [ user_profile_by_id_cache_key ( user_profile . id ) ] = ( user_profile , ) <EOL> cache_set_many ( items_for_remote_cache ) <EOL> def flush_user_profile ( sender , ** kwargs ) : <EOL> user_profile = kwargs [ '<STR_LIT>' ] <EOL> update_user_profile_caches ( [ user_profile ] ) <EOL> if kwargs . get ( '<STR_LIT>' ) is None or len ( set ( [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT:email>' , '<STR_LIT>' ] ) & set ( kwargs [ '<STR_LIT>' ] ) ) > <NUM_LIT:0> : <EOL> cache_delete ( active_user_dicts_in_realm_cache_key ( user_profile . realm ) ) <EOL> bot_fields = { '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' , <EOL> '<STR_LIT>' , '<STR_LIT>' } <EOL> if user_profile . is_bot and ( kwargs [ '<STR_LIT>' ] is None or bot_fields & set ( kwargs [ '<STR_LIT>' ] ) ) : <EOL> cache_delete ( active_bot_dicts_in_realm_cache_key ( user_profile . realm ) ) <EOL> if kwargs . get ( '<STR_LIT>' ) is None or "<STR_LIT>" in kwargs [ '<STR_LIT>' ] : <EOL> cache_delete ( realm_alert_words_cache_key ( user_profile . realm ) ) <EOL> def flush_realm ( sender , ** kwargs ) : <EOL> realm = kwargs [ '<STR_LIT>' ] <EOL> users = realm . get_active_users ( ) <EOL> update_user_profile_caches ( users ) <EOL> if realm . deactivated : <EOL> cache_delete ( active_user_dicts_in_realm_cache_key ( realm ) ) <EOL> cache_delete ( active_bot_dicts_in_realm_cache_key ( realm ) ) <EOL> cache_delete ( realm_alert_words_cache_key ( realm ) ) <EOL> def realm_alert_words_cache_key ( realm ) : <EOL> return "<STR_LIT>" % ( realm . domain , ) <EOL> def flush_stream ( sender , ** kwargs ) : <EOL> from zerver . models import UserProfile <EOL> stream = kwargs [ '<STR_LIT>' ] <EOL> items_for_remote_cache = { } <EOL> items_for_remote_cache [ get_stream_cache_key ( stream . name , stream . realm ) ] = ( stream , ) <EOL> cache_set_many ( items_for_remote_cache ) <EOL> if kwargs . get ( '<STR_LIT>' ) is None or '<STR_LIT:name>' in kwargs [ '<STR_LIT>' ] and UserProfile . objects . filter ( <EOL> Q ( default_sending_stream = stream ) | <EOL> Q ( default_events_register_stream = stream ) <EOL> ) . exists ( ) : <EOL> cache_delete ( active_bot_dicts_in_realm_cache_key ( stream . realm ) ) </s>
