* This file and its contents are licensed under the Apache License 2.0.
* Please see the included NOTICE for copyright information and
* LICENSE-APACHE for a copy of the license.
*/
#include <postgres.h>
#include <access/xact.h>
#include <utils/lsyscache.h>
#include <utils/inval.h>
#include <catalog/namespace.h>
#include <nodes/nodes.h>
#include <miscadmin.h>
#include "catalog.h"
#include "compat.h"
#include "extension.h"
#include "hypertable_cache.h"
#include "bgw/scheduler.h"
* Notes on the way cache invalidation works.
*
* Since our caches are stored in per-process (per-backend memory), we need a
* way to signal all backends that they should invalidate their caches. For this
* we use the PostgreSQL relcache mechanism that propagates relation cache
* invalidation events to all backends. We register a callback with this
* mechanism to receive events on all backends whenever a relation cache entry
* is invalidated.
*
* To know which events should trigger invalidation of our caches, we use dummy
* (empty) tables. We can trigger relcache invalidation events for these tables
* to signal other backends. If the received table OID is a dummy table, we know
* that this is an event that we care about.
*
* Caches for catalog tables should be invalidated on:
*
* 1. INSERT/UPDATE/DELETE on a catalog table
* 2. Aborted transactions that taint the caches
*
* Generally, INSERTS do not warrant cache invalidation, unless it is an insert
* of a subobject that belongs to an object that might already be in the cache
* (e.g., a new dimension of a hypertable), or when replacing an existing entry
* (e.g., when replacing a negative hypertable entry with a positive one). Note,
* also, that INSERTS can taint the cache if the transaction that did the INSERT
* fails. This is why we also need to invalidate caches on transaction failure.
*/
void _cache_invalidate_init(void);
void _cache_invalidate_fini(void);
static void
cache_invalidate_all(void)
{
ts_hypertable_cache_invalidate_callback();
ts_bgw_job_cache_invalidate_callback();
}
* This function is called when any relcache is invalidated.
* Should route the invalidation to the correct cache.
*/
static void
cache_invalidate_callback(Datum arg, Oid relid)
{
Catalog *catalog;
if (ts_extension_invalidate(relid))
{
cache_invalidate_all();
return;
}
if (!ts_extension_is_loaded())
return;
catalog = ts_catalog_get();
if (relid == ts_catalog_get_cache_proxy_id(catalog, CACHE_TYPE_HYPERTABLE))
ts_hypertable_cache_invalidate_callback();
if (relid == ts_catalog_get_cache_proxy_id(catalog, CACHE_TYPE_BGW_JOB))
ts_bgw_job_cache_invalidate_callback();
if (relid == InvalidOid)
cache_invalidate_all();
}
TS_FUNCTION_INFO_V1(ts_timescaledb_invalidate_cache);
* Force a cache invalidation for a catalog table.
*
* This function is used for debugging purposes and triggers a cache
* invalidation.
*
* The first argument should be the catalog table that has changed, warranting a
* cache invalidation.
*/
Datum
ts_timescaledb_invalidate_cache(PG_FUNCTION_ARGS)
{
ts_catalog_invalidate_cache(PG_GETARG_OID(0), CMD_UPDATE);
PG_RETURN_VOID();
}
static void
cache_invalidate_xact_end(XactEvent event, void *arg)
{
switch (event)
{
case XACT_EVENT_PREROLLBACK_CLEANUP:
case XACT_EVENT_POST_COMMIT_CLEANUP:
case XACT_EVENT_RECORD_COMMIT:
case XACT_EVENT_START:
case XACT_EVENT_STMT_FINISH:
break;
case XACT_EVENT_ABORT:
cache_invalidate_all();
default:
break;
}
}
static void
cache_invalidate_subxact_end(SubXactEvent event, SubTransactionId mySubid,
SubTransactionId parentSubid, void *arg)
{
switch (event)
{
case SUBXACT_EVENT_ABORT_SUB:
* Invalidate caches on aborted sub transactions. See notes above
* in cache_invalidate_xact_end.
*/
cache_invalidate_all();
default:
break;
}
}
void
_cache_invalidate_init(void)
{
#ifdef ENABLE_MOT
RegisterXactCallback(cache_invalidate_xact_end, NULL);
#endif
RegisterSubXactCallback(cache_invalidate_subxact_end, NULL);
CacheRegisterThreadRelcacheCallback(cache_invalidate_callback, PointerGetDatum(NULL));
tsdb_first_start = true;
}
void
_cache_invalidate_fini(void)
{
#ifdef ENABLE_MOT
UnregisterXactCallback(cache_invalidate_xact_end, NULL);
#endif
UnregisterSubXactCallback(cache_invalidate_subxact_end, NULL);
tsdb_first_start = false;
}