summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Paquier2012-07-13 01:52:46 +0000
committerMichael Paquier2012-07-13 01:52:46 +0000
commit4ecfc866de54c0327fbef19ff803257748bf8480 (patch)
tree9dd44a927073c30b54ddfe5d10ae23d46cc7e55b
parent5d8d73970dcd36236df3405801349ec01623753f (diff)
Change control file of GTM into a text file
This includes latest GXID and sequence information. This configuration allows an external operator to modify sequence information with a simple text editor before restarting a GTM. Some functionalities have been added to include sequence name encoding and decoding when interacting with control file. Patch by Andrei Martsinchyk
-rw-r--r--src/gtm/main/gtm_seq.c216
-rw-r--r--src/gtm/main/gtm_standby.c2
-rw-r--r--src/gtm/main/gtm_txn.c10
-rw-r--r--src/gtm/main/main.c24
-rw-r--r--src/include/gtm/gtm_seq.h4
-rw-r--r--src/include/gtm/gtm_txn.h4
6 files changed, 195 insertions, 65 deletions
diff --git a/src/gtm/main/gtm_seq.c b/src/gtm/main/gtm_seq.c
index b050e7a411..d3b2f3339a 100644
--- a/src/gtm/main/gtm_seq.c
+++ b/src/gtm/main/gtm_seq.c
@@ -35,9 +35,6 @@ typedef struct GTM_SeqInfoHashBucket
GTM_RWLock shb_lock;
} GTM_SeqInfoHashBucket;
-static int SeqStartMagic = 0xfafafafa;
-static int SeqEndMagic = 0xfefefefe;
-
#define SEQ_HASH_TABLE_SIZE 1024
static GTM_SeqInfoHashBucket GTMSequences[SEQ_HASH_TABLE_SIZE];
@@ -1610,13 +1607,129 @@ ProcessSequenceRenameCommand(Port *myport, StringInfo message, bool is_backup)
/* FIXME: need to check errors */
}
+
+/*
+ * Escape whitespace and non-printable characters in the sequence name to
+ * store it to the control file.
+ */
+static void
+encode_seq_key(GTM_SequenceKey seqkey, char *buffer)
+{
+ int i;
+ char c;
+ char *out;
+
+ out = buffer;
+ for (i = 0; i < seqkey->gsk_keylen; i++)
+ {
+ c = seqkey->gsk_key[i];
+
+ if (c == '\\') /* double backslach */
+ {
+ *out++ = '\\';
+ *out++ = '\\';
+ }
+ else if (c > ' ') /* no need to escape */
+ {
+ *out++ = c;
+ }
+ else if (c == '\n') /* below some known non-printable chars */
+ {
+ *out++ = '\\';
+ *out++ = 'n';
+ }
+ else if (c == '\r')
+ {
+ *out++ = '\\';
+ *out++ = 'r';
+ }
+ else if (c == '\t')
+ {
+ *out++ = '\\';
+ *out++ = 't';
+ }
+ else /* other non-printable chars */
+ {
+ *out++ = '\\';
+ if ((int) c < 10)
+ {
+ *out++ = '0';
+ *out++ = (char) ((int) '0' + (int) c);
+ }
+ else
+ {
+ *out++ = (char) ((int) '0' + ((int) c) / 10);
+ *out++ = (char) ((int) '0' + ((int) c) % 10);
+ }
+ }
+ }
+ /* Add NULL terminator */
+ *out++ = '\0';
+}
+
+
+/*
+ * Decode the string encoded by the encode_seq_key function
+ */
+static void
+decode_seq_key(char* value, GTM_SequenceKey seqkey)
+{
+ char *in;
+ char out[1024];
+ int len = 0;
+
+ in = value;
+ while (*in != '\0')
+ {
+ if (*in == '\\') /* get escaped character */
+ {
+ in++; /* next value */
+ if (*in == '\\')
+ out[len++] = *in++;
+ else if (*in == 'n')
+ {
+ out[len++] = '\n';
+ in++;
+ }
+ else if (*in == 'r')
+ {
+ out[len++] = '\r';
+ in++;
+ }
+ else if (*in == 't')
+ {
+ out[len++] = '\t';
+ in++;
+ }
+ else /* \nn format */
+ {
+ int val;
+ val = ((int) *in++ - (int) '0');
+ val *= 10;
+ val += ((int) *in++ - (int) '0');
+ out[len++] = (char) val;
+ }
+ }
+ else /* get plain character */
+ {
+ out[len++] = *in++;
+ }
+ }
+ /* copy result to palloc'ed memory */
+ seqkey->gsk_keylen = len;
+ seqkey->gsk_key = (char *) palloc(len);
+ memcpy(seqkey->gsk_key, out, len);
+}
+
+
void
-GTM_SaveSeqInfo(int ctlfd)
+GTM_SaveSeqInfo(FILE *ctlf)
{
GTM_SeqInfoHashBucket *bucket;
gtm_ListCell *elem;
GTM_SeqInfo *seqinfo = NULL;
int hash;
+ char buffer[1024];
for (hash = 0; hash < SEQ_HASH_TABLE_SIZE; hash++)
{
@@ -1635,18 +1748,14 @@ GTM_SaveSeqInfo(int ctlfd)
GTM_RWLockAcquire(&seqinfo->gs_lock, GTM_LOCKMODE_READ);
- write(ctlfd, &SeqStartMagic, sizeof (SeqStartMagic));
- write(ctlfd, &seqinfo->gs_key->gsk_keylen, sizeof (uint32));
- write(ctlfd, seqinfo->gs_key->gsk_key, seqinfo->gs_key->gsk_keylen);
- write(ctlfd, &seqinfo->gs_value, sizeof (GTM_Sequence));
- write(ctlfd, &seqinfo->gs_init_value, sizeof (GTM_Sequence));
- write(ctlfd, &seqinfo->gs_increment_by, sizeof (GTM_Sequence));
- write(ctlfd, &seqinfo->gs_min_value, sizeof (GTM_Sequence));
- write(ctlfd, &seqinfo->gs_max_value, sizeof (GTM_Sequence));
- write(ctlfd, &seqinfo->gs_cycle, sizeof (bool));
- write(ctlfd, &seqinfo->gs_called, sizeof (bool));
- write(ctlfd, &seqinfo->gs_state, sizeof (int32));
- write(ctlfd, &SeqEndMagic, sizeof(SeqEndMagic));
+ encode_seq_key(seqinfo->gs_key, buffer);
+ fprintf(ctlf, "%s\t%ld\t%ld\t%ld\t%ld\t%ld\t%c\t%c\t%x\n",
+ buffer, seqinfo->gs_value,
+ seqinfo->gs_init_value, seqinfo->gs_increment_by,
+ seqinfo->gs_min_value, seqinfo->gs_max_value,
+ (seqinfo->gs_cycle ? 't' : 'f'),
+ (seqinfo->gs_called ? 't' : 'f'),
+ seqinfo->gs_state);
GTM_RWLockRelease(&seqinfo->gs_lock);
}
@@ -1656,15 +1765,16 @@ GTM_SaveSeqInfo(int ctlfd)
}
+
void
-GTM_RestoreSeqInfo(int ctlfd)
+GTM_RestoreSeqInfo(FILE *ctlf)
{
- int magic;
+ char seqname[1024];
- if (ctlfd == -1)
+ if (ctlf == NULL)
return;
- while (read(ctlfd, &magic, sizeof (SeqStartMagic)) == sizeof (SeqStartMagic))
+ while (fscanf(ctlf, "%s", seqname) == 1)
{
GTM_SequenceKeyData seqkey;
GTM_Sequence increment_by;
@@ -1675,38 +1785,58 @@ GTM_RestoreSeqInfo(int ctlfd)
int32 state;
bool cycle;
bool called;
+ char boolval[16];
- if (magic != SeqStartMagic)
+ decode_seq_key(seqname, &seqkey);
+
+ if (fscanf(ctlf, "%ld", &curval) != 1)
{
- elog(LOG, "Start magic mismatch %x - %x", magic, SeqStartMagic);
- break;
+ elog(WARNING, "Corrupted control file");
+ return;
}
-
- if (read(ctlfd, &seqkey.gsk_keylen, sizeof (uint32)) != sizeof (uint32))
+ if (fscanf(ctlf, "%ld", &startval) != 1)
{
- elog(LOG, "Failed to read keylen");
- break;
+ elog(WARNING, "Corrupted control file");
+ return;
}
-
- seqkey.gsk_key = palloc(seqkey.gsk_keylen);
- read(ctlfd, seqkey.gsk_key, seqkey.gsk_keylen);
-
- read(ctlfd, &curval, sizeof (GTM_Sequence));
- read(ctlfd, &startval, sizeof (GTM_Sequence));
- read(ctlfd, &increment_by, sizeof (GTM_Sequence));
- read(ctlfd, &minval, sizeof (GTM_Sequence));
- read(ctlfd, &maxval, sizeof (GTM_Sequence));
- read(ctlfd, &cycle, sizeof (bool));
- read(ctlfd, &called, sizeof (bool));
- read(ctlfd, &state, sizeof (int32));
- read(ctlfd, &magic, sizeof(SeqEndMagic));
-
- if (magic != SeqEndMagic)
+ if (fscanf(ctlf, "%ld", &increment_by) != 1)
+ {
+ elog(WARNING, "Corrupted control file");
+ return;
+ }
+ if (fscanf(ctlf, "%ld", &minval) != 1)
+ {
+ elog(WARNING, "Corrupted control file");
+ return;
+ }
+ if (fscanf(ctlf, "%ld", &maxval) != 1)
+ {
+ elog(WARNING, "Corrupted control file");
+ return;
+ }
+ if (fscanf(ctlf, "%s", boolval) == 1)
+ {
+ cycle = (*boolval == 't');
+ }
+ else
+ {
+ elog(WARNING, "Corrupted control file");
+ return;
+ }
+ if (fscanf(ctlf, "%s", boolval) == 1)
+ {
+ called = (*boolval == 't');
+ }
+ else
+ {
+ elog(WARNING, "Corrupted control file");
+ return;
+ }
+ if (fscanf(ctlf, "%x", &state) != 1)
{
elog(WARNING, "Corrupted control file");
return;
}
-
GTM_SeqRestore(&seqkey, increment_by, minval, maxval, startval, curval,
state, cycle, called);
}
diff --git a/src/gtm/main/gtm_standby.c b/src/gtm/main/gtm_standby.c
index 575d2a12ad..5c2c8f0a4d 100644
--- a/src/gtm/main/gtm_standby.c
+++ b/src/gtm/main/gtm_standby.c
@@ -71,7 +71,7 @@ gtm_standby_restore_next_gxid(void)
GlobalTransactionId next_gxid = InvalidGlobalTransactionId;
next_gxid = get_next_gxid(GTM_ActiveConn);
- GTM_RestoreTxnInfo(-1, next_gxid);
+ GTM_RestoreTxnInfo(NULL, next_gxid);
elog(LOG, "Restoring the next GXID done.");
return 1;
diff --git a/src/gtm/main/gtm_txn.c b/src/gtm/main/gtm_txn.c
index f507c988e2..ccfd602864 100644
--- a/src/gtm/main/gtm_txn.c
+++ b/src/gtm/main/gtm_txn.c
@@ -2578,13 +2578,13 @@ GTM_SetShuttingDown(void)
}
void
-GTM_RestoreTxnInfo(int ctlfd, GlobalTransactionId next_gxid)
+GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid)
{
GlobalTransactionId saved_gxid;
- if (ctlfd != -1)
+ if (ctlf)
{
- if ((read(ctlfd, &saved_gxid, sizeof (saved_gxid)) != sizeof (saved_gxid)) &&
+ if ((fscanf(ctlf, "%u", &saved_gxid) != 1) &&
(!GlobalTransactionIdIsValid(next_gxid)))
next_gxid = InitialGXIDValue_Default;
else if (!GlobalTransactionIdIsValid(next_gxid))
@@ -2603,7 +2603,7 @@ GTM_RestoreTxnInfo(int ctlfd, GlobalTransactionId next_gxid)
}
void
-GTM_SaveTxnInfo(int ctlfd)
+GTM_SaveTxnInfo(FILE *ctlf)
{
GlobalTransactionId next_gxid;
@@ -2611,7 +2611,7 @@ GTM_SaveTxnInfo(int ctlfd)
elog(LOG, "Saving transaction info - next_gxid: %u", next_gxid);
- write(ctlfd, &next_gxid, sizeof (next_gxid));
+ fprintf(ctlf, "%u\n", next_gxid);
}
/*
* TODO
diff --git a/src/gtm/main/main.c b/src/gtm/main/main.c
index cca3c5d1cd..f6c5e8d58e 100644
--- a/src/gtm/main/main.c
+++ b/src/gtm/main/main.c
@@ -286,7 +286,7 @@ main(int argc, char *argv[])
int status;
int i;
GlobalTransactionId next_gxid = InvalidGlobalTransactionId;
- int ctlfd;
+ FILE *ctlf;
/*
* Local variable to hold command line options.
@@ -584,10 +584,11 @@ main(int argc, char *argv[])
}
else
{
- ctlfd = open(GTMControlFile, O_RDONLY);
- GTM_RestoreTxnInfo(ctlfd, next_gxid);
- GTM_RestoreSeqInfo(ctlfd);
- close(ctlfd);
+ ctlf = fopen(GTMControlFile, "r");
+ GTM_RestoreTxnInfo(ctlf, next_gxid);
+ GTM_RestoreSeqInfo(ctlf);
+ if (ctlf)
+ fclose(ctlf);
}
if (Recovery_IsStandby())
@@ -768,7 +769,7 @@ ServerLoop(void)
if (GTMAbortPending)
{
- int ctlfd;
+ FILE *ctlf;
/*
* XXX We should do a clean shutdown here. For the time being, just
@@ -783,16 +784,15 @@ ServerLoop(void)
*/
GTM_SetShuttingDown();
- ctlfd = open(GTMControlFile, O_WRONLY | O_TRUNC | O_CREAT,
- S_IRUSR | S_IWUSR);
- if (ctlfd == -1)
+ ctlf = fopen(GTMControlFile, "w");
+ if (ctlf == NULL)
{
fprintf(stderr, "Failed to create/open the control file\n");
exit(2);
}
- GTM_SaveTxnInfo(ctlfd);
- GTM_SaveSeqInfo(ctlfd);
+ GTM_SaveTxnInfo(ctlf);
+ GTM_SaveSeqInfo(ctlf);
#if 0
/*
@@ -808,7 +808,7 @@ ServerLoop(void)
}
#endif
- close(ctlfd);
+ fclose(ctlf);
exit(1);
}
diff --git a/src/include/gtm/gtm_seq.h b/src/include/gtm/gtm_seq.h
index 3cd218f3bf..b6fcdc61a9 100644
--- a/src/include/gtm/gtm_seq.h
+++ b/src/include/gtm/gtm_seq.h
@@ -87,8 +87,8 @@ void ProcessSequenceAlterCommand(Port *myport, StringInfo message, bool is_backu
void ProcessSequenceListCommand(Port *myport, StringInfo message);
-void GTM_SaveSeqInfo(int ctlfd);
-void GTM_RestoreSeqInfo(int ctlfd);
+void GTM_SaveSeqInfo(FILE *ctlf);
+void GTM_RestoreSeqInfo(FILE *ctlf);
int GTM_SeqRestore(GTM_SequenceKey seqkey,
GTM_Sequence increment_by,
GTM_Sequence minval,
diff --git a/src/include/gtm/gtm_txn.h b/src/include/gtm/gtm_txn.h
index 0089064cb0..2b29b68735 100644
--- a/src/include/gtm/gtm_txn.h
+++ b/src/include/gtm/gtm_txn.h
@@ -247,8 +247,8 @@ void ProcessBeginTransactionGetGXIDCommandMulti(Port *myport, StringInfo message
void ProcessCommitTransactionCommandMulti(Port *myport, StringInfo message, bool is_backup);
void ProcessRollbackTransactionCommandMulti(Port *myport, StringInfo message, bool is_backup) ;
-void GTM_SaveTxnInfo(int ctlfd);
-void GTM_RestoreTxnInfo(int ctlfd, GlobalTransactionId next_gxid);
+void GTM_SaveTxnInfo(FILE *ctlf);
+void GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid);
void GTM_BkupBeginTransaction(char *coord_name,
GTM_TransactionHandle txn,
GTM_IsolationLevel isolevel,