Save global_xmin in the GTM control file and use that when its restarted
authorPavan Deolasee <[email protected]>
Wed, 2 Mar 2016 06:18:30 +0000 (11:48 +0530)
committerPavan Deolasee <[email protected]>
Wed, 2 Mar 2016 06:18:30 +0000 (11:48 +0530)
The control file now also have a version identifier so that we can read and
interpret older versions while keeping flexibility to change the format

src/gtm/main/gtm_backup.c
src/gtm/main/gtm_seq.c
src/gtm/main/gtm_standby.c
src/gtm/main/gtm_txn.c
src/gtm/main/main.c
src/gtm/recovery/register_common.c
src/include/gtm/gtm.h
src/include/gtm/gtm_seq.h
src/include/gtm/gtm_txn.h

index c1cba50086b2c7a21ae319c777b1481821c1ea06..8906160d530364f69399ba4f943c7fab3f7a8921 100644 (file)
@@ -32,6 +32,7 @@ void GTM_WriteRestorePoint(void)
        }
        gtm_need_bkup = FALSE;
        GTM_RWLockRelease(&gtm_bkup_lock);
+       GTM_WriteRestorePointVersion(f);
        GTM_WriteRestorePointXid(f);
        GTM_WriteRestorePointSeq(f);
        fclose(f);
@@ -56,28 +57,12 @@ void GTM_WriteBarrierBackup(char *barrier_id)
        GTM_RWLockAcquire(&gtm_bkup_lock, GTM_LOCKMODE_WRITE);
        gtm_need_bkup = FALSE;
        GTM_RWLockRelease(&gtm_bkup_lock);
+       GTM_WriteRestorePointVersion(f);
        GTM_WriteRestorePointXid(f);
        GTM_WriteRestorePointSeq(f);
        fclose(f);
 }
        
-
-void GTM_MakeBackup(char *path)
-{
-       FILE *f = fopen(path, "w");
-
-       if (f == NULL)
-       {
-               ereport(LOG, (errno,
-                                         errmsg("Cannot open backup file %s", path),
-                                         errhint("%s", strerror(errno))));
-               return;
-       }
-       GTM_SaveTxnInfo(f);
-       GTM_SaveSeqInfo(f);
-       fclose(f);
-}
-
 void GTM_SetNeedBackup(void)
 {
        GTM_RWLockAcquire(&gtm_bkup_lock, GTM_LOCKMODE_READ);
index cd90cbafb95675e7d3c0980000acf54288339e46..2fa6bf297ad22dd286cc99fadbdf1a8937dc26df 100644 (file)
@@ -1929,7 +1929,7 @@ encode_seq_key(GTM_SequenceKey seqkey, char *buffer)
 /*
  * Decode the string encoded by the encode_seq_key function
  */
-static void
+void
 decode_seq_key(char* value, GTM_SequenceKey seqkey)
 {
        char   *in;
@@ -2148,82 +2148,6 @@ void GTM_WriteRestorePointSeq(FILE *ctlf)
        GTM_SaveSeqInfo2(ctlf, TRUE);
 }
 
-void
-GTM_RestoreSeqInfo(FILE *ctlf)
-{
-       char seqname[1024];
-
-       if (ctlf == NULL)
-               return;
-
-       while (fscanf(ctlf, "%s", seqname) == 1)
-       {
-               GTM_SequenceKeyData seqkey;
-               GTM_Sequence increment_by;
-               GTM_Sequence minval;
-               GTM_Sequence maxval;
-               GTM_Sequence startval;
-               GTM_Sequence curval;
-               int32 state;
-               bool cycle;
-               bool called;
-               char boolval[16];
-
-               decode_seq_key(seqname, &seqkey);
-
-               if (fscanf(ctlf, "%ld", &curval) != 1)
-               {
-                       elog(WARNING, "Corrupted control file");
-                       return;
-               }
-               if (fscanf(ctlf, "%ld", &startval) != 1)
-               {
-                       elog(WARNING, "Corrupted control file");
-                       return;
-               }
-               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);
-       }
-}
-
 /*
  * Remove all current values allocated for the specified session from all
  * sequences.
index cc5fea758f977365e2ca2cf9deefe46ff1cdbc71..141495d7a0bb557a392344d52f227652acd235a0 100644 (file)
@@ -68,7 +68,7 @@ gtm_standby_restore_next_gxid(void)
        GlobalTransactionId next_gxid = InvalidGlobalTransactionId;
 
        next_gxid = get_next_gxid(GTM_ActiveConn);
-       GTM_RestoreTxnInfo(NULL, next_gxid);
+       GTM_RestoreTxnInfo(NULL, next_gxid, NULL);
 
        elog(DEBUG1, "Restoring the next GXID done.");
        return 1;
index 5e82bdc25fafb7f3fec5d21cc0b40c8e58bcb2c9..6e5973dc3ff0fc7f33283d77e6c270cfc60c1f57 100644 (file)
@@ -32,6 +32,8 @@
 
 extern bool Backup_synchronously;
 
+#define GTM_CONTROL_VERSION    20160302
+
 /* Local functions */
 static XidStatus GlobalTransactionIdGetStatus(GlobalTransactionId transactionId);
 static bool GTM_SetDoVacuum(GTM_TransactionHandle handle);
@@ -93,6 +95,9 @@ GTM_InitTxnManager(void)
         */
        GTMTransactions.gt_latestCompletedXid = FirstNormalGlobalTransactionId;
 
+       /* Initialise gt_recent_global_xmin */
+       GTMTransactions.gt_recent_global_xmin = FirstNormalGlobalTransactionId;
+
        /*
         * Initialize the locks to protect various XID fields as well as the linked
         * list of transactions
@@ -684,6 +689,11 @@ SetNextGlobalTransactionId(GlobalTransactionId gxid)
        return;
 }
 
+void
+SetControlXid(GlobalTransactionId gxid)
+{
+       ControlXid = gxid;
+}
 
 /* Transaction Control */
 int
@@ -2776,62 +2786,11 @@ GTM_SetShuttingDown(void)
        GTM_RWLockRelease(&GTMTransactions.gt_XidGenLock);
 }
 
-void
-GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid)
-{
-       GlobalTransactionId saved_gxid;
-
-       if (ctlf)
-       {
-               if ((fscanf(ctlf, "%u", &saved_gxid) != 1) &&
-                       (!GlobalTransactionIdIsValid(next_gxid)))
-                       next_gxid = InitialGXIDValue_Default;
-               else if (!GlobalTransactionIdIsValid(next_gxid))
-               {
-                       /* Add in extra amount in case we had not gracefully stopped */
-                       next_gxid = saved_gxid + CONTROL_INTERVAL;
-                       ControlXid = next_gxid;
-               }
-       }
-       else if (!GlobalTransactionIdIsValid(next_gxid))
-               next_gxid = InitialGXIDValue_Default;
-
-       elog(LOG, "Restoring last GXID to %u\n", next_gxid);
-
-       if (GlobalTransactionIdIsValid(next_gxid))
-               SetNextGlobalTransactionId(next_gxid);
-       /* Set this otherwise a strange snapshot might be returned for the first one */
-       GTMTransactions.gt_latestCompletedXid = next_gxid - 1;
-       return;
-}
-
-void
-GTM_SaveTxnInfo(FILE *ctlf)
-{
-       GlobalTransactionId next_gxid;
-
-       next_gxid = ReadNewGlobalTransactionId();
-
-       elog(DEBUG1, "Saving transaction info - next_gxid: %u", next_gxid);
-
-       fprintf(ctlf, "%u\n", next_gxid);
-}
-
 bool GTM_NeedXidRestoreUpdate(void)
 {
        return(GlobalTransactionIdPrecedesOrEquals(GTMTransactions.gt_backedUpXid, GTMTransactions.gt_nextXid));
 }
 
-void GTM_WriteRestorePointXid(FILE *f)
-{
-       if ((MaxGlobalTransactionId - GTMTransactions.gt_nextXid) <= RestoreDuration)
-               GTMTransactions.gt_backedUpXid = GTMTransactions.gt_nextXid + RestoreDuration;
-       else
-               GTMTransactions.gt_backedUpXid = FirstNormalGlobalTransactionId + (RestoreDuration - (MaxGlobalTransactionId - GTMTransactions.gt_nextXid));
-       
-       elog(DEBUG1, "Saving transaction restoration info, backed-up gxid: %u", GTMTransactions.gt_backedUpXid);
-       fprintf(f, "%u\n", GTMTransactions.gt_backedUpXid);
-}
 
 GlobalTransactionId
 GTM_GetLatestCompletedXID(void)
index c5e1947948f585102997bd1514ef3ba9e277c29d..8186770ddd8688a86af330e2ab445b029aa1958b 100644 (file)
@@ -94,6 +94,8 @@ static int    ListenSocket[MAXLISTEN];
 pthread_key_t  threadinfo_key;
 static bool            GTMAbortPending = false;
 
+static void GTM_SaveVersion(FILE *ctlf);
+
 static Port *ConnCreate(int serverFd);
 static int ServerLoop(void);
 static int initMasks(fd_set *rmask);
@@ -323,6 +325,7 @@ SaveControlInfo(void)
                return;
        }
 
+       GTM_SaveVersion(ctlf);
        GTM_SaveTxnInfo(ctlf);
        GTM_SaveSeqInfo(ctlf);
        fclose(ctlf);
@@ -648,6 +651,7 @@ main(int argc, char *argv[])
        else
        {
                GTM_MutexLockAcquire(&control_lock);
+               GTM_RestoreContext restoreContext;
 
                ctlf = fopen(GTMControlFile, "r");
 
@@ -691,8 +695,10 @@ main(int argc, char *argv[])
                                elog(ERROR, "Could not open %s, errno %d - aborting GTM start",
                                                GTMControlFile, errno);
                }
-               GTM_RestoreTxnInfo(ctlf, next_gxid);
-               GTM_RestoreSeqInfo(ctlf);
+
+               GTM_RestoreStart(ctlf, &restoreContext);
+               GTM_RestoreTxnInfo(ctlf, next_gxid, &restoreContext);
+               GTM_RestoreSeqInfo(ctlf, &restoreContext);
                if (ctlf)
                        fclose(ctlf);
 
@@ -2284,3 +2290,210 @@ static void ProcessBarrierCommand(Port *myport, GTM_MessageType mtype, StringInf
        }
 }
        
+void
+GTM_RestoreStart(FILE *ctlf, struct GTM_RestoreContext *context)
+{
+       int version;
+
+       Assert(ctlf);
+
+       if (fscanf(ctlf, "version: %d\n", &version) == 1)
+       {
+               elog(LOG, "Read control file version %d", version);
+               context->version = version;
+       }
+       else
+       {
+               elog(LOG, "Failed to read file version");
+               context->version = -1;
+       }
+}
+
+void
+GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid,
+               struct GTM_RestoreContext *context)
+{
+       GlobalTransactionId saved_gxid;
+       GlobalTransactionId saved_global_xmin;
+
+       if (ctlf)
+       {
+               /*
+                * If the control file version is 20160302, then we expect to see
+                * next_xid and global_xmin saved as first two lines. For older
+                * versions, just the next_xid is stored
+                */
+               if (context && context->version == 20160302)
+               {
+                       if (fscanf(ctlf, "next_xid: %u\n", &saved_gxid) != 1)
+                               saved_gxid = InvalidGlobalTransactionId;
+
+                       if (fscanf(ctlf, "global_xmin: %u\n", &saved_global_xmin) != 1)
+                               saved_global_xmin = InvalidGlobalTransactionId;
+               }
+               else
+               {
+                       if (fscanf(ctlf, "%u\n", &saved_gxid) != 1)
+                               saved_gxid = InvalidGlobalTransactionId;
+                       saved_global_xmin = InvalidGlobalTransactionId;
+               }
+       }
+
+       /*
+        * If the caller has supplied an explicit XID to restore, just use that.
+        * This is typically only be used during initdb and in some exception
+        * circumstances to recover from failures. But otherwise we must start with
+        * the XIDs saved in the control file
+        *
+        * If the global_xmin was saved (which should be unless we are dealing with
+        * an old control file), use that. Otherwise set it saved_gxid/next_xid
+        * whatever is available. If we don't used the value incremented by
+        * CONTROL_INTERVAL because its better to start with a conservative value
+        * for the GlobalXmin
+        */
+       if (!GlobalTransactionIdIsValid(next_gxid))
+       {
+               if (GlobalTransactionIdIsValid(saved_gxid))
+               {
+                       /* 
+                        * Add in extra amount in case we had not gracefully stopped
+                        */
+                       next_gxid = saved_gxid + CONTROL_INTERVAL;
+                       SetControlXid(next_gxid);
+               }
+               else
+                       saved_gxid = next_gxid = InitialGXIDValue_Default;
+
+               if (GlobalTransactionIdIsValid(saved_global_xmin))
+                       GTMTransactions.gt_recent_global_xmin = saved_global_xmin;
+               else
+                       GTMTransactions.gt_recent_global_xmin = saved_gxid;
+       }
+       else
+               GTMTransactions.gt_recent_global_xmin = next_gxid;
+
+       SetNextGlobalTransactionId(next_gxid);
+       elog(LOG, "Restoring last GXID to %u\n", next_gxid);
+       elog(LOG, "Restoring global xmin to %u\n",
+                       GTMTransactions.gt_recent_global_xmin);
+
+       /* Set this otherwise a strange snapshot might be returned for the first one */
+       GTMTransactions.gt_latestCompletedXid = next_gxid - 1;
+       return;
+}
+
+static void
+GTM_SaveVersion(FILE *ctlf)
+{
+       fprintf(ctlf, "version: %d\n", GTM_CONTROL_VERSION);
+}
+
+void
+GTM_SaveTxnInfo(FILE *ctlf)
+{
+       GlobalTransactionId next_gxid;
+       GlobalTransactionId global_xmin = GTMTransactions.gt_recent_global_xmin;
+
+       next_gxid = ReadNewGlobalTransactionId();
+
+       elog(DEBUG1, "Saving transaction info - next_gxid: %u, global_xmin: %u",
+                       next_gxid, global_xmin);
+
+       fprintf(ctlf, "next_xid: %u\n", next_gxid);
+       fprintf(ctlf, "global_xmin: %u\n", global_xmin);
+}
+
+void
+GTM_WriteRestorePointXid(FILE *f)
+{
+       if ((MaxGlobalTransactionId - GTMTransactions.gt_nextXid) <= RestoreDuration)
+               GTMTransactions.gt_backedUpXid = GTMTransactions.gt_nextXid + RestoreDuration;
+       else
+               GTMTransactions.gt_backedUpXid = FirstNormalGlobalTransactionId + (RestoreDuration - (MaxGlobalTransactionId - GTMTransactions.gt_nextXid));
+       
+       elog(DEBUG1, "Saving transaction restoration info, backed-up gxid: %u", GTMTransactions.gt_backedUpXid);
+       fprintf(f, "next_xid: %u\n", GTMTransactions.gt_backedUpXid);
+       fprintf(f, "global_xmin: %u\n", GTMTransactions.gt_backedUpXid);
+}
+
+void
+GTM_WriteRestorePointVersion(FILE *f)
+{
+       GTM_SaveVersion(f);
+}
+
+void
+GTM_RestoreSeqInfo(FILE *ctlf, struct GTM_RestoreContext *context)
+{
+       char seqname[1024];
+
+       if (ctlf == NULL)
+               return;
+
+       while (fscanf(ctlf, "%s", seqname) == 1)
+       {
+               GTM_SequenceKeyData seqkey;
+               GTM_Sequence increment_by;
+               GTM_Sequence minval;
+               GTM_Sequence maxval;
+               GTM_Sequence startval;
+               GTM_Sequence curval;
+               int32 state;
+               bool cycle;
+               bool called;
+               char boolval[16];
+
+               decode_seq_key(seqname, &seqkey);
+
+               if (fscanf(ctlf, "%ld", &curval) != 1)
+               {
+                       elog(WARNING, "Corrupted control file");
+                       return;
+               }
+               if (fscanf(ctlf, "%ld", &startval) != 1)
+               {
+                       elog(WARNING, "Corrupted control file");
+                       return;
+               }
+               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);
+       }
+}
index 0d73685d1caf1fe67f0545281ed21f9f81593f6a..5d5c8d658a6e5ece90a8dd3c8e0ed0ea0dd26e50 100644 (file)
@@ -57,8 +57,9 @@ static int NodeRegisterMagic = 0xeaeaeaea;
 static int NodeUnregisterMagic = 0xebebebeb;
 static int NodeEndMagic = 0xefefefef;
 
+#define GTM_GlobalXmin GTMTransactions.gt_recent_global_xmin
+
 static GTM_PGXCNodeInfoHashBucket GTM_PGXCNodes[NODE_HASH_TABLE_SIZE];
-static GlobalTransactionId GTM_GlobalXmin = FirstNormalGlobalTransactionId;
 static GTM_Timestamp GTM_GlobalXminComputedTime;
 
 static GTM_PGXCNodeInfo *pgxcnode_find_info(GTM_PGXCNodeType type, char *node_name);
@@ -1025,10 +1026,6 @@ GTM_HandleGlobalXmin(GTM_PGXCNodeType type, char *node_name,
                *errcode = GTM_ERRCODE_TOO_OLD_XMIN;
 
                mynodeinfo->joining = true;
-               mynodeinfo->reported_xmin_time = GTM_TimestampGetCurrent();
-               mynodeinfo->reported_xmin = GTM_GlobalXmin;
-
-               GTM_RWLockRelease(&mynodeinfo->node_lock);
 
                /*
                 * When node registers from the first time, the reported_xmin is set
@@ -1042,6 +1039,11 @@ GTM_HandleGlobalXmin(GTM_PGXCNodeType type, char *node_name,
                        elog(LOG, "GTM_ERRCODE_TOO_OLD_XMIN - node_name %s, reported_xmin %d, "
                                        "previously reported_xmin %d, GTM_GlobalXmin %d", node_name,
                                        reported_xmin, mynodeinfo->reported_xmin, GTM_GlobalXmin);
+
+               mynodeinfo->reported_xmin_time = GTM_TimestampGetCurrent();
+               mynodeinfo->reported_xmin = GTM_GlobalXmin;
+
+               GTM_RWLockRelease(&mynodeinfo->node_lock);
                return InvalidGlobalTransactionId;
        }
 
index 200e09c66880bb937d6d01f1e895b2a3614c3807..8dfa77b1397fb49b6c12ef33f0801feab5b70019 100644 (file)
@@ -73,6 +73,10 @@ typedef struct GTM_Threads
 
 extern GTM_Threads *GTMThreads;
 
+typedef struct GTM_RestoreContext {
+       int     version;
+} GTM_RestoreContext;
+
 int GTM_ThreadAdd(GTM_ThreadInfo *thrinfo);
 int GTM_ThreadRemove(GTM_ThreadInfo *thrinfo);
 int GTM_ThreadJoin(GTM_ThreadInfo *thrinfo);
@@ -88,6 +92,7 @@ GTM_ThreadInfo *GTM_ThreadCreate(GTM_ConnectionInfo *conninfo,
 GTM_ThreadInfo * GTM_GetThreadInfo(GTM_ThreadID thrid);
 #ifdef XCP
 extern void SaveControlInfo(void);
+void GTM_RestoreSeqInfo(FILE *ctlf, struct GTM_RestoreContext *context);
 #define CONTROL_INTERVAL               50000
 #endif
 
@@ -143,5 +148,6 @@ extern GTM_ThreadID                                         TopMostThreadID;
        ((((a) + 1) == UINT32_MAX) ? 1 : ((a) + 1))
 
 #define GTM_CONTROL_FILE               "gtm.control"
+#define GTM_CONTROL_VERSION            20160302
 
 #endif
index aee08a762135e3744331dc8739dc8bb853eea066..870ac56b946546e7f016c4aae9fc03985fa282cb 100644 (file)
@@ -101,8 +101,8 @@ void ProcessSequenceAlterCommand(Port *myport, StringInfo message, bool is_backu
 
 void ProcessSequenceListCommand(Port *myport, StringInfo message);
 
+void decode_seq_key(char* value, GTM_SequenceKey seqkey);
 void GTM_SaveSeqInfo(FILE *ctlf);
-void GTM_RestoreSeqInfo(FILE *ctlf);
 int GTM_SeqRestore(GTM_SequenceKey seqkey,
                           GTM_Sequence increment_by,
                           GTM_Sequence minval,
index 0a7b38b29cdb0e6df785381d2cf70201955b8c6f..86c7986811381f5ca4b4bea9c0869077095ba1c6 100644 (file)
@@ -28,6 +28,7 @@ typedef int XidStatus;
 #define TRANSACTION_STATUS_COMMITTED        0x01
 #define TRANSACTION_STATUS_ABORTED          0x02
 
+struct GTM_RestoreContext;
 /*
  * prototypes for functions in transam/transam.c
  */
@@ -226,8 +227,11 @@ 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_WriteRestorePointVersion(FILE *f);
+void GTM_RestoreStart(FILE *ctlf, struct GTM_RestoreContext *context);
 void GTM_SaveTxnInfo(FILE *ctlf);
-void GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid);
+void GTM_RestoreTxnInfo(FILE *ctlf, GlobalTransactionId next_gxid,
+               struct GTM_RestoreContext *context);
 void GTM_BkupBeginTransaction(GTM_IsolationLevel isolevel,
                                                          bool readonly,
                                                          const char *global_sessionid,