Skip to content

ext/pgsql: add meta_cache per-link metadata caching#21885

Draft
arshidkv12 wants to merge 5 commits intophp:masterfrom
arshidkv12:pgsql-meta-3
Draft

ext/pgsql: add meta_cache per-link metadata caching#21885
arshidkv12 wants to merge 5 commits intophp:masterfrom
arshidkv12:pgsql-meta-3

Conversation

@arshidkv12
Copy link
Copy Markdown
Contributor

@arshidkv12 arshidkv12 commented Apr 27, 2026

  • Introduce per-connection meta_cache HashTable in pgsql_link_handle
  • Cache results of php_pgsql_meta_data() to avoid repeated catalog queries
  • Add lookup before executing PQexec() for faster metadata access
  • Initialize meta_cache lazily per connection
  • Properly destroy meta_cache on connection free and query mutations
  • Clear meta_cache on pg_query/pg_delete to avoid stale schema data
  • Add NULL-safe checks for link->meta_cache usage

Improves performance by reducing repeated queries.

@devnexen
Copy link
Copy Markdown
Member

I may have a look later but one large thing I notice is the conflict of interest between persistent connections and request scoped caching. There is probably more to it ..

@arshidkv12
Copy link
Copy Markdown
Contributor Author

I need to check as follows. Is that correct?

if (!link->persistent && link->meta_cache) {
    // check cache
}
if (!link->persistent && !link->meta_cache) {
    // allocate cache
} 

Comment thread ext/pgsql/pgsql.c Outdated
int i, num_rows, err;
zval elem;
pgsql_link_handle *link;
link = FETCH_DEFAULT_LINK_NO_WARNING();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FETCH_DEFAULT_LINK_NO_WARNING() in php_pgsql_meta_data is wrong. The function gets PGconn *pg_link but the cache is looked up against the default link. Those don't match with multiple connections, and OO callers (no default link set) get no caching at all. The pgsql_link_handle * needs to be plumbed through.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. How can I obtain a pgsql_link_handle *link from a PGconn *pgsql? I believe we cannot replace pgsql_link_handle with PGconn, as it would break the API. How can this be resolved?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't ; plumb the handle through instead. The usual way is to keep the existing PHP_PGSQL_API symbol for ABI and introduce an internal variant taking the link directly. In-tree callers all have it on hand.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Comment thread ext/pgsql/pgsql.c Outdated
RETURN_FALSE;
}

if (link->meta_cache) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalidation is incomplete. Wiping on pg_query() only — pg_query_params, pg_execute, pg_prepare, and the pg_send_* family all leave stale entries

Comment thread ext/pgsql/pgsql.c Outdated
FREE_HASHTABLE(link->notices);
link->notices = NULL;
}
if (link->meta_cache) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty repetitive. Could be a helper.

@devnexen
Copy link
Copy Markdown
Member

You really do need to focus on solving design flaws I mentioned earlier. Even then, there might be other issues when I do a 2nd pass.

@arshidkv12
Copy link
Copy Markdown
Contributor Author

You really do need to focus on solving design flaws I mentioned earlier. Even then, there might be other issues when I do a 2nd pass.

We could store a direct PGconn > pgsql_link mapping using a HashTable for O(1) lookup:

zend_hash_index_update_ptr(&PGG(conn_to_link), (zend_ulong) pg_conn, link);
link = zend_hash_index_find_ptr(&PGG(conn_to_link), (zend_ulong) pg_conn);

This avoids repeated lookups or iteration. What do you think?

@devnexen
Copy link
Copy Markdown
Member

Rather not, that adds another structure with its own lifetime concerns (insert/remove on connect/close, persistent vs request) just to work around the first one. The handle is already reachable without a side map. Worth a look at how other helpers in the file get it passed in. Should be enough for your agent to get started.

@devnexen
Copy link
Copy Markdown
Member

I do not think it s going to cut it, I'd suggest to put it in draft mode and going through the eviction part, the cache design and so on ... Cheers.

@arshidkv12 arshidkv12 marked this pull request as draft April 28, 2026 12:29
@arshidkv12
Copy link
Copy Markdown
Contributor Author

Thank you

@devnexen
Copy link
Copy Markdown
Member

I do not think you re extremely far behind neither but once you re done, there is need for tests too. Good luck

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants