Skip to content

_StatementCache does not call on_remove callback when clear()'ed #416

Closed
@un-def

Description

@un-def
  • asyncpg version: 0.18.3
  • PostgreSQL version: 9.6
  • Do you use a PostgreSQL SaaS?: no
  • Python version: 3.7
  • Platform: Ubuntu 18.04.2 LTS
  • Do you use pgbouncer?: no
  • Did you install asyncpg with pip?: yes
  • Can the issue be reproduced under both asyncio and
    uvloop?
    : not related

_StatementCache on_remove callback is called for expired entries (1) and for least recently used entries when the cache is full (2), but not when clear() method is called (3).

Connection sets own _maybe_gc_stmt method (4) as a callback for _StatementCache. The method is used to mark non-referenced PreparedStatementState objects as closed and put them in _stmts_to_close set to schedule to close them later (they will be closed on the server side when _cleanup_stmts is called (5)).

As noted above, the callback is not called when the cache is cleared by _StatementCache.clear method, therefore the statements will never be closed on the postgres side (“closed” in the meaning of the Close frontend protocol message) and can no longer be used by asyncpg. This leads to memory leak on the server side until the connection is closed.

There are two Connection methods that used to drop the cache:_drop_local_statement_cache and _drop_global_statement_cache (6). Both of them (directly or indirectly) call _StatementCache.clear. Some Connection methods (set_type_codec, reset_type_codec, set_builtin_type_codec, reload_schema_state) drop the cache unconditionally, some methods do so if the database schema has been changed (_do_execute → (execute, executemany, fetch, fetchval, fetchrow)). In any case, each cache drop may increase the number of unreachable named prepared statements that eat postgres memory.


Is this a bug or an expected behavior?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions