Merge pull request #456 from citusdata/367-drop-extension-messages

DROP EXTENSION without any warnings
pull/464/head
Brian Cloutier 2016-04-22 13:39:08 -07:00
commit 1a8939e30d
7 changed files with 134 additions and 90 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;