summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2017-02-20 07:44:19 +0000
committerPavan Deolasee2017-05-05 04:59:34 +0000
commit77e5c18763be07607c7f1b1ec1ac14eb034f4eb4 (patch)
tree35cf4d60552166190277128942d8bc892b48381f
parent416f11f2610738c87e7da8c25b1e284359e5835e (diff)
Handle sequence's transactional behaviour on GTM
Previously we were tracking changes to sequences on the coordinator side and applying those changes at transaction commit/rollback time. While this worked ok for most cases, there were issues such as what happens if a sequence is dropped and then recreated in the same transaction. Since the DROP is not executed until the transaction commit time, the subsequent CREATE would fail on the GTM. We now track sequences renamed/dropped/created on the GTM side and do a cleanup on transaction commit/rollback. For example, if a sequence is renamed but the transaction is later aborted, the sequence will be renamed back to its original name. Similarly, if a sequence is dropped and the transaction aborts, the sequence will be re-instated.
-rw-r--r--src/backend/access/transam/gtm.c12
-rw-r--r--src/backend/catalog/dependency.c11
-rw-r--r--src/backend/commands/sequence.c133
-rw-r--r--src/backend/commands/tablecmds.c6
-rw-r--r--src/gtm/client/gtm_client.c82
-rw-r--r--src/gtm/main/gtm_seq.c365
-rw-r--r--src/gtm/main/gtm_txn.c127
-rw-r--r--src/include/commands/sequence.h6
-rw-r--r--src/include/gtm/gtm_client.h16
-rw-r--r--src/include/gtm/gtm_seq.h15
-rw-r--r--src/include/gtm/gtm_txn.h8
-rw-r--r--src/test/regress/expected/xc_sequence.out292
-rw-r--r--src/test/regress/sql/xc_sequence.sql129
13 files changed, 945 insertions, 257 deletions
diff --git a/src/backend/access/transam/gtm.c b/src/backend/access/transam/gtm.c
index 210e70b175..e8b793d6fa 100644
--- a/src/backend/access/transam/gtm.c
+++ b/src/backend/access/transam/gtm.c
@@ -16,6 +16,7 @@
#include "gtm/gtm_client.h"
#include "access/gtm.h"
#include "access/transam.h"
+#include "access/xact.h"
#include "utils/elog.h"
#include "miscadmin.h"
#include "pgxc/pgxc.h"
@@ -470,7 +471,8 @@ CreateSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval,
seqkey.gsk_keylen = strlen(seqname) + 1;
seqkey.gsk_key = seqname;
- return conn ? open_sequence(conn, &seqkey, increment, minval, maxval, startval, cycle) : 0;
+ return conn ? open_sequence(conn, &seqkey, increment, minval, maxval,
+ startval, cycle, GetTopTransactionId()) : 0;
}
/*
@@ -485,7 +487,8 @@ AlterSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval,
seqkey.gsk_keylen = strlen(seqname) + 1;
seqkey.gsk_key = seqname;
- return conn ? alter_sequence(conn, &seqkey, increment, minval, maxval, startval, lastval, cycle, is_restart) : 0;
+ return conn ? alter_sequence(conn, &seqkey, increment, minval, maxval,
+ startval, lastval, cycle, is_restart) : 0;
}
/*
@@ -596,7 +599,7 @@ DropSequenceGTM(char *name, GTM_SequenceKeyType type)
seqkey.gsk_key = name;
seqkey.gsk_type = type;
- return conn ? close_sequence(conn, &seqkey) : -1;
+ return conn ? close_sequence(conn, &seqkey, GetTopTransactionId()) : -1;
}
/*
@@ -612,7 +615,8 @@ RenameSequenceGTM(char *seqname, const char *newseqname)
newseqkey.gsk_keylen = strlen(newseqname) + 1;
newseqkey.gsk_key = (char *) newseqname;
- return conn ? rename_sequence(conn, &seqkey, &newseqkey) : -1;
+ return conn ? rename_sequence(conn, &seqkey, &newseqkey,
+ GetTopTransactionId()) : -1;
}
/*
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 8fb46e8eb1..3aa884599c 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -440,8 +440,6 @@ doRename(const ObjectAddress *object, const char *oldname, const char *newname)
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("GTM error, could not rename sequence")));
- /* Register a rename callback in case transaction is dropped */
- register_sequence_rename_cb(seqname, newseqname);
pfree(seqname);
pfree(newseqname);
@@ -1297,14 +1295,7 @@ doDeletion(const ObjectAddress *object, int flags)
*/
relseq = relation_open(object->objectId, AccessShareLock);
seqname = GetGlobalSeqName(relseq, NULL, NULL);
-
- /*
- * Sequence is not immediately removed on GTM, but at the end
- * of the transaction block. In case this transaction fails,
- * all the data remains intact on GTM.
- */
- register_sequence_cb(seqname, GTM_SEQ_FULL_NAME, GTM_DROP_SEQ);
-
+ DropSequenceGTM(seqname, GTM_SEQ_FULL_NAME);
pfree(seqname);
/* Then close the relation opened previously */
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 96d0e6d475..6dd9536cd3 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -349,8 +349,6 @@ DefineSequence(CreateSeqStmt *seq)
errmsg("GTM error, could not create sequence")));
}
- /* Define a callback to drop sequence on GTM in case transaction fails */
- register_sequence_cb(seqname, GTM_SEQ_FULL_NAME, GTM_CREATE_SEQ);
pfree(seqname);
}
@@ -2048,134 +2046,3 @@ ResetSequenceCaches(void)
last_used_seq = NULL;
}
-
-#ifdef PGXC
-/*
- * Register a callback for a sequence rename drop on GTM
- */
-void
-register_sequence_rename_cb(char *oldseqname, char *newseqname)
-{
- rename_sequence_callback_arg *args;
- char *oldseqnamearg = NULL;
- char *newseqnamearg = NULL;
-
- /* All the arguments are transaction-dependent, so save them in TopTransactionContext */
- args = (rename_sequence_callback_arg *)
- MemoryContextAlloc(TopTransactionContext, sizeof(rename_sequence_callback_arg));
-
- oldseqnamearg = MemoryContextAlloc(TopTransactionContext, strlen(oldseqname) + 1);
- newseqnamearg = MemoryContextAlloc(TopTransactionContext, strlen(newseqname) + 1);
- sprintf(oldseqnamearg, "%s", oldseqname);
- sprintf(newseqnamearg, "%s", newseqname);
-
- args->oldseqname = oldseqnamearg;
- args->newseqname = newseqnamearg;
-
- RegisterGTMCallback(rename_sequence_cb, (void *) args);
-}
-
-/*
- * Callback a sequence rename
- */
-void
-rename_sequence_cb(GTMEvent event, void *args)
-{
- rename_sequence_callback_arg *cbargs = (rename_sequence_callback_arg *) args;
- char *newseqname = cbargs->newseqname;
- char *oldseqname = cbargs->oldseqname;
- int err = 0;
-
- /*
- * A sequence is here renamed to its former name only when a transaction
- * that involved a sequence rename was dropped.
- */
- switch (event)
- {
- case GTM_EVENT_ABORT:
- /*
- * Here sequence is renamed to its former name
- * so what was new becomes old.
- */
- err = RenameSequenceGTM(newseqname, oldseqname);
- break;
- case GTM_EVENT_COMMIT:
- case GTM_EVENT_PREPARE:
- /* Nothing to do */
- break;
- default:
- Assert(0);
- }
-
- /* Report error if necessary */
- if (err < 0 && event != GTM_EVENT_ABORT)
- ereport(ERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("GTM error, could not rename sequence")));
-}
-
-
-/*
- * Register a callback for a sequence drop on GTM
- */
-void
-register_sequence_cb(char *seqname, GTM_SequenceKeyType key, GTM_SequenceDropType type)
-{
- drop_sequence_callback_arg *args;
- char *seqnamearg = NULL;
-
- /* All the arguments are transaction-dependent, so save them in TopTransactionContext */
- args = (drop_sequence_callback_arg *)
- MemoryContextAlloc(TopTransactionContext, sizeof(drop_sequence_callback_arg));
-
- seqnamearg = MemoryContextAlloc(TopTransactionContext, strlen(seqname) + 1);
- sprintf(seqnamearg, "%s", seqname);
- args->seqname = seqnamearg;
- args->key = key;
- args->type = type;
-
- RegisterGTMCallback(drop_sequence_cb, (void *) args);
-}
-
-/*
- * Callback of sequence drop
- */
-void
-drop_sequence_cb(GTMEvent event, void *args)
-{
- drop_sequence_callback_arg *cbargs = (drop_sequence_callback_arg *) args;
- char *seqname = cbargs->seqname;
- GTM_SequenceKeyType key = cbargs->key;
- GTM_SequenceDropType type = cbargs->type;
- int err = 0;
-
- /*
- * A sequence is dropped on GTM if the transaction that created sequence
- * aborts or if the transaction that dropped the sequence commits. This mechanism
- * insures that sequence information is consistent on all the cluster nodes including
- * GTM. This callback is done before transaction really commits so it can still fail
- * if an error occurs.
- */
- switch (event)
- {
- case GTM_EVENT_COMMIT:
- case GTM_EVENT_PREPARE:
- if (type == GTM_DROP_SEQ)
- err = DropSequenceGTM(seqname, key);
- break;
- case GTM_EVENT_ABORT:
- if (type == GTM_CREATE_SEQ)
- err = DropSequenceGTM(seqname, key);
- break;
- default:
- /* Should not come here */
- Assert(0);
- }
-
- /* Report error if necessary */
- if (err < 0 && event != GTM_EVENT_ABORT)
- ereport(ERROR,
- (errcode(ERRCODE_CONNECTION_FAILURE),
- errmsg("GTM error, could not drop sequence")));
-}
-#endif
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ecaa7c32a0..a523113b9f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -2734,8 +2734,6 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("GTM error, could not rename sequence")));
- /* Register a rename callback in case transaction is dropped */
- register_sequence_rename_cb(seqname, newseqname);
pfree(seqname);
pfree(newseqname);
@@ -12136,8 +12134,6 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("GTM error, could not rename sequence")));
- /* Register a rename callback in case transaction is dropped */
- register_sequence_rename_cb(seqname, newseqname);
pfree(seqname);
pfree(newseqname);
@@ -12346,8 +12342,6 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
(errcode(ERRCODE_CONNECTION_FAILURE),
errmsg("GTM error, could not rename sequence")));
- /* Register a rename callback in case transaction is dropped */
- register_sequence_rename_cb(seqname, newseqname);
pfree(seqname);
pfree(newseqname);
diff --git a/src/gtm/client/gtm_client.c b/src/gtm/client/gtm_client.c
index 126ff30ca4..4ac13faeb6 100644
--- a/src/gtm/client/gtm_client.c
+++ b/src/gtm/client/gtm_client.c
@@ -56,7 +56,8 @@ static int abort_transaction_multi_internal(GTM_Conn *conn, int txn_count, Globa
int *txn_count_out, int *status_out, bool is_backup);
static int open_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle, bool is_backup);
+ GTM_Sequence startval, bool cycle,
+ GlobalTransactionId gxid, bool is_backup);
static int get_next_internal(GTM_Conn *conn, GTM_SequenceKey key,
char *coord_name, int coord_procid, GTM_Sequence range,
GTM_Sequence *result, GTM_Sequence *rangemax, bool is_backup);
@@ -68,11 +69,14 @@ static int commit_transaction_internal(GTM_Conn *conn, GlobalTransactionId gxid,
int waited_xid_count,
GlobalTransactionId *waited_xids,
bool is_backup);
-static int close_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, bool is_backup);
-static int rename_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey, bool is_backup);
+static int close_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key,
+ GlobalTransactionId gxid, bool is_backup);
+static int rename_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key,
+ GTM_SequenceKey newkey, GlobalTransactionId gxid, bool is_backup);
static int alter_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
- GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart, bool is_backup);
+ GTM_Sequence minval, GTM_Sequence maxval,
+ GTM_Sequence startval, GTM_Sequence lastval, bool cycle,
+ bool is_restart, bool is_backup);
static int node_register_worker(GTM_Conn *conn, GTM_PGXCNodeType type, const char *host, GTM_PGXCNodePort port,
char *node_name, char *datafolder,
GTM_PGXCNodeStatus status, bool is_backup);
@@ -1139,23 +1143,31 @@ send_failed:
int
open_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle)
+ GTM_Sequence startval,
+ bool cycle,
+ GlobalTransactionId gxid)
{
- return open_sequence_internal(conn, key, increment, minval, maxval, startval, cycle, false);
+ return open_sequence_internal(conn, key, increment, minval, maxval,
+ startval, cycle, gxid, false);
}
int
bkup_open_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle)
+ GTM_Sequence startval,
+ bool cycle,
+ GlobalTransactionId gxid)
{
- return open_sequence_internal(conn, key, increment, minval, maxval, startval, cycle, true);
+ return open_sequence_internal(conn, key, increment, minval, maxval,
+ startval, cycle, gxid, true);
}
static int
open_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle, bool is_backup)
+ GTM_Sequence startval, bool cycle,
+ GlobalTransactionId gxid,
+ bool is_backup)
{
GTM_Result *res = NULL;
time_t finish_time;
@@ -1169,7 +1181,8 @@ open_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increme
gtmpqPutnchar((char *)&minval, sizeof (GTM_Sequence), conn) ||
gtmpqPutnchar((char *)&maxval, sizeof (GTM_Sequence), conn) ||
gtmpqPutnchar((char *)&startval, sizeof (GTM_Sequence), conn) ||
- gtmpqPutc(cycle, conn))
+ gtmpqPutc(cycle, conn) ||
+ gtmpqPutnchar((char *)&gxid, sizeof (GlobalTransactionId), conn))
goto send_failed;
/* Finish the message. */
@@ -1204,23 +1217,28 @@ send_failed:
int
alter_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart)
+ GTM_Sequence startval, GTM_Sequence lastval, bool cycle,
+ bool is_restart)
{
- return alter_sequence_internal(conn, key, increment, minval, maxval, startval, lastval, cycle, is_restart, false);
+ return alter_sequence_internal(conn, key, increment, minval, maxval,
+ startval, lastval, cycle, is_restart, false);
}
int
bkup_alter_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart)
+ GTM_Sequence startval, GTM_Sequence lastval, bool cycle,
+ bool is_restart)
{
- return alter_sequence_internal(conn, key, increment, minval, maxval, startval, lastval, cycle, is_restart, true);
+ return alter_sequence_internal(conn, key, increment, minval, maxval,
+ startval, lastval, cycle, is_restart, true);
}
static int
alter_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart, bool is_backup)
+ GTM_Sequence startval, GTM_Sequence lastval, bool cycle,
+ bool is_restart, bool is_backup)
{
GTM_Result *res = NULL;
time_t finish_time;
@@ -1269,19 +1287,22 @@ send_failed:
}
int
-close_sequence(GTM_Conn *conn, GTM_SequenceKey key)
+close_sequence(GTM_Conn *conn, GTM_SequenceKey key, GlobalTransactionId gxid)
{
- return close_sequence_internal(conn, key, false);
+ return close_sequence_internal(conn, key, gxid, false);
}
int
-bkup_close_sequence(GTM_Conn *conn, GTM_SequenceKey key)
+bkup_close_sequence(GTM_Conn *conn, GTM_SequenceKey key,
+ GlobalTransactionId gxid)
{
- return close_sequence_internal(conn, key, true);
+ return close_sequence_internal(conn, key, gxid, true);
}
static int
-close_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, bool is_backup)
+close_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key,
+ GlobalTransactionId gxid,
+ bool is_backup)
{
GTM_Result *res = NULL;
time_t finish_time;
@@ -1291,7 +1312,8 @@ close_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, bool is_backup)
gtmpqPutInt(is_backup ? MSG_BKUP_SEQUENCE_CLOSE : MSG_SEQUENCE_CLOSE, sizeof (GTM_MessageType), conn) ||
gtmpqPutInt(key->gsk_keylen, 4, conn) ||
gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn) ||
- gtmpqPutnchar((char *)&key->gsk_type, sizeof(GTM_SequenceKeyType), conn))
+ gtmpqPutnchar((char *)&key->gsk_type, sizeof(GTM_SequenceKeyType), conn) ||
+ gtmpqPutnchar((char *)&gxid, sizeof (GlobalTransactionId), conn))
goto send_failed;
/* Finish the message. */
@@ -1324,19 +1346,22 @@ send_failed:
}
int
-rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey)
+rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey,
+ GlobalTransactionId gxid)
{
- return rename_sequence_internal(conn, key, newkey, false);
+ return rename_sequence_internal(conn, key, newkey, gxid, false);
}
int
-bkup_rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey)
+bkup_rename_sequence(GTM_Conn *conn, GTM_SequenceKey key,
+ GTM_SequenceKey newkey, GlobalTransactionId gxid)
{
- return rename_sequence_internal(conn, key, newkey, true);
+ return rename_sequence_internal(conn, key, newkey, gxid, true);
}
static int
-rename_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey, bool is_backup)
+rename_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey,
+ GlobalTransactionId gxid, bool is_backup)
{
GTM_Result *res = NULL;
time_t finish_time;
@@ -1347,7 +1372,8 @@ rename_sequence_internal(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey ne
gtmpqPutInt(key->gsk_keylen, 4, conn) ||
gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn)||
gtmpqPutInt(newkey->gsk_keylen, 4, conn) ||
- gtmpqPutnchar(newkey->gsk_key, newkey->gsk_keylen, conn))
+ gtmpqPutnchar(newkey->gsk_key, newkey->gsk_keylen, conn) ||
+ gtmpqPutnchar((char *)&gxid, sizeof (GlobalTransactionId), conn))
goto send_failed;
/* Finish the message. */
diff --git a/src/gtm/main/gtm_seq.c b/src/gtm/main/gtm_seq.c
index 2b3868ec5e..5ff1ee0fdd 100644
--- a/src/gtm/main/gtm_seq.c
+++ b/src/gtm/main/gtm_seq.c
@@ -37,6 +37,12 @@ typedef struct GTM_SeqInfoHashBucket
GTM_RWLock shb_lock;
} GTM_SeqInfoHashBucket;
+typedef struct GTM_SeqAlteredInfo
+{
+ GTM_SequenceKey curr_key;
+ GTM_SequenceKey prev_key;
+} GTM_SeqAlteredInfo;
+
#define SEQ_HASH_TABLE_SIZE 1024
static GTM_SeqInfoHashBucket GTMSequences[SEQ_HASH_TABLE_SIZE];
@@ -47,6 +53,9 @@ static GTM_SeqInfo *seq_find_seqinfo(GTM_SequenceKey seqkey);
static int seq_release_seqinfo(GTM_SeqInfo *seqinfo);
static int seq_add_seqinfo(GTM_SeqInfo *seqinfo);
static int seq_remove_seqinfo(GTM_SeqInfo *seqinfo);
+static int seq_rename_seqinfo(GTM_SeqInfo *seqinfo, GTM_SequenceKey newkey);
+static GTM_SequenceKey seq_copy_key_context(GTM_SequenceKey key,
+ MemoryContext context);
static GTM_SequenceKey seq_copy_key(GTM_SequenceKey key);
static int seq_drop_with_dbkey(GTM_SequenceKey nsp);
static bool GTM_NeedSeqRestoreUpdateInternal(GTM_SeqInfo *seqinfo);
@@ -221,6 +230,107 @@ seq_remove_seqinfo(GTM_SeqInfo *seqinfo)
return 0;
}
+/*
+ * Rename sequence managed by seqinfo to "newkey".
+ *
+ * The sequence is moved to the new bucket and rest of the fields remain
+ * unchanged.
+ */
+static int
+seq_rename_seqinfo(GTM_SeqInfo *seqinfo, GTM_SequenceKey newkey)
+{
+ uint32 oldhash = seq_gethash(seqinfo->gs_key);
+ uint32 newhash = seq_gethash(newkey);
+ GTM_SeqInfoHashBucket *oldbucket;
+ GTM_SeqInfoHashBucket *newbucket;
+ gtm_ListCell *elem;
+ MemoryContext oldContext;
+
+ oldbucket = &GTMSequences[oldhash];
+ newbucket = &GTMSequences[newhash];
+
+ /*
+ * We must lock both old and new hash buckets. To avoid deadlock, we must
+ * ensure that we don't try to lock the same bucket twice (in case old and
+ * new keys are mapped to the same bucket) and also lock them in the same
+ * order.
+ */
+ if (oldhash < newhash)
+ {
+ GTM_RWLockAcquire(&oldbucket->shb_lock, GTM_LOCKMODE_WRITE);
+ GTM_RWLockAcquire(&newbucket->shb_lock, GTM_LOCKMODE_WRITE);
+ }
+ else if (oldhash > newhash)
+ {
+ GTM_RWLockAcquire(&newbucket->shb_lock, GTM_LOCKMODE_WRITE);
+ GTM_RWLockAcquire(&oldbucket->shb_lock, GTM_LOCKMODE_WRITE);
+ }
+ else
+ /* old and new buckets are just the same */
+ GTM_RWLockAcquire(&newbucket->shb_lock, GTM_LOCKMODE_WRITE);
+
+ GTM_RWLockAcquire(&seqinfo->gs_lock, GTM_LOCKMODE_WRITE);
+
+ gtm_foreach(elem, newbucket->shb_list)
+ {
+ GTM_SeqInfo *curr_seqinfo = NULL;
+ curr_seqinfo = (GTM_SeqInfo *) gtm_lfirst(elem);
+
+ if (seq_keys_equal(curr_seqinfo->gs_key, newkey))
+ {
+ GTM_RWLockRelease(&seqinfo->gs_lock);
+ GTM_RWLockRelease(&newbucket->shb_lock);
+ /*
+ * Release oldbucket lock but only if its not same as the new
+ * bucket
+ * */
+ if (oldhash != newhash)
+ GTM_RWLockRelease(&oldbucket->shb_lock);
+ ereport(LOG,
+ (EEXIST,
+ errmsg("Sequence with the given key already exists")));
+ return EEXIST;
+ }
+ }
+
+ /*
+ * Must use TopMostMemoryContext since the hash bucket links can survive
+ * forever
+ */
+ oldContext = MemoryContextSwitchTo(TopMostMemoryContext);
+ seqinfo->gs_key = seq_copy_key(newkey);
+ oldbucket->shb_list = gtm_list_delete(oldbucket->shb_list, seqinfo);
+ newbucket->shb_list = gtm_lappend(newbucket->shb_list, seqinfo);
+ MemoryContextSwitchTo(oldContext);
+
+ GTM_RWLockRelease(&seqinfo->gs_lock);
+ GTM_RWLockRelease(&newbucket->shb_lock);
+ /* Release oldbucket lock but only if its not same as the new bucket */
+ if (oldhash != newhash)
+ GTM_RWLockRelease(&oldbucket->shb_lock);
+
+ return 0;
+
+}
+
+/*
+ * Same as seq_copy_key but use specified MemoryContext
+ */
+static GTM_SequenceKey
+seq_copy_key_context(GTM_SequenceKey key, MemoryContext context)
+{
+ MemoryContext oldContext;
+ GTM_SequenceKey newkey;
+
+ oldContext = MemoryContextSwitchTo(TopMostMemoryContext);
+ newkey = seq_copy_key(key);
+ MemoryContextSwitchTo(oldContext);
+ return newkey;
+}
+
+/*
+ * Copy sequence key in the CurrentMemoryContext
+ */
static GTM_SequenceKey
seq_copy_key(GTM_SequenceKey key)
{
@@ -254,7 +364,8 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
GTM_Sequence minval,
GTM_Sequence maxval,
GTM_Sequence startval,
- bool cycle)
+ bool cycle,
+ GlobalTransactionId gxid)
{
GTM_SeqInfo *seqinfo = NULL;
int errcode = 0;
@@ -269,6 +380,7 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
seqinfo->gs_key = seq_copy_key(seqkey);
seqinfo->gs_state = SEQ_STATE_ACTIVE;
seqinfo->gs_called = false;
+ seqinfo->gs_created_gxid = gxid;
/*
* Set the increment. Default is 1
@@ -348,6 +460,13 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
pfree(seqinfo->gs_key);
pfree(seqinfo);
}
+ else
+ {
+ seqinfo = seq_find_seqinfo(seqinfo->gs_key);
+ GTM_RememberCreatedSequence(gxid, seq_copy_key_context(seqinfo->gs_key,
+ TopMostMemoryContext));
+ }
+
GTM_SetNeedBackup();
return errcode;
@@ -355,6 +474,9 @@ GTM_SeqOpen(GTM_SequenceKey seqkey,
/*
* Alter a sequence
+ *
+ * We don't track altered sequences because changes to sequence values are not
+ * transactional and must not be rolled back if the transaction aborts.
*/
int GTM_SeqAlter(GTM_SequenceKey seqkey,
GTM_Sequence increment_by,
@@ -464,7 +586,7 @@ GTM_SeqRestore(GTM_SequenceKey seqkey,
* Destroy the given sequence depending on type of given key
*/
int
-GTM_SeqClose(GTM_SequenceKey seqkey)
+GTM_SeqClose(GTM_SequenceKey seqkey, GlobalTransactionId gxid)
{
int res;
@@ -473,14 +595,46 @@ GTM_SeqClose(GTM_SequenceKey seqkey)
case GTM_SEQ_FULL_NAME:
{
GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey);
- if (seqinfo != NULL)
+ /*
+ * If the sequence by created by the same transaction, then just
+ * drop it completely
+ */
+ res = 0;
+ if ((seqinfo != NULL) && (!GlobalTransactionIdIsValid(gxid) ||
+ (seqinfo->gs_created_gxid == gxid)))
+ {
+ GTM_ForgetCreatedSequence(gxid, seqinfo);
+ seq_release_seqinfo(seqinfo);
+ if (!seq_remove_seqinfo(seqinfo))
+ {
+ pfree(seqinfo->gs_key);
+ pfree(seqinfo);
+ }
+ }
+ /*
+ * Otherwise we rename it to a special value so that it can be
+ * restored back if the transaction fails
+ */
+ else if (seqinfo != NULL)
{
- seq_remove_seqinfo(seqinfo);
- pfree(seqinfo->gs_key);
- pfree(seqinfo);
- res = 0;
+ GTM_SequenceKeyData newkey;
+ MemoryContext oldContext;
+
+ newkey.gsk_key = (char *) palloc0(seqinfo->gs_key->gsk_keylen +
+ strlen("__dropped_") + 11);
+ sprintf(newkey.gsk_key, "%s_dropped_%d", seqinfo->gs_key->gsk_key,
+ gxid);
+ newkey.gsk_key[strlen(newkey.gsk_key)] = '\0';
+ newkey.gsk_keylen = strlen(newkey.gsk_key) + 1;
+ oldContext = MemoryContextSwitchTo(TopMostMemoryContext);
+ seqinfo->gs_oldkey = seq_copy_key(seqinfo->gs_key);
+ if ((res = seq_rename_seqinfo(seqinfo, &newkey)) == 0)
+ GTM_RememberDroppedSequence(gxid,
+ seq_copy_key_context(seqinfo->gs_key, TopMostMemoryContext));
+ MemoryContextSwitchTo(oldContext);
+ seq_release_seqinfo(seqinfo);
}
- else
+ else if (seqinfo == NULL)
res = EINVAL;
break;
@@ -600,11 +754,13 @@ seq_drop_with_dbkey(GTM_SequenceKey nsp)
* Rename an existing sequence with a new name
*/
int
-GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey)
+GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey,
+ GlobalTransactionId gxid)
{
GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey);
- GTM_SeqInfo *newseqinfo = NULL;
int errcode = 0;
+ MemoryContext oldContext;
+ GTM_SeqAlteredInfo *alterinfo;
/* replace old key by new key */
if (seqinfo == NULL)
@@ -615,53 +771,17 @@ GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey)
return EINVAL;
}
- /* Now create the new sequence info */
- newseqinfo = (GTM_SeqInfo *) palloc(sizeof (GTM_SeqInfo));
+ oldContext = MemoryContextSwitchTo(TopMostMemoryContext);
+ alterinfo = (GTM_SeqAlteredInfo *) palloc0(sizeof (GTM_SeqAlteredInfo));
- GTM_RWLockAcquire(&seqinfo->gs_lock, GTM_LOCKMODE_WRITE);
- GTM_RWLockInit(&newseqinfo->gs_lock);
-
- newseqinfo->gs_ref_count = 0;
- newseqinfo->gs_key = seq_copy_key(newseqkey);
- newseqinfo->gs_state = seqinfo->gs_state;
- newseqinfo->gs_called = seqinfo->gs_called;
-
- newseqinfo->gs_increment_by = seqinfo->gs_increment_by;
- newseqinfo->gs_min_value = seqinfo->gs_min_value;
- newseqinfo->gs_max_value = seqinfo->gs_max_value;
-
- newseqinfo->gs_init_value = seqinfo->gs_init_value;
- newseqinfo->gs_value = seqinfo->gs_value;
- newseqinfo->gs_backedUpValue = seqinfo->gs_backedUpValue;
- newseqinfo->gs_cycle = seqinfo->gs_cycle;
-
- newseqinfo->gs_state = seqinfo->gs_state;
- newseqinfo->gs_max_lastvals = seqinfo->gs_max_lastvals;
- newseqinfo->gs_lastval_count = seqinfo->gs_lastval_count;
- newseqinfo->gs_last_values = (GTM_SeqLastVal *)
- MemoryContextAlloc(TopMostMemoryContext,
- newseqinfo->gs_max_lastvals * sizeof(GTM_SeqLastVal));
- memcpy(newseqinfo->gs_last_values, seqinfo->gs_last_values,
- newseqinfo->gs_max_lastvals * sizeof(GTM_SeqLastVal));
-
- /* Add the copy to the list */
- if ((errcode = seq_add_seqinfo(newseqinfo))) /* a lock is taken here for the new sequence */
- {
- GTM_RWLockDestroy(&newseqinfo->gs_lock);
- pfree(newseqinfo->gs_key);
- pfree(newseqinfo);
- return errcode;
- }
+ alterinfo->curr_key = seq_copy_key(newseqkey);
+ alterinfo->prev_key = seq_copy_key(seqinfo->gs_key);
+ MemoryContextSwitchTo(oldContext);
- /* Remove the old key with the old name */
- GTM_RWLockRelease(&seqinfo->gs_lock);
- /* Release first the structure as it has been taken previously */
+ errcode = seq_rename_seqinfo(seqinfo, newseqkey);
+ if (!errcode)
+ GTM_RememberAlteredSequence(gxid, alterinfo);
seq_release_seqinfo(seqinfo);
-
- /* Close sequence properly, full name is here */
- seqkey->gsk_type = GTM_SEQ_FULL_NAME;
- /* Then close properly the old sequence */
- GTM_SeqClose(seqkey);
return errcode;
}
@@ -1018,6 +1138,8 @@ ProcessSequenceInitCommand(Port *myport, StringInfo message, bool is_backup)
StringInfoData buf;
int errcode;
MemoryContext oldContext;
+ const char *data;
+ GlobalTransactionId gxid;
/*
* Get the sequence key
@@ -1039,6 +1161,13 @@ ProcessSequenceInitCommand(Port *myport, StringInfo message, bool is_backup)
cycle = pq_getmsgbyte(message);
+ data = pq_getmsgbytes(message, sizeof (gxid));
+ if (data == NULL)
+ ereport(ERROR,
+ (EPROTO,
+ errmsg("Message does not contain valid GXID")));
+ memcpy(&gxid, data, sizeof (gxid));
+
/*
* We must use the TopMostMemoryContext because the sequence information is
@@ -1047,7 +1176,8 @@ ProcessSequenceInitCommand(Port *myport, StringInfo message, bool is_backup)
*/
oldContext = MemoryContextSwitchTo(TopMostMemoryContext);
- if ((errcode = GTM_SeqOpen(&seqkey, increment, minval, maxval, startval, cycle)))
+ if ((errcode = GTM_SeqOpen(&seqkey, increment, minval, maxval, startval,
+ cycle, gxid)))
ereport(ERROR,
(errcode,
errmsg("Failed to open a new sequence")));
@@ -1076,7 +1206,8 @@ ProcessSequenceInitCommand(Port *myport, StringInfo message, bool is_backup)
minval,
maxval,
startval,
- cycle);
+ cycle,
+ gxid);
if (gtm_standby_check_communication_error(&count, oldconn))
goto retry;
@@ -1163,7 +1294,8 @@ ProcessSequenceAlterCommand(Port *myport, StringInfo message, bool is_backup)
elog(DEBUG1, "Altering sequence key %s", seqkey.gsk_key);
- if ((errcode = GTM_SeqAlter(&seqkey, increment, minval, maxval, startval, lastval, cycle, is_restart)))
+ if ((errcode = GTM_SeqAlter(&seqkey, increment, minval, maxval, startval,
+ lastval, cycle, is_restart)))
ereport(ERROR,
(errcode,
errmsg("Failed to open a new sequence")));
@@ -1710,15 +1842,24 @@ ProcessSequenceCloseCommand(Port *myport, StringInfo message, bool is_backup)
GTM_SequenceKeyData seqkey;
StringInfoData buf;
int errcode;
+ GlobalTransactionId gxid;
+ const char *data;
seqkey.gsk_keylen = pq_getmsgint(message, sizeof (seqkey.gsk_keylen));
seqkey.gsk_key = (char *)pq_getmsgbytes(message, seqkey.gsk_keylen);
memcpy(&seqkey.gsk_type, pq_getmsgbytes(message, sizeof (GTM_SequenceKeyType)),
sizeof (GTM_SequenceKeyType));
+ data = pq_getmsgbytes(message, sizeof (gxid));
+ if (data == NULL)
+ ereport(ERROR,
+ (EPROTO,
+ errmsg("Message does not contain valid GXID")));
+ memcpy(&gxid, data, sizeof (gxid));
+
elog(DEBUG1, "Closing sequence %s", seqkey.gsk_key);
- if ((errcode = GTM_SeqClose(&seqkey)))
+ if ((errcode = GTM_SeqClose(&seqkey, gxid)))
ereport(ERROR,
(errcode,
errmsg("Can not close the sequence")));
@@ -1735,7 +1876,8 @@ ProcessSequenceCloseCommand(Port *myport, StringInfo message, bool is_backup)
elog(DEBUG1, "calling close_sequence() for standby GTM %p.", GetMyThreadInfo->thr_conn->standby);
retry:
- rc = bkup_close_sequence(GetMyThreadInfo->thr_conn->standby, &seqkey);
+ rc = bkup_close_sequence(GetMyThreadInfo->thr_conn->standby,
+ &seqkey, gxid);
if (gtm_standby_check_communication_error(&count, oldconn))
goto retry;
@@ -1786,6 +1928,8 @@ ProcessSequenceRenameCommand(Port *myport, StringInfo message, bool is_backup)
StringInfoData buf;
int errcode;
MemoryContext oldContext;
+ const char *data;
+ GlobalTransactionId gxid;
/* get the message from backend */
seqkey.gsk_keylen = pq_getmsgint(message, sizeof (seqkey.gsk_keylen));
@@ -1795,6 +1939,14 @@ ProcessSequenceRenameCommand(Port *myport, StringInfo message, bool is_backup)
newseqkey.gsk_keylen = pq_getmsgint(message, sizeof (newseqkey.gsk_keylen));
newseqkey.gsk_key = (char *)pq_getmsgbytes(message, newseqkey.gsk_keylen);
+ data = pq_getmsgbytes(message, sizeof (gxid));
+ if (data == NULL)
+ ereport(ERROR,
+ (EPROTO,
+ errmsg("Message does not contain valid GXID")));
+ memcpy(&gxid, data, sizeof (gxid));
+
+
/*
* As when creating a sequence, we must use the TopMostMemoryContext
* because the sequence information is not bound to a thread and
@@ -1804,7 +1956,7 @@ ProcessSequenceRenameCommand(Port *myport, StringInfo message, bool is_backup)
elog(DEBUG1, "Renaming sequence %s to %s", seqkey.gsk_key, newseqkey.gsk_key);
- if ((errcode = GTM_SeqRename(&seqkey, &newseqkey)))
+ if ((errcode = GTM_SeqRename(&seqkey, &newseqkey, gxid)))
ereport(ERROR,
(errcode,
errmsg("Can not rename the sequence")));
@@ -1825,7 +1977,8 @@ ProcessSequenceRenameCommand(Port *myport, StringInfo message, bool is_backup)
elog(DEBUG1, "calling rename_sequence() for standby GTM %p.", GetMyThreadInfo->thr_conn->standby);
retry:
- rc = bkup_rename_sequence(GetMyThreadInfo->thr_conn->standby, &seqkey, &newseqkey);
+ rc = bkup_rename_sequence(GetMyThreadInfo->thr_conn->standby,
+ &seqkey, &newseqkey, gxid);
if (gtm_standby_check_communication_error(&count, oldconn))
goto retry;
@@ -2208,3 +2361,93 @@ GTM_CleanupSeqSession(char *coord_name, int coord_procid)
GTM_RWLockRelease(&bucket->shb_lock);
}
}
+
+/*
+ * Upon transaction abort, remove the sequence created in the transaction being
+ * aborted.
+ */
+void
+GTM_SeqRemoveCreated(void *ptr)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo((GTM_SequenceKey) ptr);
+ if (seqinfo)
+ {
+ seq_release_seqinfo(seqinfo);
+ if (!seq_remove_seqinfo(seqinfo))
+ {
+ pfree(seqinfo->gs_key);
+ pfree(seqinfo);
+ }
+ }
+}
+
+/*
+ * Upon transaction abort, restore the sequence back to its state when it was
+ * altered first time in the transaction.
+ */
+void
+GTM_SeqRestoreAltered(void *ptr)
+{
+ GTM_SeqAlteredInfo *alterinfo = (GTM_SeqAlteredInfo *) ptr;
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo(alterinfo->curr_key);
+
+ if (seqinfo)
+ {
+ if (!seq_keys_equal(seqinfo->gs_key, alterinfo->prev_key))
+ seq_rename_seqinfo(seqinfo, alterinfo->prev_key);
+ pfree(alterinfo->prev_key);
+ pfree(alterinfo->curr_key);
+ pfree(alterinfo);
+ seq_release_seqinfo(seqinfo);
+ }
+}
+
+/*
+ * Upon transaction abort, rename the sequence back to its original value.
+ */
+void
+GTM_SeqRestoreDropped(void *ptr)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo((GTM_SequenceKey) ptr);
+ if (seqinfo)
+ {
+ seq_rename_seqinfo(seqinfo, seqinfo->gs_oldkey);
+ seq_release_seqinfo(seqinfo);
+ }
+
+}
+
+/*
+ * Upon transaction commit, forget the original sequence state. The current
+ * state becomes the final state of the sequence.
+ */
+void
+GTM_SeqRemoveAltered(void *ptr)
+{
+ GTM_SeqAlteredInfo *alterinfo = (GTM_SeqAlteredInfo *) ptr;
+ if (alterinfo)
+ {
+ pfree(alterinfo->curr_key);
+ pfree(alterinfo->prev_key);
+ pfree(alterinfo);
+ }
+}
+
+/*
+ * Upon transaction commit, remove the temporarily renamed sequence forever
+ * from the global structure.
+ */
+void
+GTM_SeqRemoveDropped(void *ptr)
+{
+ GTM_SeqInfo *seqinfo = seq_find_seqinfo((GTM_SequenceKey) ptr);
+ if (seqinfo)
+ {
+ seq_release_seqinfo(seqinfo);
+ if (!seq_remove_seqinfo(seqinfo))
+ {
+ pfree(seqinfo->gs_key);
+ pfree(seqinfo);
+ }
+ }
+}
diff --git a/src/gtm/main/gtm_txn.c b/src/gtm/main/gtm_txn.c
index 80199073ca..706b9bc256 100644
--- a/src/gtm/main/gtm_txn.c
+++ b/src/gtm/main/gtm_txn.c
@@ -834,6 +834,67 @@ init_GTM_TransactionInfo(GTM_TransactionInfo *gtm_txninfo,
static void
clean_GTM_TransactionInfo(GTM_TransactionInfo *gtm_txninfo)
{
+ gtm_ListCell *lc;
+
+ if (gtm_txninfo->gti_state == GTM_TXN_ABORT_IN_PROGRESS)
+ {
+ /*
+ * First drop any sequences created in this transaction. We must do
+ * this before restoring any dropped sequences because the new sequence
+ * may have reused old name
+ */
+ gtm_foreach(lc, gtm_txninfo->gti_created_seqs)
+ {
+ GTM_SeqRemoveCreated(gtm_lfirst(lc));
+ }
+
+ /*
+ * Restore dropped sequences to their original state
+ */
+ gtm_foreach(lc, gtm_txninfo->gti_dropped_seqs)
+ {
+ GTM_SeqRestoreDropped(gtm_lfirst(lc));
+ }
+
+ /*
+ * Restore altered sequences to their original state
+ */
+ gtm_foreach(lc, gtm_txninfo->gti_altered_seqs)
+ {
+ GTM_SeqRestoreAltered(gtm_lfirst(lc));
+ }
+
+
+ }
+ else if (gtm_txninfo->gti_state == GTM_TXN_COMMIT_IN_PROGRESS)
+ {
+ /*
+ * Remove sequences dropped in this transaction permanently. No action
+ * needed for sequences created in this transaction
+ */
+ gtm_foreach(lc, gtm_txninfo->gti_dropped_seqs)
+ {
+ GTM_SeqRemoveDropped(gtm_lfirst(lc));
+ }
+ /*
+ * Remove original copies of sequences altered in this transaction
+ * permanently. The altered copies stay.
+ */
+ gtm_foreach(lc, gtm_txninfo->gti_altered_seqs)
+ {
+ GTM_SeqRemoveAltered(gtm_lfirst(lc));
+ }
+
+ }
+
+ gtm_list_free(gtm_txninfo->gti_created_seqs);
+ gtm_list_free(gtm_txninfo->gti_dropped_seqs);
+ gtm_list_free(gtm_txninfo->gti_altered_seqs);
+
+ gtm_txninfo->gti_dropped_seqs = gtm_NIL;
+ gtm_txninfo->gti_created_seqs = gtm_NIL;
+ gtm_txninfo->gti_altered_seqs = gtm_NIL;
+
gtm_txninfo->gti_state = GTM_TXN_ABORTED;
gtm_txninfo->gti_in_use = false;
gtm_txninfo->gti_snapshot_set = false;
@@ -2765,6 +2826,72 @@ GTM_GetLatestCompletedXID(void)
return GTMTransactions.gt_latestCompletedXid;
}
+void
+GTM_ForgetCreatedSequence(GlobalTransactionId gxid, void *seq)
+{
+ GTM_TransactionInfo *gtm_txninfo;
+ GTM_TransactionHandle txn = GTM_GXIDToHandle(gxid);
+
+ if (txn == InvalidTransactionHandle)
+ return;
+
+ gtm_txninfo = GTM_HandleToTransactionInfo(txn);
+ gtm_txninfo->gti_created_seqs =
+ gtm_list_delete(gtm_txninfo->gti_created_seqs, seq);
+}
+
+/*
+ * Remember sequence created by transaction 'gxid'.
+ *
+ * This should be removed from the global data structure if the transaction
+ * aborts (see GTM_SeqRemoveCreated). If the sequence is later dropped in the
+ * same transaction, we remove it from the global structure as well as forget
+ * tracking (see GTM_ForgetCreatedSequence). If the transaction commits, just
+ * forget about this tracked sequence.
+ */
+void
+GTM_RememberCreatedSequence(GlobalTransactionId gxid, void *seq)
+{
+ GTM_TransactionInfo *gtm_txninfo;
+ GTM_TransactionHandle txn = GTM_GXIDToHandle(gxid);
+
+ if (txn == InvalidTransactionHandle)
+ return;
+
+ gtm_txninfo = GTM_HandleToTransactionInfo(txn);
+ gtm_txninfo->gti_created_seqs =
+ gtm_lappend(gtm_txninfo->gti_created_seqs, seq);
+}
+
+void
+GTM_RememberDroppedSequence(GlobalTransactionId gxid, void *seq)
+{
+ GTM_TransactionInfo *gtm_txninfo;
+ GTM_TransactionHandle txn = GTM_GXIDToHandle(gxid);
+
+ if (txn == InvalidTransactionHandle)
+ return;
+
+ gtm_txninfo = GTM_HandleToTransactionInfo(txn);
+ gtm_txninfo->gti_dropped_seqs =
+ gtm_lappend(gtm_txninfo->gti_dropped_seqs, seq);
+}
+
+void
+GTM_RememberAlteredSequence(GlobalTransactionId gxid, void *seq)
+{
+ GTM_TransactionInfo *gtm_txninfo;
+ GTM_TransactionHandle txn = GTM_GXIDToHandle(gxid);
+
+ if (txn == InvalidTransactionHandle)
+ return;
+
+ gtm_txninfo = GTM_HandleToTransactionInfo(txn);
+ gtm_txninfo->gti_altered_seqs = gtm_lcons(seq,
+ gtm_txninfo->gti_altered_seqs);
+}
+
+
/*
* TODO
*/
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 30e2df6b54..0f82def1f1 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -105,12 +105,6 @@ typedef enum
GTM_DROP_SEQ
} GTM_SequenceDropType;
-/* Sequence callbacks on GTM */
-extern void register_sequence_rename_cb(char *oldseqname, char *newseqname);
-extern void rename_sequence_cb(GTMEvent event, void *args);
-extern void register_sequence_cb(char *seqname, GTM_SequenceKeyType key, GTM_SequenceDropType type);
-extern void drop_sequence_cb(GTMEvent event, void *args);
-
extern bool IsTempSequence(Oid relid);
extern char *GetGlobalSeqName(Relation rel, const char *new_seqname, const char *new_schemaname);
#endif
diff --git a/src/include/gtm/gtm_client.h b/src/include/gtm/gtm_client.h
index 41206b944f..021bf512b2 100644
--- a/src/include/gtm/gtm_client.h
+++ b/src/include/gtm/gtm_client.h
@@ -286,20 +286,24 @@ int report_global_xmin(GTM_Conn *conn, const char *node_name,
*/
int open_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle);
+ GTM_Sequence startval, bool cycle,
+ GlobalTransactionId gxid);
int bkup_open_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
- GTM_Sequence startval, bool cycle);
+ GTM_Sequence startval, bool cycle,
+ GlobalTransactionId gxid);
int alter_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart);
int bkup_alter_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_Sequence increment,
GTM_Sequence minval, GTM_Sequence maxval,
GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart);
-int close_sequence(GTM_Conn *conn, GTM_SequenceKey key);
-int bkup_close_sequence(GTM_Conn *conn, GTM_SequenceKey key);
-int rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey);
-int bkup_rename_sequence(GTM_Conn *conn, GTM_SequenceKey key, GTM_SequenceKey newkey);
+int close_sequence(GTM_Conn *conn, GTM_SequenceKey key, GlobalTransactionId gxid);
+int bkup_close_sequence(GTM_Conn *conn, GTM_SequenceKey key, GlobalTransactionId gxid);
+int rename_sequence(GTM_Conn *conn, GTM_SequenceKey key,
+ GTM_SequenceKey newkey, GlobalTransactionId gxid);
+int bkup_rename_sequence(GTM_Conn *conn, GTM_SequenceKey key,
+ GTM_SequenceKey newkey, GlobalTransactionId gxid);
int get_current(GTM_Conn *conn, GTM_SequenceKey key,
char *coord_name, int coord_procid, GTM_Sequence *result);
int get_next(GTM_Conn *conn, GTM_SequenceKey key,
diff --git a/src/include/gtm/gtm_seq.h b/src/include/gtm/gtm_seq.h
index 870ac56b94..e619d6964c 100644
--- a/src/include/gtm/gtm_seq.h
+++ b/src/include/gtm/gtm_seq.h
@@ -31,6 +31,7 @@ typedef struct GTM_SeqLastVal
typedef struct GTM_SeqInfo
{
GTM_SequenceKey gs_key;
+ GTM_SequenceKey gs_oldkey;
GTM_Sequence gs_value;
GTM_Sequence gs_backedUpValue;
GTM_Sequence gs_init_value;
@@ -42,6 +43,7 @@ typedef struct GTM_SeqInfo
GTM_Sequence gs_max_value;
bool gs_cycle;
bool gs_called;
+ GlobalTransactionId gs_created_gxid;
int32 gs_ref_count;
int32 gs_state;
@@ -70,7 +72,8 @@ int GTM_SeqOpen(GTM_SequenceKey seqkey,
GTM_Sequence minval,
GTM_Sequence maxval,
GTM_Sequence startval,
- bool cycle);
+ bool cycle,
+ GlobalTransactionId gxid);
int GTM_SeqAlter(GTM_SequenceKey seqkey,
GTM_Sequence increment_by,
GTM_Sequence minval,
@@ -79,8 +82,9 @@ int GTM_SeqAlter(GTM_SequenceKey seqkey,
GTM_Sequence lastval,
bool cycle,
bool is_restart);
-int GTM_SeqClose(GTM_SequenceKey seqkey);
-int GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey);
+int GTM_SeqClose(GTM_SequenceKey seqkey, GlobalTransactionId gxid);
+int GTM_SeqRename(GTM_SequenceKey seqkey, GTM_SequenceKey newseqkey,
+ GlobalTransactionId gxid);
int GTM_SeqGetNext(GTM_SequenceKey seqkey, char *coord_name,
int coord_procid, GTM_Sequence range,
GTM_Sequence *result, GTM_Sequence *rangemax);
@@ -117,4 +121,9 @@ void GTM_CleanupSeqSession(char *coord_name, int coord_procid);
bool GTM_NeedSeqRestoreUpdate(GTM_SequenceKey seqkey);
void GTM_WriteRestorePointSeq(FILE *f);
+void GTM_SeqRemoveCreated(void *seqinfo);
+void GTM_SeqRestoreDropped(void *seqinfo);
+void GTM_SeqRemoveDropped(void *seqinfo);
+void GTM_SeqRestoreAltered(void *ptr);
+void GTM_SeqRemoveAltered(void *seqinfo);
#endif
diff --git a/src/include/gtm/gtm_txn.h b/src/include/gtm/gtm_txn.h
index d516acecee..f175062b00 100644
--- a/src/include/gtm/gtm_txn.h
+++ b/src/include/gtm/gtm_txn.h
@@ -97,6 +97,9 @@ typedef struct GTM_TransactionInfo
GTM_RWLock gti_lock;
bool gti_vacuum;
+ gtm_List *gti_created_seqs;
+ gtm_List *gti_dropped_seqs;
+ gtm_List *gti_altered_seqs;
} GTM_TransactionInfo;
#define GTM_MAX_2PC_NODES 16
@@ -247,4 +250,9 @@ void ProcessBkupBeginTransactionGetGXIDCommandMulti(Port *myport, StringInfo mes
void ProcessGetSnapshotCommand(Port *myport, StringInfo message, bool get_gxid);
void ProcessGetSnapshotCommandMulti(Port *myport, StringInfo message);
void GTM_FreeSnapshotData(GTM_Snapshot snapshot);
+void GTM_RememberDroppedSequence(GlobalTransactionId gxid, void *seq);
+void GTM_ForgetCreatedSequence(GlobalTransactionId gxid, void *seq);
+void GTM_RememberCreatedSequence(GlobalTransactionId gxid, void *seq);
+void GTM_RememberAlteredSequence(GlobalTransactionId gxid, void *seq);
+
#endif
diff --git a/src/test/regress/expected/xc_sequence.out b/src/test/regress/expected/xc_sequence.out
index 5ba8bf9c14..6674596187 100644
--- a/src/test/regress/expected/xc_sequence.out
+++ b/src/test/regress/expected/xc_sequence.out
@@ -174,3 +174,295 @@ SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok
(1 row)
DROP SEQUENCE xc_sequence_tab1_col2_seq;
+-- As simple test that sequences are dropped properly
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- Check if rollback reverses sequence drop properly
+CREATE SEQUENCE xl_s1;
+BEGIN;
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+DROP SEQUENCE xl_s1;
+-- Check if commit makes sequence drop permanent
+CREATE SEQUENCE xl_s1;
+BEGIN;
+DROP SEQUENCE xl_s1;
+COMMIT;
+DROP SEQUENCE xl_s1; -- error
+ERROR: sequence "xl_s1" does not exist
+-- Drop a sequence and recreate another sequence with the same name in the same
+-- transaction. Check that transaction abort does not cause any surprising
+-- behaviour
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+BEGIN;
+DROP SEQUENCE xl_s1;
+CREATE SEQUENCE xl_s1; -- create again with the same name
+SELECT nextval('xl_s1');-- new value
+ nextval
+---------
+ 1
+(1 row)
+
+ROLLBACK;
+SELECT nextval('xl_s1');-- sequence value changes are not transactional
+ nextval
+---------
+ 3
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- Check sequence renaming works ok
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1'); -- error
+ERROR: relation "xl_s1" does not exist
+LINE 1: SELECT nextval('xl_s1');
+ ^
+SELECT nextval('xl_s1_newname'); -- continue with the previous value-space
+ nextval
+---------
+ 3
+(1 row)
+
+DROP SEQUENCE xl_s1; -- error
+ERROR: sequence "xl_s1" does not exist
+DROP SEQUENCE xl_s1_newname; -- should be ok
+-- A combination of ALTER and RENAME should work ok when transaction aborts
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ nextval
+---------
+ 1
+(1 row)
+
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- A combination of ALTER and RENAME should work ok when transacion commits
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ nextval
+---------
+ 1
+(1 row)
+
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ nextval
+---------
+ 2
+(1 row)
+
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+COMMIT;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- Multiple RENAMEs in the same transaction
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ nextval
+---------
+ 1
+(1 row)
+
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ nextval
+---------
+ 2
+(1 row)
+
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+DROP SEQUENCE xl_s1;
+COMMIT;
+SELECT nextval('xl_s1');
+ERROR: relation "xl_s1" does not exist
+LINE 1: SELECT nextval('xl_s1');
+ ^
+DROP SEQUENCE xl_s1;
+ERROR: sequence "xl_s1" does not exist
+-- Multiple RENAMEs in the same transaction and the transaction aborts
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ nextval
+---------
+ 1
+(1 row)
+
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ nextval
+---------
+ 2
+(1 row)
+
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- Rename back to original value, but abort the transaction
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+ROLLBACK;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 3
+(1 row)
+
+DROP SEQUENCE xl_s1;
+-- Rename back to original value
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 1
+(1 row)
+
+BEGIN;
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 2
+(1 row)
+
+COMMIT;
+SELECT nextval('xl_s1');
+ nextval
+---------
+ 3
+(1 row)
+
+CREATE TABLE xl_testtab (a serial, b int);
+ALTER TABLE xl_testtab RENAME TO xl_testtab_newname;
+\d+ xl_testtab_newname
+ Table "public.xl_testtab_newname"
+ Column | Type | Modifiers | Storage | Stats target | Description
+--------+---------+--------------------------------------------------------+---------+--------------+-------------
+ a | integer | not null default nextval('xl_testtab_a_seq'::regclass) | plain | |
+ b | integer | | plain | |
+Distribute By: HASH(a)
+Location Nodes: ALL DATANODES
+
diff --git a/src/test/regress/sql/xc_sequence.sql b/src/test/regress/sql/xc_sequence.sql
index 7a929dab34..3be45556de 100644
--- a/src/test/regress/sql/xc_sequence.sql
+++ b/src/test/regress/sql/xc_sequence.sql
@@ -84,3 +84,132 @@ COMMIT;
CREATE SEQUENCE xc_sequence_tab1_col2_seq START 2344;
SELECT nextval('xc_sequence_tab1_col2_seq'); -- ok
DROP SEQUENCE xc_sequence_tab1_col2_seq;
+
+-- As simple test that sequences are dropped properly
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+-- Check if rollback reverses sequence drop properly
+CREATE SEQUENCE xl_s1;
+BEGIN;
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+DROP SEQUENCE xl_s1;
+
+-- Check if commit makes sequence drop permanent
+CREATE SEQUENCE xl_s1;
+BEGIN;
+DROP SEQUENCE xl_s1;
+COMMIT;
+DROP SEQUENCE xl_s1; -- error
+
+-- Drop a sequence and recreate another sequence with the same name in the same
+-- transaction. Check that transaction abort does not cause any surprising
+-- behaviour
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+BEGIN;
+DROP SEQUENCE xl_s1;
+CREATE SEQUENCE xl_s1; -- create again with the same name
+SELECT nextval('xl_s1');-- new value
+ROLLBACK;
+SELECT nextval('xl_s1');-- sequence value changes are not transactional
+DROP SEQUENCE xl_s1;
+
+-- Check sequence renaming works ok
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1'); -- error
+SELECT nextval('xl_s1_newname'); -- continue with the previous value-space
+DROP SEQUENCE xl_s1; -- error
+DROP SEQUENCE xl_s1_newname; -- should be ok
+
+-- A combination of ALTER and RENAME should work ok when transaction aborts
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+-- A combination of ALTER and RENAME should work ok when transacion commits
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+COMMIT;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+
+-- Multiple RENAMEs in the same transaction
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+DROP SEQUENCE xl_s1;
+COMMIT;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+-- Multiple RENAMEs in the same transaction and the transaction aborts
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RESTART;
+SELECT nextval('xl_s1'); -- restart value
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+SELECT nextval('xl_s1_newname');
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+ALTER SEQUENCE xl_s1 RESTART;
+DROP SEQUENCE xl_s1;
+ROLLBACK;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+-- Rename back to original value, but abort the transaction
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+SELECT nextval('xl_s1');
+ROLLBACK;
+SELECT nextval('xl_s1');
+DROP SEQUENCE xl_s1;
+
+-- Rename back to original value
+CREATE SEQUENCE xl_s1;
+SELECT nextval('xl_s1');
+BEGIN;
+ALTER SEQUENCE xl_s1 RENAME TO xl_s1_newname;
+ALTER SEQUENCE xl_s1_newname RENAME TO xl_s1;
+SELECT nextval('xl_s1');
+COMMIT;
+SELECT nextval('xl_s1');
+
+CREATE TABLE xl_testtab (a serial, b int);
+ALTER TABLE xl_testtab RENAME TO xl_testtab_newname;
+\d+ xl_testtab_newname
+