From: mason_s <ma...@us...> - 2010-11-23 07:23:21
|
Project "Postgres-XC". The branch, master has been updated via 392180900570a9f3f8bd482663013b6778b323cd (commit) from a1f26c32e159aeff6cdf1488b1020ff8bc115386 (commit) - Log ----------------------------------------------------------------- commit 392180900570a9f3f8bd482663013b6778b323cd Author: Mason Sharp <ma...@us...> Date: Tue Nov 23 02:18:55 2010 -0500 Fix for sourceforge.net bug#3013984: Sequence scope When we drop databases, we need to make sure that we remove the sequences from GTM. By Benny Mei Le, Michael Paquier, with bug fix by Mason Sharp diff --git a/src/backend/access/transam/gtm.c b/src/backend/access/transam/gtm.c index 64437e7..fafa0b7 100644 --- a/src/backend/access/transam/gtm.c +++ b/src/backend/access/transam/gtm.c @@ -166,12 +166,14 @@ CommitPreparedTranGTM(GlobalTransactionId gxid, GlobalTransactionId prepared_gxi int RollbackTranGTM(GlobalTransactionId gxid) { - int ret; + int ret = -1; if (!GlobalTransactionIdIsValid(gxid)) return 0; CheckConnection(); - ret = abort_transaction(conn, gxid); + + if (conn) + ret = abort_transaction(conn, gxid); /* * If something went wrong (timeout), try and reset GTM connection. @@ -376,15 +378,20 @@ SetValGTM(char *seqname, GTM_Sequence nextval, bool iscalled) } /* - * Drop the sequence + * Drop the sequence depending the key type + * + * Type of Sequence name use in key; + * GTM_SEQ_FULL_NAME, full name of sequence + * GTM_SEQ_DB_NAME, DB name part of sequence key */ int -DropSequenceGTM(char *seqname) +DropSequenceGTM(const char *name, GTM_SequenceKeyType type) { GTM_SequenceKeyData seqkey; CheckConnection(); - seqkey.gsk_keylen = strlen(seqname); - seqkey.gsk_key = seqname; + seqkey.gsk_keylen = strlen(name); + seqkey.gsk_key = name; + seqkey.gsk_type = type; return conn ? close_sequence(conn, &seqkey) : -1; } diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index dbbca98..5333cf0 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -1160,7 +1160,7 @@ doDeletion(const ObjectAddress *object) relseq = relation_open(object->objectId, AccessShareLock); seqname = GetGlobalSeqName(relseq, NULL, NULL); - DropSequenceGTM(seqname); + DropSequenceGTM(seqname, GTM_SEQ_FULL_NAME); pfree(seqname); /* Then close the relation opened previously */ diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index ec1db5a..208d621 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -57,7 +57,10 @@ #include "utils/snapmgr.h" #include "utils/syscache.h" #include "utils/tqual.h" - +#ifdef PGXC +#include "pgxc/pgxc.h" +#include "access/gtm.h" +#endif typedef struct { @@ -875,6 +878,13 @@ dropdb(const char *dbname, bool missing_ok) * according to pg_database, which is not good. */ database_file_update_needed(); + +#ifdef PGXC + /* Drop sequences on gtm that are on the database dropped. */ + if(IS_PGXC_COORDINATOR && !IsConnFromCoord()) + if(DropSequenceGTM(dbname, GTM_SEQ_DB_NAME)) + elog(ERROR, "Deletion of sequences on database %s not completed", dbname); +#endif } diff --git a/src/gtm/client/gtm_client.c b/src/gtm/client/gtm_client.c index 53ab3f3..6ff3996 100644 --- a/src/gtm/client/gtm_client.c +++ b/src/gtm/client/gtm_client.c @@ -574,7 +574,8 @@ close_sequence(GTM_Conn *conn, GTM_SequenceKey key) if (gtmpqPutMsgStart('C', true, conn) || gtmpqPutInt(MSG_SEQUENCE_CLOSE, sizeof (GTM_MessageType), conn) || gtmpqPutInt(key->gsk_keylen, 4, conn) || - gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn)) + gtmpqPutnchar(key->gsk_key, key->gsk_keylen, conn) || + gtmpqPutnchar((char *)&key->gsk_type, sizeof(GTM_SequenceKeyType), conn)) goto send_failed; /* Finish the message. */ diff --git a/src/gtm/main/gtm_seq.c b/src/gtm/main/gtm_seq.c index 8611f40..6d946a9 100644 --- a/src/gtm/main/gtm_seq.c +++ b/src/gtm/main/gtm_seq.c @@ -37,11 +37,13 @@ static GTM_SeqInfoHashBucket GTMSequences[SEQ_HASH_TABLE_SIZE]; static uint32 seq_gethash(GTM_SequenceKey key); static bool seq_keys_equal(GTM_SequenceKey key1, GTM_SequenceKey key2); +static bool seq_key_dbname_equal(GTM_SequenceKey nsp, GTM_SequenceKey seq); 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 GTM_SequenceKey seq_copy_key(GTM_SequenceKey key); +static int seq_drop_with_dbkey(GTM_SequenceKey nsp); /* * Get the hash value given the sequence key @@ -442,24 +444,143 @@ GTM_SeqRestore(GTM_SequenceKey seqkey, } return errcode; } + /* - * Destroy the given sequence + * Destroy the given sequence depending on type of given key */ int GTM_SeqClose(GTM_SequenceKey seqkey) { - GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey); - if (seqinfo != NULL) + int res; + + switch(seqkey->gsk_type) { - seq_remove_seqinfo(seqinfo); - pfree(seqinfo->gs_key); - pfree(seqinfo); - return 0; + case GTM_SEQ_FULL_NAME: + { + GTM_SeqInfo *seqinfo = seq_find_seqinfo(seqkey); + if (seqinfo != NULL) + { + seq_remove_seqinfo(seqinfo); + pfree(seqinfo->gs_key); + pfree(seqinfo); + res = 0; + } + else + res = EINVAL; + + break; + } + case GTM_SEQ_DB_NAME: + res = seq_drop_with_dbkey(seqkey); + break; + + default: + res = EINVAL; + break; } - else - return EINVAL; + + return res; } +/* Check if sequence key contains only Database name */ +static bool +seq_key_dbname_equal(GTM_SequenceKey nsp, GTM_SequenceKey seq) +{ + Assert(nsp); + Assert(seq); + + /* + * Sequence key of GTM_SEQ_DB_NAME type has to be shorter + * than given sequence key. + */ + if(nsp->gsk_keylen >= seq->gsk_keylen) + return false; + + /* + * Check also if first part of sequence key name has a dot at the right place. + * This accelerates process instead of making numerous memcmp. + */ + if (seq->gsk_key[nsp->gsk_keylen] != '.') + return false; + + /* Then Check the strings */ + return (memcmp(nsp->gsk_key, seq->gsk_key, nsp->gsk_keylen) == 0); +} + +/* + * Remove all sequences with given key depending on its type. + */ +static int +seq_drop_with_dbkey(GTM_SequenceKey nsp) +{ + int ii = 0; + GTM_SeqInfoHashBucket *bucket; + ListCell *cell, *prev; + GTM_SeqInfo *curr_seqinfo = NULL; + int res = 0; + bool deleted; + + for(ii = 0; ii < SEQ_HASH_TABLE_SIZE; ii++) + { + bucket = >MSequences[ii]; + + GTM_RWLockAcquire(&bucket->shb_lock, GTM_LOCKMODE_READ); + + prev = NULL; + cell = list_head(bucket->shb_list); + while (cell != NULL) + { + curr_seqinfo = (GTM_SeqInfo *) lfirst(cell); + deleted = false; + + if (seq_key_dbname_equal(nsp, curr_seqinfo->gs_key)) + { + GTM_RWLockAcquire(&curr_seqinfo->gs_lock, GTM_LOCKMODE_WRITE); + + if (curr_seqinfo->gs_ref_count > 1) + { + curr_seqinfo->gs_state = SEQ_STATE_DELETED; + + /* can not happen, be checked before called */ + elog(LOG,"Sequence %s is in use, mark for deletion only", + curr_seqinfo->gs_key->gsk_key); + + /* + * Continue to delete other sequences linked to this dbname, + * sequences in use are deleted later. + */ + res = EBUSY; + } + else + { + /* Sequence is not is busy state, it can be deleted safely */ + + bucket->shb_list = list_delete_cell(bucket->shb_list, cell, prev); + elog(LOG, "Sequence %s was deleted from GTM", + curr_seqinfo->gs_key->gsk_key); + + deleted = true; + } + GTM_RWLockRelease(&curr_seqinfo->gs_lock); + } + if (deleted) + { + if (prev) + cell = lnext(prev); + else + cell = list_head(bucket->shb_list); + } + else + { + prev = cell; + cell = lnext(cell); + } + } + GTM_RWLockRelease(&bucket->shb_lock); + } + + return res; +} /* * Rename an existing sequence with a new name */ @@ -1017,6 +1138,8 @@ ProcessSequenceCloseCommand(Port *myport, StringInfo message) 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)); if ((errcode = GTM_SeqClose(&seqkey))) ereport(ERROR, diff --git a/src/include/access/gtm.h b/src/include/access/gtm.h index 3fc4cfe..6687474 100644 --- a/src/include/access/gtm.h +++ b/src/include/access/gtm.h @@ -53,6 +53,6 @@ extern int CreateSequenceGTM(char *seqname, GTM_Sequence increment, extern int AlterSequenceGTM(char *seqname, GTM_Sequence increment, GTM_Sequence minval, GTM_Sequence maxval, GTM_Sequence startval, GTM_Sequence lastval, bool cycle, bool is_restart); -extern int DropSequenceGTM(char *seqname); +extern int DropSequenceGTM(const char *name, GTM_SequenceKeyType type); extern int RenameSequenceGTM(char *seqname, const char *newseqname); #endif /* ACCESS_GTM_H */ diff --git a/src/include/gtm/gtm_c.h b/src/include/gtm/gtm_c.h index da15df3..e8b9984 100644 --- a/src/include/gtm/gtm_c.h +++ b/src/include/gtm/gtm_c.h @@ -63,13 +63,23 @@ typedef int32 GTM_TransactionHandle; typedef int64 GTM_Timestamp; /* timestamp data is 64-bit based */ typedef int64 GTM_Sequence; /* a 64-bit sequence */ -typedef struct GTM_SequenceKeyData + +/* Type of sequence name used when dropping it */ +typedef enum GTM_SequenceKeyType +{ + GTM_SEQ_FULL_NAME, /* Full sequence key */ + GTM_SEQ_DB_NAME /* DB name part of sequence key */ +} GTM_SequenceKeyType; + +typedef struct GTM_SequenceKeyData { uint32 gsk_keylen; char *gsk_key; -} GTM_SequenceKeyData; /* Counter key, set by the client */ + GTM_SequenceKeyType gsk_type; /* see constants below */ +} GTM_SequenceKeyData; /* Counter key, set by the client */ typedef GTM_SequenceKeyData *GTM_SequenceKey; + #define GTM_MAX_SEQKEY_LENGTH 1024 #define InvalidSequenceValue 0x7fffffffffffffffLL ----------------------------------------------------------------------- Summary of changes: src/backend/access/transam/gtm.c | 19 ++++-- src/backend/catalog/dependency.c | 2 +- src/backend/commands/dbcommands.c | 12 +++- src/gtm/client/gtm_client.c | 3 +- src/gtm/main/gtm_seq.c | 141 ++++++++++++++++++++++++++++++++++--- src/include/access/gtm.h | 2 +- src/include/gtm/gtm_c.h | 14 +++- 7 files changed, 172 insertions(+), 21 deletions(-) hooks/post-receive -- Postgres-XC |