Browse Source

Fix user cache acting incorrectly with evictions

The first issue involved copied users which would lead to user updates
causing faster evictions of the cache than was expected.

The second issue involved users that weren't bound to an internal
lifetime eviction policy. These users would not get evicted.
For example, a user without mutual guilds or being part of the internal
cache in general (messages, DMs) would never end up being evicted for
some strange reason. To handle this case, store_user would get a
counterpart named create_user which would create a user without
potentially storing them in the cache. That way only users with a
bound lifetime within the library would be stored.
pull/7297/head
Rapptz 4 years ago
parent
commit
ecf239d2a2
  1. 2
      discord/appinfo.py
  2. 3
      discord/interactions.py
  3. 4
      discord/invite.py
  4. 2
      discord/member.py
  5. 4
      discord/state.py
  6. 2
      discord/template.py
  7. 2
      discord/user.py
  8. 3
      discord/webhook/async_.py

2
discord/appinfo.py

@ -146,7 +146,7 @@ class AppInfo:
self.rpc_origins: List[str] = data['rpc_origins'] self.rpc_origins: List[str] = data['rpc_origins']
self.bot_public: bool = data['bot_public'] self.bot_public: bool = data['bot_public']
self.bot_require_code_grant: bool = data['bot_require_code_grant'] self.bot_require_code_grant: bool = data['bot_require_code_grant']
self.owner: User = state.store_user(data['owner']) self.owner: User = state.create_user(data['owner'])
team: Optional[TeamPayload] = data.get('team') team: Optional[TeamPayload] = data.get('team')
self.team: Optional[Team] = Team(state, team) if team else None self.team: Optional[Team] = Team(state, team) if team else None

3
discord/interactions.py

@ -626,6 +626,9 @@ class _InteractionMessageState:
def store_user(self, data): def store_user(self, data):
return self._parent.store_user(data) return self._parent.store_user(data)
def create_user(self, data):
return self._parent.create_user(data)
@property @property
def http(self): def http(self):
return self._parent.http return self._parent.http

4
discord/invite.py

@ -352,12 +352,12 @@ class Invite(Hashable):
self.expires_at: Optional[datetime.datetime] = parse_time(expires_at) if expires_at else None self.expires_at: Optional[datetime.datetime] = parse_time(expires_at) if expires_at else None
inviter_data = data.get('inviter') inviter_data = data.get('inviter')
self.inviter: Optional[User] = None if inviter_data is None else self._state.store_user(inviter_data) self.inviter: Optional[User] = None if inviter_data is None else self._state.create_user(inviter_data)
self.channel: Optional[InviteChannelType] = self._resolve_channel(data.get('channel'), channel) self.channel: Optional[InviteChannelType] = self._resolve_channel(data.get('channel'), channel)
target_user_data = data.get('target_user') target_user_data = data.get('target_user')
self.target_user: Optional[User] = None if target_user_data is None else self._state.store_user(target_user_data) self.target_user: Optional[User] = None if target_user_data is None else self._state.create_user(target_user_data)
self.target_type: InviteTarget = try_enum(InviteTarget, data.get("target_type", 0)) self.target_type: InviteTarget = try_enum(InviteTarget, data.get("target_type", 0))

2
discord/member.py

@ -326,7 +326,7 @@ class Member(discord.abc.Messageable, _UserTag):
try: try:
member_data = data.pop('member') member_data = data.pop('member')
except KeyError: except KeyError:
return state.store_user(data) return state.create_user(data)
else: else:
member_data['user'] = data # type: ignore member_data['user'] = data # type: ignore
return cls(data=member_data, guild=guild, state=state) # type: ignore return cls(data=member_data, guild=guild, state=state) # type: ignore

4
discord/state.py

@ -178,7 +178,7 @@ class ConnectionState:
self._intents = intents self._intents = intents
if not intents.members or cache_flags._empty: if not intents.members or cache_flags._empty:
self.store_user = self.store_user_no_intents self.store_user = self.create_user
self.deref_user = self.deref_user_no_intents self.deref_user = self.deref_user_no_intents
self.parsers = parsers = {} self.parsers = parsers = {}
@ -284,7 +284,7 @@ class ConnectionState:
def deref_user(self, user_id): def deref_user(self, user_id):
self._users.pop(user_id, None) self._users.pop(user_id, None)
def store_user_no_intents(self, data): def create_user(self, data):
return User(state=self, data=data) return User(state=self, data=data)
def deref_user_no_intents(self, user_id): def deref_user_no_intents(self, user_id):

2
discord/template.py

@ -137,7 +137,7 @@ class Template:
self.name = data['name'] self.name = data['name']
self.description = data['description'] self.description = data['description']
creator_data = data.get('creator') creator_data = data.get('creator')
self.creator = None if creator_data is None else self._state.store_user(creator_data) self.creator = None if creator_data is None else self._state.create_user(creator_data)
self.created_at = parse_time(data.get('created_at')) self.created_at = parse_time(data.get('created_at'))
self.updated_at = parse_time(data.get('updated_at')) self.updated_at = parse_time(data.get('updated_at'))

2
discord/user.py

@ -393,7 +393,7 @@ class User(BaseUser, discord.abc.Messageable):
@classmethod @classmethod
def _copy(cls, user): def _copy(cls, user):
self = super()._copy(user) self = super()._copy(user)
self._stored = getattr(user, '_stored', False) self._stored = False
return self return self
async def _get_channel(self): async def _get_channel(self):

3
discord/webhook/async_.py

@ -597,6 +597,9 @@ class _WebhookState:
return self._parent.store_user(data) return self._parent.store_user(data)
return BaseUser(state=self, data=data) return BaseUser(state=self, data=data)
def create_user(self, data):
return BaseUser(state=self, data=data)
@property @property
def http(self): def http(self):
if self._parent is not None: if self._parent is not None:

Loading…
Cancel
Save