mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Avoid invalidating all RelationSyncCache entries on publication rename.
On Publication rename, we need to only invalidate the RelationSyncCache entries corresponding to relations that are part of the publication being renamed. As part of this patch, we introduce a new invalidation message to invalidate the cache maintained by the logical decoding output plugin. We can't use existing relcache invalidation for this purpose, as that would unnecessarily cause relcache invalidations in other backends. This will improve performance by building fewer relation cache entries during logical replication. Author: Hayato Kuroda <kuroda.hayato@fujitsu.com> Author: Shlok Kyal <shlok.kyal.oss@gmail.com> Reviewed-by: Hou Zhijie <houzj.fnst@fujitsu.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Discussion: https://postgr.es/m/OSCPR01MB14966C09AA201EFFA706576A7F5C92@OSCPR01MB14966.jpnprd01.prod.outlook.com
This commit is contained in:
@@ -132,6 +132,8 @@ standby_desc_invalidations(StringInfo buf,
|
||||
appendStringInfo(buf, " relmap db %u", msg->rm.dbId);
|
||||
else if (msg->id == SHAREDINVALSNAPSHOT_ID)
|
||||
appendStringInfo(buf, " snapshot %u", msg->sn.relId);
|
||||
else if (msg->id == SHAREDINVALRELSYNC_ID)
|
||||
appendStringInfo(buf, " relsync %u", msg->rs.relid);
|
||||
else
|
||||
appendStringInfo(buf, " unrecognized id %d", msg->id);
|
||||
}
|
||||
|
||||
@@ -338,6 +338,22 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
|
||||
|
||||
InvokeObjectPostAlterHook(classId, objectId, 0);
|
||||
|
||||
/* Do post catalog-update tasks */
|
||||
if (classId == PublicationRelationId)
|
||||
{
|
||||
Form_pg_publication pub = (Form_pg_publication) GETSTRUCT(oldtup);
|
||||
|
||||
/*
|
||||
* Invalidate relsynccache entries.
|
||||
*
|
||||
* Unlike ALTER PUBLICATION ADD/SET/DROP commands, renaming a
|
||||
* publication does not impact the publication status of tables. So,
|
||||
* we don't need to invalidate relcache to rebuild the rd_pubdesc.
|
||||
* Instead, we invalidate only the relsyncache.
|
||||
*/
|
||||
InvalidatePubRelSyncCache(pub->oid, pub->puballtables);
|
||||
}
|
||||
|
||||
/* Release memory */
|
||||
pfree(values);
|
||||
pfree(nulls);
|
||||
|
||||
@@ -491,6 +491,45 @@ pub_contains_invalid_column(Oid pubid, Relation relation, List *ancestors,
|
||||
return *invalid_column_list || *invalid_gen_col;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate entries in the RelationSyncCache for relations included in the
|
||||
* specified publication, either via FOR TABLE or FOR TABLES IN SCHEMA.
|
||||
*
|
||||
* If 'puballtables' is true, invalidate all cache entries.
|
||||
*/
|
||||
void
|
||||
InvalidatePubRelSyncCache(Oid pubid, bool puballtables)
|
||||
{
|
||||
if (puballtables)
|
||||
{
|
||||
CacheInvalidateRelSyncAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
List *relids = NIL;
|
||||
List *schemarelids = NIL;
|
||||
|
||||
/*
|
||||
* For partitioned tables, we must invalidate all partitions and
|
||||
* itself. WAL records for INSERT/UPDATE/DELETE specify leaf tables as
|
||||
* a target. However, WAL records for TRUNCATE specify both a root and
|
||||
* its leaves.
|
||||
*/
|
||||
relids = GetPublicationRelations(pubid,
|
||||
PUBLICATION_PART_ALL);
|
||||
schemarelids = GetAllSchemaPublicationRelations(pubid,
|
||||
PUBLICATION_PART_ALL);
|
||||
|
||||
relids = list_concat_unique_oid(relids, schemarelids);
|
||||
|
||||
/* Invalidate the relsyncache */
|
||||
foreach_oid(relid, relids)
|
||||
CacheInvalidateRelSync(relid);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* check_functions_in_node callback */
|
||||
static bool
|
||||
contain_mutable_or_user_functions_checker(Oid func_id, void *context)
|
||||
|
||||
@@ -531,6 +531,8 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
|
||||
CacheRegisterSyscacheCallback(PUBLICATIONOID,
|
||||
publication_invalidation_cb,
|
||||
(Datum) 0);
|
||||
CacheRegisterRelSyncCallback(rel_sync_cache_relation_cb,
|
||||
(Datum) 0);
|
||||
publication_callback_registered = true;
|
||||
}
|
||||
|
||||
@@ -1789,12 +1791,6 @@ static void
|
||||
publication_invalidation_cb(Datum arg, int cacheid, uint32 hashvalue)
|
||||
{
|
||||
publications_valid = false;
|
||||
|
||||
/*
|
||||
* Also invalidate per-relation cache so that next time the filtering info
|
||||
* is checked it will be updated with the new publication settings.
|
||||
*/
|
||||
rel_sync_cache_publication_cb(arg, cacheid, hashvalue);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
125
src/backend/utils/cache/inval.c
vendored
125
src/backend/utils/cache/inval.c
vendored
@@ -271,6 +271,7 @@ int debug_discard_caches = 0;
|
||||
|
||||
#define MAX_SYSCACHE_CALLBACKS 64
|
||||
#define MAX_RELCACHE_CALLBACKS 10
|
||||
#define MAX_RELSYNC_CALLBACKS 10
|
||||
|
||||
static struct SYSCACHECALLBACK
|
||||
{
|
||||
@@ -292,6 +293,15 @@ static struct RELCACHECALLBACK
|
||||
|
||||
static int relcache_callback_count = 0;
|
||||
|
||||
static struct RELSYNCCALLBACK
|
||||
{
|
||||
RelSyncCallbackFunction function;
|
||||
Datum arg;
|
||||
} relsync_callback_list[MAX_RELSYNC_CALLBACKS];
|
||||
|
||||
static int relsync_callback_count = 0;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Invalidation subgroup support functions
|
||||
* ----------------------------------------------------------------
|
||||
@@ -484,6 +494,36 @@ AddRelcacheInvalidationMessage(InvalidationMsgsGroup *group,
|
||||
AddInvalidationMessage(group, RelCacheMsgs, &msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a relsync inval entry
|
||||
*
|
||||
* We put these into the relcache subgroup for simplicity. This message is the
|
||||
* same as AddRelcacheInvalidationMessage() except that it is for
|
||||
* RelationSyncCache maintained by decoding plugin pgoutput.
|
||||
*/
|
||||
static void
|
||||
AddRelsyncInvalidationMessage(InvalidationMsgsGroup *group,
|
||||
Oid dbId, Oid relId)
|
||||
{
|
||||
SharedInvalidationMessage msg;
|
||||
|
||||
/* Don't add a duplicate item. */
|
||||
ProcessMessageSubGroup(group, RelCacheMsgs,
|
||||
if (msg->rc.id == SHAREDINVALRELSYNC_ID &&
|
||||
(msg->rc.relId == relId ||
|
||||
msg->rc.relId == InvalidOid))
|
||||
return);
|
||||
|
||||
/* OK, add the item */
|
||||
msg.rc.id = SHAREDINVALRELSYNC_ID;
|
||||
msg.rc.dbId = dbId;
|
||||
msg.rc.relId = relId;
|
||||
/* check AddCatcacheInvalidationMessage() for an explanation */
|
||||
VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));
|
||||
|
||||
AddInvalidationMessage(group, RelCacheMsgs, &msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a snapshot inval entry
|
||||
*
|
||||
@@ -611,6 +651,17 @@ RegisterRelcacheInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
|
||||
info->RelcacheInitFileInval = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* RegisterRelsyncInvalidation
|
||||
*
|
||||
* As above, but register a relsynccache invalidation event.
|
||||
*/
|
||||
static void
|
||||
RegisterRelsyncInvalidation(InvalidationInfo *info, Oid dbId, Oid relId)
|
||||
{
|
||||
AddRelsyncInvalidationMessage(&info->CurrentCmdInvalidMsgs, dbId, relId);
|
||||
}
|
||||
|
||||
/*
|
||||
* RegisterSnapshotInvalidation
|
||||
*
|
||||
@@ -751,6 +802,13 @@ InvalidateSystemCachesExtended(bool debug_discard)
|
||||
|
||||
ccitem->function(ccitem->arg, InvalidOid);
|
||||
}
|
||||
|
||||
for (i = 0; i < relsync_callback_count; i++)
|
||||
{
|
||||
struct RELSYNCCALLBACK *ccitem = relsync_callback_list + i;
|
||||
|
||||
ccitem->function(ccitem->arg, InvalidOid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -832,6 +890,12 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
|
||||
else if (msg->sn.dbId == MyDatabaseId)
|
||||
InvalidateCatalogSnapshot();
|
||||
}
|
||||
else if (msg->id == SHAREDINVALRELSYNC_ID)
|
||||
{
|
||||
/* We only care about our own database */
|
||||
if (msg->rs.dbId == MyDatabaseId)
|
||||
CallRelSyncCallbacks(msg->rs.relid);
|
||||
}
|
||||
else
|
||||
elog(FATAL, "unrecognized SI message ID: %d", msg->id);
|
||||
}
|
||||
@@ -1621,6 +1685,32 @@ CacheInvalidateRelcacheByRelid(Oid relid)
|
||||
ReleaseSysCache(tup);
|
||||
}
|
||||
|
||||
/*
|
||||
* CacheInvalidateRelSync
|
||||
* Register invalidation of the cache in logical decoding output plugin
|
||||
* for a database.
|
||||
*
|
||||
* This type of invalidation message is used for the specific purpose of output
|
||||
* plugins. Processes which do not decode WALs would do nothing even when it
|
||||
* receives the message.
|
||||
*/
|
||||
void
|
||||
CacheInvalidateRelSync(Oid relid)
|
||||
{
|
||||
RegisterRelsyncInvalidation(PrepareInvalidationState(),
|
||||
MyDatabaseId, relid);
|
||||
}
|
||||
|
||||
/*
|
||||
* CacheInvalidateRelSyncAll
|
||||
* Register invalidation of the whole cache in logical decoding output
|
||||
* plugin.
|
||||
*/
|
||||
void
|
||||
CacheInvalidateRelSyncAll(void)
|
||||
{
|
||||
CacheInvalidateRelSync(InvalidOid);
|
||||
}
|
||||
|
||||
/*
|
||||
* CacheInvalidateSmgr
|
||||
@@ -1763,6 +1853,27 @@ CacheRegisterRelcacheCallback(RelcacheCallbackFunction func,
|
||||
++relcache_callback_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* CacheRegisterRelSyncCallback
|
||||
* Register the specified function to be called for all future
|
||||
* relsynccache invalidation events.
|
||||
*
|
||||
* This function is intended to be call from the logical decoding output
|
||||
* plugins.
|
||||
*/
|
||||
void
|
||||
CacheRegisterRelSyncCallback(RelSyncCallbackFunction func,
|
||||
Datum arg)
|
||||
{
|
||||
if (relsync_callback_count >= MAX_RELSYNC_CALLBACKS)
|
||||
elog(FATAL, "out of relsync_callback_list slots");
|
||||
|
||||
relsync_callback_list[relsync_callback_count].function = func;
|
||||
relsync_callback_list[relsync_callback_count].arg = arg;
|
||||
|
||||
++relsync_callback_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* CallSyscacheCallbacks
|
||||
*
|
||||
@@ -1788,6 +1899,20 @@ CallSyscacheCallbacks(int cacheid, uint32 hashvalue)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* CallSyscacheCallbacks
|
||||
*/
|
||||
void
|
||||
CallRelSyncCallbacks(Oid relid)
|
||||
{
|
||||
for (int i = 0; i < relsync_callback_count; i++)
|
||||
{
|
||||
struct RELSYNCCALLBACK *ccitem = relsync_callback_list + i;
|
||||
|
||||
ccitem->function(ccitem->arg, relid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* LogLogicalInvalidations
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user