March 3, 2025·4 min read·engineeringpostgresqlcachingpooling

Pgpool-II 4.6 makes query cache invalidation explicit

Pgpool-II 4.6 adds targeted cache deletion and an administrative invalidation request. Their different execution rules matter when cached results outlive the assumptions that made them useful.

A query cache needs a rule for deciding when an answer stops being valid. Table updates provide a useful signal, but a cached expression may have no table dependency at all. Pgpool-II 4.6 adds explicit controls for that case, alongside a way to force caching when its normal eligibility checks reject a query. The March 3 announcement presents these changes as part of a release focused on administration and logging.

The release notes date 4.6.0 itself to February 28. Today's announcement therefore describes an already released version. Its cache controls are useful to examine together because forcing a result into a cache creates a corresponding responsibility to remove it under the right conditions.

I default to PostgreSQL partly because its behavior is documented well enough to reason about changes before adopting them. A proxy that returns results without executing a query adds another set of semantics. Pgpool's new controls make more of those semantics available as explicit operations.

Forcing a result into the cache changes its lifetime

The query-cache documentation describes caching by user, database and query text, with bind parameters included for extended queries. A hit returns a saved result without parsing SQL or accessing PostgreSQL. Automatic invalidation normally removes entries associated with an updated table.

The new /*FORCE QUERY CACHE*/ comment overrides normal eligibility checks. The manual illustrates the consequence with SELECT now(). Once forced into the cache, its timestamp can remain unchanged until the cache is removed. A later query marked /*NO QUERY CACHE*/ does not delete the previously forced entry, because preventing creation and removing an existing result are separate operations.

That distinction matters for application controls. A flag that says not to cache a new execution does not necessarily revoke an answer stored by an earlier execution. The caller must use an operation whose defined effect includes deletion. This is especially apparent for a time expression, where passing time provides no table update to trigger invalidation.

Targeted deletion uses the original query text

The 4.6.0 command definition documents PGPOOL SET CACHE DELETE. Its argument must match the original query exactly, including a trailing semicolon. Single quotes inside that argument need SQL string-literal escaping.

The documented example creates and then removes an unwanted timestamp result. The same sequence can be written through a Pgpool connection as follows:

/*FORCE QUERY CACHE*/SELECT current_timestamp;
PGPOOL SET CACHE DELETE '/*FORCE QUERY CACHE*/SELECT current_timestamp;';

The command reports whether it deleted an entry or found no corresponding cache. Retaining the original statement text is therefore useful if targeted deletion is part of an application's operating procedure. A reconstructed statement with different whitespace may express the same SQL calculation while failing the command's exact-text requirement.

The rendered command reference explains why this operation particularly helps queries without table references. Such queries lack the dependency that ordinary table-driven invalidation uses. The command supplies a direct way to remove their cached answers without treating an unrelated table update as an invalidation mechanism.

Administrative invalidation is a request

The 4.6.0 PCP command definition describes a different execution model. pcp_invalidate_query_cache places an invalidation request in shared memory. A child process handles it while processing a client message. If clients are absent or idle, processing waits for a message to arrive.

This is an important distinction for automation. Submitting the administrative operation does not describe an immediate deletion at the instant the command returns. A procedure that observes an idle Pgpool instance must account for when the request is consumed. The manual's wording provides that condition directly.

Invalidation also does not reset all statistics. Hit and select counters continue increasing, while entry and space statistics reflect the emptied cache. The PCP reference also states that the command errors when memory caching is disabled. A counter remaining nonzero is consequently not evidence that invalidation failed, since historical activity and current cache contents measure different things.

Logging changes support diagnosis around the proxy

The release also adds log_backend_messages and imports PostgreSQL 17's parser. The parser change matters because Pgpool must understand statements it processes before PostgreSQL executes them. Syntax accepted by a server does not by itself establish that an intervening proxy understands it.

The logging reference distinguishes terse backend-message logging from verbose logging. Terse mode summarizes repeated messages, while verbose mode records each repetition and can produce many lines. Several collector-related settings now support configuration reloads, although enabling the collector itself remains a startup choice.

I find these administration changes useful because they expose the proxy's own work to an operator. A stale answer can originate in Pgpool's result cache even when PostgreSQL would execute the query correctly. Version 4.6 provides an exact-query deletion operation and a broader administrative request, each with a documented effect and completion condition. Those distinctions belong in the procedure that manages cached results.