From c4320619635800a6116a02eee08b232c5abea266 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 30 Apr 2007 21:01:53 +0000
Subject: [PATCH] Change the timestamps recorded in transaction commit/abort
 xlog records from time_t to TimestampTz representation.  This provides full
 gettimeofday() resolution of the timestamps, which might be useful when
 attempting to do point-in-time recovery --- previously it was not possible to
 specify the stop point with sub-second resolution.  But mostly this is to get
 rid of TimestampTz-to-time_t conversion overhead during commit.  Per my
 proposal of a day or two back.

---
 src/backend/access/transam/twophase.c |  6 ++--
 src/backend/access/transam/xact.c     | 18 ++++--------
 src/backend/access/transam/xlog.c     | 42 ++++++++++++++-------------
 src/backend/utils/adt/timestamp.c     | 29 +++++++++++++++++-
 src/include/access/xact.h             |  6 ++--
 src/include/access/xlog_internal.h    |  4 +--
 src/include/utils/timestamp.h         |  4 ++-
 7 files changed, 67 insertions(+), 42 deletions(-)

diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 7d6680485b0..6f495a84087 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.29 2007/04/03 16:34:35 tgl Exp $
+ *		$PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.30 2007/04/30 21:01:52 tgl Exp $
  *
  * NOTES
  *		Each global transaction is associated with a global transaction
@@ -1675,7 +1675,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 
 	/* Emit the XLOG commit record */
 	xlrec.xid = xid;
-	xlrec.crec.xtime = time(NULL);
+	xlrec.crec.xact_time = GetCurrentTimestamp();
 	xlrec.crec.nrels = nrels;
 	xlrec.crec.nsubxacts = nchildren;
 	rdata[0].data = (char *) (&xlrec);
@@ -1753,7 +1753,7 @@ RecordTransactionAbortPrepared(TransactionId xid,
 
 	/* Emit the XLOG abort record */
 	xlrec.xid = xid;
-	xlrec.arec.xtime = time(NULL);
+	xlrec.arec.xact_time = GetCurrentTimestamp();
 	xlrec.arec.nrels = nrels;
 	xlrec.arec.nsubxacts = nchildren;
 	rdata[0].data = (char *) (&xlrec);
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index e3f16d38a5b..f2685ee0b34 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.241 2007/04/30 03:23:48 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.242 2007/04/30 21:01:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -773,7 +773,7 @@ RecordTransactionCommit(void)
 			MyProc->inCommit = true;
 
 			SetCurrentTransactionStopTimestamp();
-			xlrec.xtime = timestamptz_to_time_t(xactStopTimestamp);
+			xlrec.xact_time = xactStopTimestamp;
 			xlrec.nrels = nrels;
 			xlrec.nsubxacts = nchildren;
 			rdata[0].data = (char *) (&xlrec);
@@ -1069,7 +1069,7 @@ RecordTransactionAbort(void)
 			XLogRecPtr	recptr;
 
 			SetCurrentTransactionStopTimestamp();
-			xlrec.xtime = timestamptz_to_time_t(xactStopTimestamp);
+			xlrec.xact_time = xactStopTimestamp;
 			xlrec.nrels = nrels;
 			xlrec.nsubxacts = nchildren;
 			rdata[0].data = (char *) (&xlrec);
@@ -1247,7 +1247,7 @@ RecordSubTransactionAbort(void)
 			xl_xact_abort xlrec;
 			XLogRecPtr	recptr;
 
-			xlrec.xtime = time(NULL);
+			xlrec.xact_time = GetCurrentTimestamp();
 			xlrec.nrels = nrels;
 			xlrec.nsubxacts = nchildren;
 			rdata[0].data = (char *) (&xlrec);
@@ -4282,12 +4282,9 @@ xact_redo(XLogRecPtr lsn, XLogRecord *record)
 static void
 xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
 {
-	struct tm  *tm = localtime(&xlrec->xtime);
 	int			i;
 
-	appendStringInfo(buf, "%04u-%02u-%02u %02u:%02u:%02u",
-					 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-					 tm->tm_hour, tm->tm_min, tm->tm_sec);
+	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
 	if (xlrec->nrels > 0)
 	{
 		appendStringInfo(buf, "; rels:");
@@ -4313,12 +4310,9 @@ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
 static void
 xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
 {
-	struct tm  *tm = localtime(&xlrec->xtime);
 	int			i;
 
-	appendStringInfo(buf, "%04u-%02u-%02u %02u:%02u:%02u",
-					 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-					 tm->tm_hour, tm->tm_min, tm->tm_sec);
+	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
 	if (xlrec->nrels > 0)
 	{
 		appendStringInfo(buf, "; rels:");
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f70a3d5dd0e..655563a3d84 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.267 2007/04/03 16:34:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.268 2007/04/30 21:01:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,6 @@
 #include "storage/procarray.h"
 #include "storage/spin.h"
 #include "utils/builtins.h"
-#include "utils/nabstime.h"
 #include "utils/pg_locale.h"
 
 
@@ -114,11 +113,11 @@ static bool recoveryTarget = false;
 static bool recoveryTargetExact = false;
 static bool recoveryTargetInclusive = true;
 static TransactionId recoveryTargetXid;
-static time_t recoveryTargetTime;
+static TimestampTz recoveryTargetTime;
 
 /* if recoveryStopsHere returns true, it saves actual stop xid/time here */
 static TransactionId recoveryStopXid;
-static time_t recoveryStopTime;
+static TimestampTz recoveryStopTime;
 static bool recoveryStopAfter;
 
 /*
@@ -3536,7 +3535,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 			 xlogfname,
 			 recoveryStopAfter ? "after" : "before",
 			 recoveryStopXid,
-			 str_time(recoveryStopTime));
+			 timestamptz_to_str(recoveryStopTime));
 
 	nbytes = strlen(buffer);
 	errno = 0;
@@ -4276,17 +4275,16 @@ readRecoveryCommandFile(void)
 			recoveryTargetExact = false;
 
 			/*
-			 * Convert the time string given by the user to the time_t format.
-			 * We use type abstime's input converter because we know abstime
-			 * has the same representation as time_t.
+			 * Convert the time string given by the user to TimestampTz form.
 			 */
-			recoveryTargetTime = (time_t)
-				DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
-													 CStringGetDatum(tok2)));
+			recoveryTargetTime =
+				DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+												   CStringGetDatum(tok2),
+												ObjectIdGetDatum(InvalidOid),
+														Int32GetDatum(-1)));
 			ereport(LOG,
 					(errmsg("recovery_target_time = %s",
-							DatumGetCString(DirectFunctionCall1(abstimeout,
-				AbsoluteTimeGetDatum((AbsoluteTime) recoveryTargetTime))))));
+							timestamptz_to_str(recoveryTargetTime))));
 		}
 		else if (strcmp(tok1, "recovery_target_inclusive") == 0)
 		{
@@ -4464,7 +4462,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 {
 	bool		stopsHere;
 	uint8		record_info;
-	time_t		recordXtime;
+	TimestampTz	recordXtime;
 
 	/* Do we have a PITR target at all? */
 	if (!recoveryTarget)
@@ -4479,14 +4477,14 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		xl_xact_commit *recordXactCommitData;
 
 		recordXactCommitData = (xl_xact_commit *) XLogRecGetData(record);
-		recordXtime = recordXactCommitData->xtime;
+		recordXtime = recordXactCommitData->xact_time;
 	}
 	else if (record_info == XLOG_XACT_ABORT)
 	{
 		xl_xact_abort *recordXactAbortData;
 
 		recordXactAbortData = (xl_xact_abort *) XLogRecGetData(record);
-		recordXtime = recordXactAbortData->xtime;
+		recordXtime = recordXactAbortData->xact_time;
 	}
 	else
 		return false;
@@ -4532,22 +4530,26 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 			if (recoveryStopAfter)
 				ereport(LOG,
 						(errmsg("recovery stopping after commit of transaction %u, time %s",
-							  recoveryStopXid, str_time(recoveryStopTime))));
+								recoveryStopXid,
+								timestamptz_to_str(recoveryStopTime))));
 			else
 				ereport(LOG,
 						(errmsg("recovery stopping before commit of transaction %u, time %s",
-							  recoveryStopXid, str_time(recoveryStopTime))));
+								recoveryStopXid,
+								timestamptz_to_str(recoveryStopTime))));
 		}
 		else
 		{
 			if (recoveryStopAfter)
 				ereport(LOG,
 						(errmsg("recovery stopping after abort of transaction %u, time %s",
-							  recoveryStopXid, str_time(recoveryStopTime))));
+								recoveryStopXid,
+								timestamptz_to_str(recoveryStopTime))));
 			else
 				ereport(LOG,
 						(errmsg("recovery stopping before abort of transaction %u, time %s",
-							  recoveryStopXid, str_time(recoveryStopTime))));
+								recoveryStopXid,
+								timestamptz_to_str(recoveryStopTime))));
 		}
 	}
 
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 2a83ae96b2a..f9fb9ef5820 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.175 2007/04/30 03:23:49 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.176 2007/04/30 21:01:52 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1301,6 +1301,33 @@ timestamptz_to_time_t(TimestampTz t)
 	return result;
 }
 
+/*
+ * Produce a C-string representation of a TimestampTz.
+ *
+ * This is mostly for use in emitting messages.  The primary difference
+ * from timestamptz_out is that we force the output format to ISO.  Note
+ * also that the result is in a static buffer, not pstrdup'd.
+ */
+const char *
+timestamptz_to_str(TimestampTz t)
+{
+	static char	buf[MAXDATELEN + 1];
+	int			tz;
+	struct pg_tm tt,
+			   *tm = &tt;
+	fsec_t		fsec;
+	char	   *tzn;
+
+	if (TIMESTAMP_NOT_FINITE(t))
+		EncodeSpecialTimestamp(t, buf);
+	else if (timestamp2tm(t, &tz, tm, &fsec, &tzn, NULL) == 0)
+		EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
+	else
+		strlcpy(buf, "(timestamp out of range)", sizeof(buf));
+
+	return buf;
+}
+
 
 void
 dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 8ec834676df..759eab1a3d9 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.86 2007/04/30 03:23:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.87 2007/04/30 21:01:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -81,7 +81,7 @@ typedef void (*SubXactCallback) (SubXactEvent event, SubTransactionId mySubid,
 
 typedef struct xl_xact_commit
 {
-	time_t		xtime;
+	TimestampTz	xact_time;		/* time of commit */
 	int			nrels;			/* number of RelFileNodes */
 	int			nsubxacts;		/* number of subtransaction XIDs */
 	/* Array of RelFileNode(s) to drop at commit */
@@ -93,7 +93,7 @@ typedef struct xl_xact_commit
 
 typedef struct xl_xact_abort
 {
-	time_t		xtime;
+	TimestampTz	xact_time;		/* time of abort */
 	int			nrels;			/* number of RelFileNodes */
 	int			nsubxacts;		/* number of subtransaction XIDs */
 	/* Array of RelFileNode(s) to drop at abort */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index e2ff478149f..cc9c6070bc7 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.19 2007/03/03 20:02:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.20 2007/04/30 21:01:53 tgl Exp $
  */
 #ifndef XLOG_INTERNAL_H
 #define XLOG_INTERNAL_H
@@ -71,7 +71,7 @@ typedef struct XLogContRecord
 /*
  * Each page of XLOG file has a header like this:
  */
-#define XLOG_PAGE_MAGIC 0xD05F	/* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD061	/* can be used as WAL version indicator */
 
 typedef struct XLogPageHeaderData
 {
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index 594cd61e884..5923c354936 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.68 2007/04/30 03:23:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.69 2007/04/30 21:01:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -318,6 +318,8 @@ extern bool TimestampDifferenceExceeds(TimestampTz start_time,
 extern TimestampTz time_t_to_timestamptz(time_t tm);
 extern time_t timestamptz_to_time_t(TimestampTz t);
 
+extern const char *timestamptz_to_str(TimestampTz t);
+
 extern int	tm2timestamp(struct pg_tm * tm, fsec_t fsec, int *tzp, Timestamp *dt);
 extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm * tm,
 			 fsec_t *fsec, char **tzn, pg_tz *attimezone);
-- 
GitLab