Add enable_version_checks GUC and address feedback

pull/1277/head
Burak Yucesoy 2017-04-04 15:37:07 +03:00
parent 1c2056ec74
commit a09614553f
8 changed files with 222 additions and 66 deletions

View File

@ -20,7 +20,7 @@ install-extension: extension
install-headers: extension
$(MKDIR_P) '$(DESTDIR)$(includedir_server)/distributed/'
# generated headers are located in the build directory
$(INSTALL_DATA) $(citus_abs_srcdir)/src/include/citus_config.h '$(DESTDIR)$(includedir_server)/'
$(INSTALL_DATA) $(citus_abs_srcdir)/src/include/citus_version.h '$(DESTDIR)$(includedir_server)/'
# the rest in the source tree
$(INSTALL_DATA) $(citus_abs_srcdir)/src/include/distributed/*.h '$(DESTDIR)$(includedir_server)/distributed/'
clean-extension:

View File

@ -83,7 +83,6 @@
bool EnableDDLPropagation = true; /* ddl propagation is enabled */
/*
* This struct defines the state for the callback for drop statements.
* It is copied as it is from commands/tablecmds.c in Postgres source.
@ -173,6 +172,7 @@ multi_ProcessUtility(Node *parsetree,
int savedSecurityContext = 0;
List *ddlJobs = NIL;
bool extensionStatement = false;
bool checkExtensionVersion = false;
if (IsA(parsetree, TransactionStmt))
{
@ -193,7 +193,7 @@ multi_ProcessUtility(Node *parsetree,
CreateExtensionStmt *createExtensionStmt = (CreateExtensionStmt *) parsetree;
if (strcmp(createExtensionStmt->extname, "citus") == 0)
{
ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree);
checkExtensionVersion = true;
}
extensionStatement = true;
@ -204,7 +204,7 @@ multi_ProcessUtility(Node *parsetree,
AlterExtensionStmt *alterExtensionStmt = (AlterExtensionStmt *) parsetree;
if (strcmp(alterExtensionStmt->extname, "citus") == 0)
{
ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree);
checkExtensionVersion = true;
}
extensionStatement = true;
@ -220,18 +220,23 @@ multi_ProcessUtility(Node *parsetree,
}
}
if (extensionStatement)
if (extensionStatement || IsA(parsetree, VariableSetStmt))
{
/*
* In CitusHasBeenLoaded check below, we compare binary Citus version,
* extension version and available version. If they are different, we
* force user to execute ALTER EXTENSION citus UPDATE. Therefore, if
* user executes ALTER EXTENSION or DROP EXTENSION query we should drop
* to the standart utility before CitusHasBeenLoaded check.
* force user to execute ALTER EXTENSION citus UPDATE. Therefore, we
* drop to standard_ProcessUtility earlier for some commands which are
* safe and necessary to user even in version mismatch situation.
*/
standard_ProcessUtility(parsetree, queryString, context,
params, dest, completionTag);
if (EnableVersionChecks && checkExtensionVersion)
{
ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree);
}
return;
}
@ -1310,7 +1315,7 @@ DeparseVacuumColumnNames(List *columnNameList)
* ErrorIfUnstableCreateOrAlterExtensionStmt compares CITUS_EXTENSIONVERSION
* and version given CREATE/ALTER EXTENSION statement will create/update to. If
* they are not same in major or minor version numbers, this function errors
* out. It ignores the catalog version.
* out. It ignores the schema version.
*/
static void
ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree)
@ -1342,7 +1347,7 @@ ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree)
{
char *newVersion = strVal(defElement->arg);
if (!CompareVersions(newVersion, CITUS_EXTENSIONVERSION))
if (!MajorVersionsCompatible(newVersion, CITUS_EXTENSIONVERSION))
{
ereport(ERROR, (errmsg("requested version is not compatible with "
"loaded Citus binaries.")));
@ -1354,11 +1359,11 @@ ErrorIfUnstableCreateOrAlterExtensionStmt(Node *parsetree)
/*
* new_version is not specified in ALTER EXTENSION statement, PostgreSQL will use
* default_version from citus.control file. We will flush availableMajorVersion to
* re-check the available version from citus.control file.
* default_version from citus.control file. We will flush availableExtensionVersion
* to re-check the available version from citus.control file.
*/
availableMajorVersion = NULL;
ErrorIfNewMajorVersionAvailable();
availableExtensionVersion = NULL;
ErrorIfAvailableVersionMismatch();
}

View File

@ -49,7 +49,7 @@
/* marks shared object as one loadable by the postgres version compiled against */
PG_MODULE_MAGIC;
static char *CitusVersion;
static char *CitusVersion = CITUS_VERSION;
void _PG_init(void);
@ -623,6 +623,16 @@ RegisterCitusConfigVariables(void)
0,
NULL, NULL, NULL);
DefineCustomBoolVariable(
"citus.enable_version_checks",
gettext_noop("Enables version checks in CREATE/ALTER extension queries"),
NULL,
&EnableVersionChecks,
true,
PGC_USERSET,
GUC_NO_SHOW_ALL,
NULL, NULL, NULL);
/* warn about config items in the citus namespace that are not registered above */
EmitWarningsOnPlaceholders("citus");
}

View File

@ -100,8 +100,10 @@ static Oid distTransactionRelationId = InvalidOid;
static Oid distTransactionGroupIndexId = InvalidOid;
static Oid extraDataContainerFuncId = InvalidOid;
/* Citus installed extension version */
char *availableMajorVersion = NULL;
/* Citus extension version variables */
bool EnableVersionChecks = true; /* version checks are enabled */
char *availableExtensionVersion = NULL;
static char *installedExtensionVersion = NULL;
/* Hash table for informations about each partition */
@ -139,8 +141,8 @@ static bool HasUniformHashDistribution(ShardInterval **shardIntervalArray,
int shardIntervalArrayLength);
static bool HasUninitializedShardInterval(ShardInterval **sortedShardIntervalArray,
int shardCount);
static void ErrorIfExtensionUpdateNeeded(void);
static char * AvailableMajorVersion(void);
static void ErrorIfInstalledVersionMismatch(void);
static char * AvailableExtensionVersion(void);
static char * InstalledExtensionVersion(void);
static void InitializeDistTableCache(void);
static void InitializeWorkerNodeCache(void);
@ -984,8 +986,8 @@ CitusHasBeenLoaded(void)
if (extensionLoaded)
{
ErrorIfNewMajorVersionAvailable();
ErrorIfExtensionUpdateNeeded();
ErrorIfAvailableVersionMismatch();
ErrorIfInstalledVersionMismatch();
}
return extensionLoaded;
@ -993,16 +995,23 @@ CitusHasBeenLoaded(void)
/*
* ErrorIfNewMajorVersionAvailable compares CITUS_EXTENSIONVERSION and currently
* available version from citus.control file. If they are not same in major or
* minor version numbers, this function errors out. It ignores the schema version.
* ErrorIfAvailableExtensionVersionMismatch compares CITUS_EXTENSIONVERSION and
* currently available version from citus.control file. If they are not same in
* major or minor version numbers, this function errors out. It ignores the schema
* version.
*/
void
ErrorIfNewMajorVersionAvailable(void)
ErrorIfAvailableVersionMismatch(void)
{
char *availableVersion = AvailableMajorVersion();
char *availableVersion = NULL;
if (!CompareVersions(availableVersion, CITUS_EXTENSIONVERSION))
if (!EnableVersionChecks)
{
return;
}
availableVersion = AvailableExtensionVersion();
if (!MajorVersionsCompatible(availableVersion, CITUS_EXTENSIONVERSION))
{
ereport(ERROR, (errmsg("server restart is needed because, loaded Citus binaries "
"does not match the available extension version")));
@ -1011,16 +1020,23 @@ ErrorIfNewMajorVersionAvailable(void)
/*
* ErrorIfExtensionUpdateNeeded compares CITUS_EXTENSIONVERSION and currently and
* catalog version from pg_extemsion catalog table. If they are not same in major or
* minor version numbers, this function errors out. It ignores the schema version.
* ErrorIfInstalledVersionMismatch compares CITUS_EXTENSIONVERSION and currently
* and catalog version from pg_extemsion catalog table. If they are not same in
* major or minor version numbers, this function errors out. It ignores the schema
* version.
*/
static void
ErrorIfExtensionUpdateNeeded(void)
ErrorIfInstalledVersionMismatch(void)
{
char *installedVersion = InstalledExtensionVersion();
char *installedVersion = NULL;
if (!CompareVersions(installedVersion, CITUS_EXTENSIONVERSION))
if (!EnableVersionChecks)
{
return;
}
installedVersion = InstalledExtensionVersion();
if (!MajorVersionsCompatible(installedVersion, CITUS_EXTENSIONVERSION))
{
ereport(ERROR, (errmsg("\"ALTER EXTENSION citus UPDATE;\" is needed, because "
"loaded Citus binaries does not match the installed "
@ -1030,36 +1046,55 @@ ErrorIfExtensionUpdateNeeded(void)
/*
* CompareVersions compares given two versions. If they are same in major and
* minor version numbers, this function returns true. It ignores the schema version.
* MajorVersionsCompatible compares given two versions. If they are same in major
* and minor version numbers, this function returns true. It ignores the schema
* version.
*/
bool
CompareVersions(char *leftVersion, char *rightVersion)
MajorVersionsCompatible(char *leftVersion, char *rightVersion)
{
const char schemaVersionSeparator = '-';
char *seperatorPosition = strchr(leftVersion, schemaVersionSeparator);
int comparisionLimit = 0;
if (seperatorPosition != NULL)
char *leftSeperatorPosition = strchr(leftVersion, schemaVersionSeparator);
char *rightSeperatorPosition = strchr(rightVersion, schemaVersionSeparator);
int leftComparisionLimit = 0;
int rightComparisionLimit = 0;
if (leftSeperatorPosition != NULL)
{
comparisionLimit = seperatorPosition - leftVersion;
leftComparisionLimit = leftSeperatorPosition - leftVersion;
}
else
{
comparisionLimit = strlen(leftVersion);
leftComparisionLimit = strlen(leftVersion);
}
return strncmp(leftVersion, rightVersion, comparisionLimit) == 0;
if (rightSeperatorPosition != NULL)
{
rightComparisionLimit = rightSeperatorPosition - rightVersion;
}
else
{
rightComparisionLimit = strlen(leftVersion);
}
/* we can error out early if hypens are not in the same position */
if (leftComparisionLimit != rightComparisionLimit)
{
return false;
}
return strncmp(leftVersion, rightVersion, leftComparisionLimit) == 0;
}
/*
* AvailableMajorVersion returns the Citus version from citus.control file. It also
* AvailableExtensionVersion returns the Citus version from citus.control file. It also
* saves the result, thus consecutive calls to CitusExtensionAvailableVersion will
* not read the citus.control file again.
*/
static char *
AvailableMajorVersion(void)
AvailableExtensionVersion(void)
{
ReturnSetInfo *extensionsResultSet = NULL;
TupleTableSlot *tupleTableSlot = NULL;
@ -1073,9 +1108,9 @@ AvailableMajorVersion(void)
bool doCopy = false;
/* if we cached the result before, return it*/
if (availableMajorVersion != NULL)
if (availableExtensionVersion != NULL)
{
return availableMajorVersion;
return availableExtensionVersion;
}
estate = CreateExecutorState();
@ -1107,7 +1142,7 @@ AvailableMajorVersion(void)
if (strcmp(extensionName, "citus") == 0)
{
MemoryContext oldMemoryContext = NULL;
Datum citusVersionDatum = slot_getattr(tupleTableSlot, 2, &isNull);
Datum availableVersion = slot_getattr(tupleTableSlot, 2, &isNull);
/* we will cache the result of citus version to prevent catalog access */
if (CacheMemoryContext == NULL)
@ -1116,14 +1151,14 @@ AvailableMajorVersion(void)
}
oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext);
availableMajorVersion = text_to_cstring(DatumGetTextPP(citusVersionDatum));
availableExtensionVersion = text_to_cstring(DatumGetTextPP(availableVersion));
MemoryContextSwitchTo(oldMemoryContext);
ExecClearTuple(tupleTableSlot);
ExecDropSingleTupleTableSlot(tupleTableSlot);
return availableMajorVersion;
return availableExtensionVersion;
}
ExecClearTuple(tupleTableSlot);
@ -1177,8 +1212,8 @@ InstalledExtensionVersion(void)
TupleDesc tupleDescriptor = RelationGetDescr(relation);
bool isNull = false;
Datum extensionVersionDatum = heap_getattr(extensionTuple, extensionIndex,
tupleDescriptor, &isNull);
Datum installedVersion = heap_getattr(extensionTuple, extensionIndex,
tupleDescriptor, &isNull);
if (isNull)
{
@ -1194,8 +1229,7 @@ InstalledExtensionVersion(void)
oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext);
installedExtensionVersion = text_to_cstring(DatumGetTextPP(
extensionVersionDatum));
installedExtensionVersion = text_to_cstring(DatumGetTextPP(installedVersion));
MemoryContextSwitchTo(oldMemoryContext);
}

View File

@ -17,7 +17,8 @@
#include "distributed/worker_manager.h"
#include "utils/hsearch.h"
extern char *availableMajorVersion;
extern bool EnableVersionChecks;
extern char *availableExtensionVersion;
/*
* Representation of a table's metadata that is frequently used for
@ -69,8 +70,8 @@ extern void CitusInvalidateRelcacheByRelid(Oid relationId);
extern void CitusInvalidateRelcacheByShardId(int64 shardId);
extern bool CitusHasBeenLoaded(void);
void ErrorIfNewMajorVersionAvailable(void);
bool CompareVersions(char *leftVersion, char *rightVersion);
void ErrorIfAvailableVersionMismatch(void);
bool MajorVersionsCompatible(char *leftVersion, char *rightVersion);
/* access WorkerNodeHash */
extern HTAB * GetWorkerNodeHash(void);

View File

@ -13,6 +13,7 @@
#include "tcop/utility.h"
extern bool EnableDDLPropagation;
extern bool EnableVersionChecks;
/*
* A DDLJob encapsulates the remote tasks and commands needed to process all or

View File

@ -24,11 +24,59 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
-- DROP EXTENSION pre-created by the regression suite
DROP EXTENSION citus;
\c
-- Create extension in oldest version, this is expected to fail
SET citus.enable_version_checks TO 'false';
-- Create extension in oldest version
CREATE EXTENSION citus VERSION '5.0';
ERROR: requested version is not compatible with loaded Citus binaries.
-- Create extension in newest major version, test every upgrade step
CREATE EXTENSION citus VERSION '6.2-1';
ALTER EXTENSION citus UPDATE TO '5.0-1';
ALTER EXTENSION citus UPDATE TO '5.0-2';
ALTER EXTENSION citus UPDATE TO '5.1-1';
ALTER EXTENSION citus UPDATE TO '5.1-2';
ALTER EXTENSION citus UPDATE TO '5.1-3';
ALTER EXTENSION citus UPDATE TO '5.1-4';
ALTER EXTENSION citus UPDATE TO '5.1-5';
ALTER EXTENSION citus UPDATE TO '5.1-6';
ALTER EXTENSION citus UPDATE TO '5.1-7';
ALTER EXTENSION citus UPDATE TO '5.1-8';
ALTER EXTENSION citus UPDATE TO '5.2-1';
ALTER EXTENSION citus UPDATE TO '5.2-2';
ALTER EXTENSION citus UPDATE TO '5.2-3';
ALTER EXTENSION citus UPDATE TO '5.2-4';
ALTER EXTENSION citus UPDATE TO '6.0-1';
ALTER EXTENSION citus UPDATE TO '6.0-2';
ALTER EXTENSION citus UPDATE TO '6.0-3';
ALTER EXTENSION citus UPDATE TO '6.0-4';
ALTER EXTENSION citus UPDATE TO '6.0-5';
ALTER EXTENSION citus UPDATE TO '6.0-6';
ALTER EXTENSION citus UPDATE TO '6.0-7';
ALTER EXTENSION citus UPDATE TO '6.0-8';
ALTER EXTENSION citus UPDATE TO '6.0-9';
ALTER EXTENSION citus UPDATE TO '6.0-10';
ALTER EXTENSION citus UPDATE TO '6.0-11';
ALTER EXTENSION citus UPDATE TO '6.0-12';
ALTER EXTENSION citus UPDATE TO '6.0-13';
ALTER EXTENSION citus UPDATE TO '6.0-14';
ALTER EXTENSION citus UPDATE TO '6.0-15';
ALTER EXTENSION citus UPDATE TO '6.0-16';
ALTER EXTENSION citus UPDATE TO '6.0-17';
ALTER EXTENSION citus UPDATE TO '6.0-18';
ALTER EXTENSION citus UPDATE TO '6.1-1';
ALTER EXTENSION citus UPDATE TO '6.1-2';
ALTER EXTENSION citus UPDATE TO '6.1-3';
ALTER EXTENSION citus UPDATE TO '6.1-4';
ALTER EXTENSION citus UPDATE TO '6.1-5';
ALTER EXTENSION citus UPDATE TO '6.1-6';
ALTER EXTENSION citus UPDATE TO '6.1-7';
ALTER EXTENSION citus UPDATE TO '6.1-8';
ALTER EXTENSION citus UPDATE TO '6.1-9';
ALTER EXTENSION citus UPDATE TO '6.1-10';
ALTER EXTENSION citus UPDATE TO '6.1-11';
ALTER EXTENSION citus UPDATE TO '6.1-12';
ALTER EXTENSION citus UPDATE TO '6.1-13';
ALTER EXTENSION citus UPDATE TO '6.1-14';
ALTER EXTENSION citus UPDATE TO '6.1-15';
ALTER EXTENSION citus UPDATE TO '6.1-16';
ALTER EXTENSION citus UPDATE TO '6.1-17';
ALTER EXTENSION citus UPDATE TO '6.2-1';
ALTER EXTENSION citus UPDATE TO '6.2-2';
-- show running version
SHOW citus.version;
@ -51,7 +99,11 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
0
(1 row)
-- drop extension an re-create in newest version
-- see incompatible version errors out
DROP EXTENSION citus;
\c
CREATE EXTENSION citus VERSION '5.0';
ERROR: requested version is not compatible with loaded Citus binaries.
-- re-create in newest version
\c
CREATE EXTENSION citus;

View File

@ -24,11 +24,60 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
DROP EXTENSION citus;
\c
-- Create extension in oldest version, this is expected to fail
CREATE EXTENSION citus VERSION '5.0';
SET citus.enable_version_checks TO 'false';
-- Create extension in newest major version, test every upgrade step
CREATE EXTENSION citus VERSION '6.2-1';
-- Create extension in oldest version
CREATE EXTENSION citus VERSION '5.0';
ALTER EXTENSION citus UPDATE TO '5.0-1';
ALTER EXTENSION citus UPDATE TO '5.0-2';
ALTER EXTENSION citus UPDATE TO '5.1-1';
ALTER EXTENSION citus UPDATE TO '5.1-2';
ALTER EXTENSION citus UPDATE TO '5.1-3';
ALTER EXTENSION citus UPDATE TO '5.1-4';
ALTER EXTENSION citus UPDATE TO '5.1-5';
ALTER EXTENSION citus UPDATE TO '5.1-6';
ALTER EXTENSION citus UPDATE TO '5.1-7';
ALTER EXTENSION citus UPDATE TO '5.1-8';
ALTER EXTENSION citus UPDATE TO '5.2-1';
ALTER EXTENSION citus UPDATE TO '5.2-2';
ALTER EXTENSION citus UPDATE TO '5.2-3';
ALTER EXTENSION citus UPDATE TO '5.2-4';
ALTER EXTENSION citus UPDATE TO '6.0-1';
ALTER EXTENSION citus UPDATE TO '6.0-2';
ALTER EXTENSION citus UPDATE TO '6.0-3';
ALTER EXTENSION citus UPDATE TO '6.0-4';
ALTER EXTENSION citus UPDATE TO '6.0-5';
ALTER EXTENSION citus UPDATE TO '6.0-6';
ALTER EXTENSION citus UPDATE TO '6.0-7';
ALTER EXTENSION citus UPDATE TO '6.0-8';
ALTER EXTENSION citus UPDATE TO '6.0-9';
ALTER EXTENSION citus UPDATE TO '6.0-10';
ALTER EXTENSION citus UPDATE TO '6.0-11';
ALTER EXTENSION citus UPDATE TO '6.0-12';
ALTER EXTENSION citus UPDATE TO '6.0-13';
ALTER EXTENSION citus UPDATE TO '6.0-14';
ALTER EXTENSION citus UPDATE TO '6.0-15';
ALTER EXTENSION citus UPDATE TO '6.0-16';
ALTER EXTENSION citus UPDATE TO '6.0-17';
ALTER EXTENSION citus UPDATE TO '6.0-18';
ALTER EXTENSION citus UPDATE TO '6.1-1';
ALTER EXTENSION citus UPDATE TO '6.1-2';
ALTER EXTENSION citus UPDATE TO '6.1-3';
ALTER EXTENSION citus UPDATE TO '6.1-4';
ALTER EXTENSION citus UPDATE TO '6.1-5';
ALTER EXTENSION citus UPDATE TO '6.1-6';
ALTER EXTENSION citus UPDATE TO '6.1-7';
ALTER EXTENSION citus UPDATE TO '6.1-8';
ALTER EXTENSION citus UPDATE TO '6.1-9';
ALTER EXTENSION citus UPDATE TO '6.1-10';
ALTER EXTENSION citus UPDATE TO '6.1-11';
ALTER EXTENSION citus UPDATE TO '6.1-12';
ALTER EXTENSION citus UPDATE TO '6.1-13';
ALTER EXTENSION citus UPDATE TO '6.1-14';
ALTER EXTENSION citus UPDATE TO '6.1-15';
ALTER EXTENSION citus UPDATE TO '6.1-16';
ALTER EXTENSION citus UPDATE TO '6.1-17';
ALTER EXTENSION citus UPDATE TO '6.2-1';
ALTER EXTENSION citus UPDATE TO '6.2-2';
-- show running version
@ -44,7 +93,11 @@ WHERE pgd.refclassid = 'pg_extension'::regclass AND
pge.extname = 'citus' AND
pgio.schema NOT IN ('pg_catalog', 'citus');
-- drop extension an re-create in newest version
-- see incompatible version errors out
DROP EXTENSION citus;
\c
CREATE EXTENSION citus VERSION '5.0';
-- re-create in newest version
\c
CREATE EXTENSION citus;