mirror of https://github.com/citusdata/citus.git
Clear metadata_cache upon DROP EXTENSION
When we notice that pg_dist_partition is being invalidated we assume that the citus extension is being dropped and drop state such as extensionLoaded and the cached oids of all the metadata tables. This frees the user from needing to reconnect after running DROP EXTENSION, so we also no longer send a warning message.pull/1938/head
parent
f8f1210c0a
commit
1f5379457a
|
@ -66,7 +66,6 @@ static void ErrorIfUnsupportedAlterTableStmt(AlterTableStmt *alterTableStatement
|
||||||
static void ErrorIfDistributedRenameStmt(RenameStmt *renameStatement);
|
static void ErrorIfDistributedRenameStmt(RenameStmt *renameStatement);
|
||||||
|
|
||||||
/* Local functions forward declarations for helper functions */
|
/* Local functions forward declarations for helper functions */
|
||||||
static void WarnIfDropCitusExtension(DropStmt *dropStatement);
|
|
||||||
static bool IsAlterTableRenameStmt(RenameStmt *renameStatement);
|
static bool IsAlterTableRenameStmt(RenameStmt *renameStatement);
|
||||||
static void ExecuteDistributedDDLCommand(Oid relationId, const char *ddlCommandString);
|
static void ExecuteDistributedDDLCommand(Oid relationId, const char *ddlCommandString);
|
||||||
static bool ExecuteCommandOnWorkerShards(Oid relationId, const char *commandString,
|
static bool ExecuteCommandOnWorkerShards(Oid relationId, const char *commandString,
|
||||||
|
@ -143,10 +142,6 @@ multi_ProcessUtility(Node *parsetree,
|
||||||
{
|
{
|
||||||
parsetree = ProcessDropIndexStmt(dropStatement, queryString);
|
parsetree = ProcessDropIndexStmt(dropStatement, queryString);
|
||||||
}
|
}
|
||||||
else if (dropStatement->removeType == OBJECT_EXTENSION)
|
|
||||||
{
|
|
||||||
WarnIfDropCitusExtension(dropStatement);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsA(parsetree, AlterTableStmt))
|
if (IsA(parsetree, AlterTableStmt))
|
||||||
|
@ -208,37 +203,6 @@ multi_ProcessUtility(Node *parsetree,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WarnIfDropCitusExtension prints a WARNING if dropStatement includes dropping
|
|
||||||
* citus extension.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
WarnIfDropCitusExtension(DropStmt *dropStatement)
|
|
||||||
{
|
|
||||||
ListCell *dropStatementObject = NULL;
|
|
||||||
|
|
||||||
Assert(dropStatement->removeType == OBJECT_EXTENSION);
|
|
||||||
|
|
||||||
foreach(dropStatementObject, dropStatement->objects)
|
|
||||||
{
|
|
||||||
List *objectNameList = lfirst(dropStatementObject);
|
|
||||||
char *objectName = NameListToString(objectNameList);
|
|
||||||
|
|
||||||
/* we're only concerned with the citus extension */
|
|
||||||
if (strncmp("citus", objectName, NAMEDATALEN) == 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Warn the user about the possibility of invalid cache. Also, see
|
|
||||||
* function comment of CachedRelationLookup().
|
|
||||||
*/
|
|
||||||
ereport(WARNING, (errmsg("could not clean the metadata cache on "
|
|
||||||
"DROP EXTENSION command"),
|
|
||||||
errhint("Reconnect to the server again.")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Is the passed in statement a transmit statement? */
|
/* Is the passed in statement a transmit statement? */
|
||||||
static bool
|
static bool
|
||||||
IsTransmitStmt(Node *parsetree)
|
IsTransmitStmt(Node *parsetree)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "access/genam.h"
|
#include "access/genam.h"
|
||||||
#include "access/heapam.h"
|
#include "access/heapam.h"
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
|
#include "access/xact.h"
|
||||||
#include "catalog/indexing.h"
|
#include "catalog/indexing.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
@ -35,6 +36,17 @@
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* state which should be cleared upon DROP EXTENSION */
|
||||||
|
static bool extensionLoaded = false;
|
||||||
|
static Oid distShardRelationId = InvalidOid;
|
||||||
|
static Oid distShardPlacementRelationId = InvalidOid;
|
||||||
|
static Oid distPartitionRelationId = InvalidOid;
|
||||||
|
static Oid distPartitionLogicalRelidIndexId = InvalidOid;
|
||||||
|
static Oid distShardLogicalRelidIndexId = InvalidOid;
|
||||||
|
static Oid distShardShardidIndexId = InvalidOid;
|
||||||
|
static Oid distShardPlacementShardidIndexId = InvalidOid;
|
||||||
|
static Oid extraDataContainerFuncId = InvalidOid;
|
||||||
|
|
||||||
/* Hash table for informations about each partition */
|
/* Hash table for informations about each partition */
|
||||||
static HTAB *DistTableCacheHash = NULL;
|
static HTAB *DistTableCacheHash = NULL;
|
||||||
|
|
||||||
|
@ -297,16 +309,10 @@ LookupDistTableCacheEntry(Oid relationId)
|
||||||
* CitusHasBeenLoaded returns true if the citus extension has been created
|
* CitusHasBeenLoaded returns true if the citus extension has been created
|
||||||
* in the current database and the extension script has been executed. Otherwise,
|
* in the current database and the extension script has been executed. Otherwise,
|
||||||
* it returns false. The result is cached as this is called very frequently.
|
* it returns false. The result is cached as this is called very frequently.
|
||||||
*
|
|
||||||
* NB: The way this is cached means the result will be wrong after the
|
|
||||||
* extension is dropped. A reconnect fixes that though, so that seems
|
|
||||||
* acceptable.
|
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
CitusHasBeenLoaded(void)
|
CitusHasBeenLoaded(void)
|
||||||
{
|
{
|
||||||
static bool extensionLoaded = false;
|
|
||||||
|
|
||||||
/* recheck presence until citus has been loaded */
|
/* recheck presence until citus has been loaded */
|
||||||
if (!extensionLoaded)
|
if (!extensionLoaded)
|
||||||
{
|
{
|
||||||
|
@ -329,6 +335,19 @@ CitusHasBeenLoaded(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
extensionLoaded = extensionPresent && extensionScriptExecuted;
|
extensionLoaded = extensionPresent && extensionScriptExecuted;
|
||||||
|
|
||||||
|
if (extensionLoaded)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* InvalidateDistRelationCacheCallback resets state such as extensionLoaded
|
||||||
|
* when it notices changes to pg_dist_partition (which usually indicate
|
||||||
|
* `DROP EXTENSION citus;` has been run)
|
||||||
|
*
|
||||||
|
* Ensure InvalidateDistRelationCacheCallback will notice those changes
|
||||||
|
* by caching pg_dist_partition's oid.
|
||||||
|
*/
|
||||||
|
DistPartitionRelationId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return extensionLoaded;
|
return extensionLoaded;
|
||||||
|
@ -339,11 +358,9 @@ CitusHasBeenLoaded(void)
|
||||||
Oid
|
Oid
|
||||||
DistShardRelationId(void)
|
DistShardRelationId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_shard", &distShardRelationId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_shard", &cachedOid);
|
return distShardRelationId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -351,11 +368,9 @@ DistShardRelationId(void)
|
||||||
Oid
|
Oid
|
||||||
DistShardPlacementRelationId(void)
|
DistShardPlacementRelationId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_shard_placement", &distShardPlacementRelationId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_shard_placement", &cachedOid);
|
return distShardPlacementRelationId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,11 +378,9 @@ DistShardPlacementRelationId(void)
|
||||||
Oid
|
Oid
|
||||||
DistPartitionRelationId(void)
|
DistPartitionRelationId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_partition", &distPartitionRelationId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_partition", &cachedOid);
|
return distPartitionRelationId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,11 +388,10 @@ DistPartitionRelationId(void)
|
||||||
Oid
|
Oid
|
||||||
DistPartitionLogicalRelidIndexId(void)
|
DistPartitionLogicalRelidIndexId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_partition_logical_relid_index",
|
||||||
|
&distPartitionLogicalRelidIndexId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_partition_logical_relid_index", &cachedOid);
|
return distPartitionLogicalRelidIndexId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -387,11 +399,10 @@ DistPartitionLogicalRelidIndexId(void)
|
||||||
Oid
|
Oid
|
||||||
DistShardLogicalRelidIndexId(void)
|
DistShardLogicalRelidIndexId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_shard_logical_relid_index",
|
||||||
|
&distShardLogicalRelidIndexId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_shard_logical_relid_index", &cachedOid);
|
return distShardLogicalRelidIndexId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -399,11 +410,9 @@ DistShardLogicalRelidIndexId(void)
|
||||||
Oid
|
Oid
|
||||||
DistShardShardidIndexId(void)
|
DistShardShardidIndexId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_shard_shardid_index", &distShardShardidIndexId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_shard_shardid_index", &cachedOid);
|
return distShardShardidIndexId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -411,11 +420,10 @@ DistShardShardidIndexId(void)
|
||||||
Oid
|
Oid
|
||||||
DistShardPlacementShardidIndexId(void)
|
DistShardPlacementShardidIndexId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = InvalidOid;
|
CachedRelationLookup("pg_dist_shard_placement_shardid_index",
|
||||||
|
&distShardPlacementShardidIndexId);
|
||||||
|
|
||||||
CachedRelationLookup("pg_dist_shard_placement_shardid_index", &cachedOid);
|
return distShardPlacementShardidIndexId;
|
||||||
|
|
||||||
return cachedOid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -423,18 +431,17 @@ DistShardPlacementShardidIndexId(void)
|
||||||
Oid
|
Oid
|
||||||
CitusExtraDataContainerFuncId(void)
|
CitusExtraDataContainerFuncId(void)
|
||||||
{
|
{
|
||||||
static Oid cachedOid = 0;
|
|
||||||
List *nameList = NIL;
|
List *nameList = NIL;
|
||||||
Oid paramOids[1] = { INTERNALOID };
|
Oid paramOids[1] = { INTERNALOID };
|
||||||
|
|
||||||
if (cachedOid == InvalidOid)
|
if (extraDataContainerFuncId == InvalidOid)
|
||||||
{
|
{
|
||||||
nameList = list_make2(makeString("pg_catalog"),
|
nameList = list_make2(makeString("pg_catalog"),
|
||||||
makeString("citus_extradata_container"));
|
makeString("citus_extradata_container"));
|
||||||
cachedOid = LookupFuncName(nameList, 1, paramOids, false);
|
extraDataContainerFuncId = LookupFuncName(nameList, 1, paramOids, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cachedOid;
|
return extraDataContainerFuncId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -677,6 +684,24 @@ InvalidateDistRelationCacheCallback(Datum argument, Oid relationId)
|
||||||
cacheEntry->isValid = false;
|
cacheEntry->isValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If pg_dist_partition is being invalidated drop all state
|
||||||
|
* This happens pretty rarely, but most importantly happens during
|
||||||
|
* DROP EXTENSION citus;
|
||||||
|
*/
|
||||||
|
if (relationId != InvalidOid && relationId == distPartitionRelationId)
|
||||||
|
{
|
||||||
|
extensionLoaded = false;
|
||||||
|
distShardRelationId = InvalidOid;
|
||||||
|
distShardPlacementRelationId = InvalidOid;
|
||||||
|
distPartitionRelationId = InvalidOid;
|
||||||
|
distPartitionLogicalRelidIndexId = InvalidOid;
|
||||||
|
distShardLogicalRelidIndexId = InvalidOid;
|
||||||
|
distShardShardidIndexId = InvalidOid;
|
||||||
|
distShardPlacementShardidIndexId = InvalidOid;
|
||||||
|
extraDataContainerFuncId = InvalidOid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -878,10 +903,6 @@ TupleToShardInterval(HeapTuple heapTuple, TupleDesc tupleDescriptor, Oid interva
|
||||||
/*
|
/*
|
||||||
* CachedRelationLookup performs a cached lookup for the relation
|
* CachedRelationLookup performs a cached lookup for the relation
|
||||||
* relationName, with the result cached in *cachedOid.
|
* relationName, with the result cached in *cachedOid.
|
||||||
*
|
|
||||||
* NB: The way this is cached means the result will be wrong after the
|
|
||||||
* extension is dropped and reconnect. A reconnect fixes that though, so that
|
|
||||||
* seems acceptable.
|
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
CachedRelationLookup(const char *relationName, Oid *cachedOid)
|
CachedRelationLookup(const char *relationName, Oid *cachedOid)
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
--
|
||||||
|
-- MULTI_DROP_EXTENSION
|
||||||
|
--
|
||||||
|
-- Tests around dropping and recreating the extension
|
||||||
|
CREATE TABLE testtableddl(somecol int, distributecol text NOT NULL);
|
||||||
|
SELECT master_create_distributed_table('testtableddl', 'distributecol', 'append');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- this emits a NOTICE message for every table we are dropping with our CASCADE. It would
|
||||||
|
-- be nice to check that we get those NOTICE messages, but it's nicer to not have to
|
||||||
|
-- change this test every time the previous tests change the set of tables they leave
|
||||||
|
-- around.
|
||||||
|
SET client_min_messages TO 'WARNING';
|
||||||
|
DROP EXTENSION citus CASCADE;
|
||||||
|
RESET client_min_messages;
|
||||||
|
CREATE EXTENSION citus;
|
||||||
|
-- verify that a table can be created after the extension has been dropped and recreated
|
||||||
|
CREATE TABLE testtableddl(somecol int, distributecol text NOT NULL);
|
||||||
|
SELECT master_create_distributed_table('testtableddl', 'distributecol', 'append');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT 1 FROM master_create_empty_shard('testtableddl');
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM testtableddl;
|
||||||
|
somecol | distributecol
|
||||||
|
---------+---------------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
DROP TABLE testtableddl;
|
|
@ -11,8 +11,6 @@ SELECT master_create_distributed_table('testtableddl', 'distributecol', 'append'
|
||||||
|
|
||||||
-- verify that the citus extension can't be dropped while distributed tables exist
|
-- verify that the citus extension can't be dropped while distributed tables exist
|
||||||
DROP EXTENSION citus;
|
DROP EXTENSION citus;
|
||||||
WARNING: could not clean the metadata cache on DROP EXTENSION command
|
|
||||||
HINT: Reconnect to the server again.
|
|
||||||
ERROR: cannot drop extension citus because other objects depend on it
|
ERROR: cannot drop extension citus because other objects depend on it
|
||||||
DETAIL: table testtableddl depends on extension citus
|
DETAIL: table testtableddl depends on extension citus
|
||||||
HINT: Use DROP ... CASCADE to drop the dependent objects too.
|
HINT: Use DROP ... CASCADE to drop the dependent objects too.
|
||||||
|
@ -62,11 +60,6 @@ SELECT * FROM pg_dist_shard_placement;
|
||||||
---------+------------+-------------+----------+----------
|
---------+------------+-------------+----------+----------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- check that the extension now can be dropped (and recreated). We reconnect
|
-- check that the extension now can be dropped (and recreated)
|
||||||
-- before creating the extension to expire extension specific variables which
|
|
||||||
-- are cached for performance.
|
|
||||||
DROP EXTENSION citus;
|
DROP EXTENSION citus;
|
||||||
WARNING: could not clean the metadata cache on DROP EXTENSION command
|
|
||||||
HINT: Reconnect to the server again.
|
|
||||||
\c
|
|
||||||
CREATE EXTENSION citus;
|
CREATE EXTENSION citus;
|
||||||
|
|
|
@ -135,3 +135,8 @@ test: multi_router_planner
|
||||||
# multi_large_shardid stages more shards into lineitem
|
# multi_large_shardid stages more shards into lineitem
|
||||||
# ----------
|
# ----------
|
||||||
test: multi_large_shardid
|
test: multi_large_shardid
|
||||||
|
|
||||||
|
# ----------
|
||||||
|
# multi_drop_extension makes sure we can safely drop and recreate the extension
|
||||||
|
# ----------
|
||||||
|
test: multi_drop_extension
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
--
|
||||||
|
-- MULTI_DROP_EXTENSION
|
||||||
|
--
|
||||||
|
-- Tests around dropping and recreating the extension
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE testtableddl(somecol int, distributecol text NOT NULL);
|
||||||
|
SELECT master_create_distributed_table('testtableddl', 'distributecol', 'append');
|
||||||
|
|
||||||
|
-- this emits a NOTICE message for every table we are dropping with our CASCADE. It would
|
||||||
|
-- be nice to check that we get those NOTICE messages, but it's nicer to not have to
|
||||||
|
-- change this test every time the previous tests change the set of tables they leave
|
||||||
|
-- around.
|
||||||
|
SET client_min_messages TO 'WARNING';
|
||||||
|
DROP EXTENSION citus CASCADE;
|
||||||
|
RESET client_min_messages;
|
||||||
|
|
||||||
|
CREATE EXTENSION citus;
|
||||||
|
|
||||||
|
-- verify that a table can be created after the extension has been dropped and recreated
|
||||||
|
CREATE TABLE testtableddl(somecol int, distributecol text NOT NULL);
|
||||||
|
SELECT master_create_distributed_table('testtableddl', 'distributecol', 'append');
|
||||||
|
SELECT 1 FROM master_create_empty_shard('testtableddl');
|
||||||
|
SELECT * FROM testtableddl;
|
||||||
|
DROP TABLE testtableddl;
|
|
@ -34,9 +34,6 @@ SELECT * FROM pg_dist_partition;
|
||||||
SELECT * FROM pg_dist_shard;
|
SELECT * FROM pg_dist_shard;
|
||||||
SELECT * FROM pg_dist_shard_placement;
|
SELECT * FROM pg_dist_shard_placement;
|
||||||
|
|
||||||
-- check that the extension now can be dropped (and recreated). We reconnect
|
-- check that the extension now can be dropped (and recreated)
|
||||||
-- before creating the extension to expire extension specific variables which
|
|
||||||
-- are cached for performance.
|
|
||||||
DROP EXTENSION citus;
|
DROP EXTENSION citus;
|
||||||
\c
|
|
||||||
CREATE EXTENSION citus;
|
CREATE EXTENSION citus;
|
||||||
|
|
Loading…
Reference in New Issue