On Mon, Aug 15, 2011 at 16:20, Tom Lane <t...@sss.pgh.pa.us> wrote: > Magnus Hagander <mag...@hagander.net> writes: >> I'm trying to make my streaming log receiver work properly with 9.1, >> and have come across a couple of things. The first one that's causing >> trouble is that the definition of the protocol is currently in >> walprotocol.h, which is not include:able in a frontend application. >> AFAICT, this is because it includes utils/timestamp.h, which doesn't >> work. AFAICT, this means that anybody other than our own backend who >> wants to talk our replication protocol has to copy the specific struct >> defines they want in their own code. This seems like a really bad >> idea. (In my case, it's the StandbyReplyMessage that I need, so I can >> make my client not get killed by the default settings for timeout) > >> The basic reason for this is that we're putting TimestampTz fields in >> the protocol. This also means that the protocol actually changes >> definition depending on if the server is compiled with integer or >> float timestamps. While the replication itself breaks if these are >> different, this seems like a bad thing to expose in the protocol. It >> also makes life a lot harder on third party tools. > > I don't really see why it matters, given that the data to be shipped is > also dependent on the timestamp format?
As an example, the stream receiver program needs to be able to construct the status message and send back - thus needs to be able to construct a TimestampTz. It never needs to look into the actual WAL data - it just writes it to a file considering it to be a stream of pure binary data. > However, for a narrow fix, I could see moving the data type definition > to someplace with fewer dependencies. Perhaps split it into a separate > file timestamp_type.h, or something like that. Yes, that seems to fix the problem of timestamptz. See the attached patch - seems ok? I also ran into a similar problem with some WAL macro definitions that are in xlog_internal.h. I've moved them to xlogdefs.h in the attached xlog.diff file. Does that seem ok as well, or should I move them somewhere else? (I don't need all those macros, but I moved the complete block of macros wherever I needed one of them, because otherwise it would be completely impossible to track). This is just a simple move of the definitions, zero new logic added and zero removed. -- Magnus Hagander Me: http://www.hagander.net/ Work: http://www.redpill-linpro.com/
diff --git a/src/include/replication/walprotocol.h b/src/include/replication/walprotocol.h index 9414667..cdba21b 100644 --- a/src/include/replication/walprotocol.h +++ b/src/include/replication/walprotocol.h @@ -13,7 +13,7 @@ #define _WALPROTOCOL_H #include "access/xlogdefs.h" -#include "utils/timestamp.h" +#include "utils/timestamp_defs.h" /* diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h index 9e51b58..1a5ea0d 100644 --- a/src/include/utils/timestamp.h +++ b/src/include/utils/timestamp.h @@ -19,86 +19,7 @@ #include "fmgr.h" #include "pgtime.h" -#ifdef HAVE_INT64_TIMESTAMP -#include "utils/int8.h" -#endif - -/* - * Timestamp represents absolute time. - * - * Interval represents delta time. Keep track of months (and years), days, - * and hours/minutes/seconds separately since the elapsed time spanned is - * unknown until instantiated relative to an absolute time. - * - * Note that Postgres uses "time interval" to mean a bounded interval, - * consisting of a beginning and ending time, not a time span - thomas 97/03/20 - * - * We have two implementations, one that uses int64 values with units of - * microseconds, and one that uses double values with units of seconds. - * - * TimeOffset and fsec_t are convenience typedefs for temporary variables - * that are of different types in the two cases. Do not use fsec_t in values - * stored on-disk, since it is not the same size in both implementations. - * Also, fsec_t is only meant for *fractional* seconds; beware of overflow - * if the value you need to store could be many seconds. - */ - -#ifdef HAVE_INT64_TIMESTAMP - -typedef int64 Timestamp; -typedef int64 TimestampTz; -typedef int64 TimeOffset; -typedef int32 fsec_t; /* fractional seconds (in microseconds) */ -#else - -typedef double Timestamp; -typedef double TimestampTz; -typedef double TimeOffset; -typedef double fsec_t; /* fractional seconds (in seconds) */ -#endif - -typedef struct -{ - TimeOffset time; /* all time units other than days, months and - * years */ - int32 day; /* days, after time for alignment */ - int32 month; /* months and years, after time for alignment */ -} Interval; - - -#define MAX_TIMESTAMP_PRECISION 6 -#define MAX_INTERVAL_PRECISION 6 - -/* in both timestamp.h and ecpg/dt.h */ -#define DAYS_PER_YEAR 365.25 /* assumes leap year every four years */ -#define MONTHS_PER_YEAR 12 -/* - * DAYS_PER_MONTH is very imprecise. The more accurate value is - * 365.2425/12 = 30.436875, or '30 days 10:29:06'. Right now we only - * return an integral number of days, but someday perhaps we should - * also return a 'time' value to be used as well. ISO 8601 suggests - * 30 days. - */ -#define DAYS_PER_MONTH 30 /* assumes exactly 30 days per month */ -#define HOURS_PER_DAY 24 /* assume no daylight savings time changes */ - -/* - * This doesn't adjust for uneven daylight savings time intervals or leap - * seconds, and it crudely estimates leap years. A more accurate value - * for days per years is 365.2422. - */ -#define SECS_PER_YEAR (36525 * 864) /* avoid floating-point computation */ -#define SECS_PER_DAY 86400 -#define SECS_PER_HOUR 3600 -#define SECS_PER_MINUTE 60 -#define MINS_PER_HOUR 60 - -#ifdef HAVE_INT64_TIMESTAMP -#define USECS_PER_DAY INT64CONST(86400000000) -#define USECS_PER_HOUR INT64CONST(3600000000) -#define USECS_PER_MINUTE INT64CONST(60000000) -#define USECS_PER_SEC INT64CONST(1000000) -#endif +#include "timestamp_type.h" /* * Macros for fmgr-callable functions. diff --git a/src/include/utils/timestamp_type.h b/src/include/utils/timestamp_type.h new file mode 100644 index 0000000..377b7f2 --- /dev/null +++ b/src/include/utils/timestamp_type.h @@ -0,0 +1,94 @@ +/*------------------------------------------------------------------------- + * + * timestamp_type.h + * Definitions for the timestamp datatype (separate from timestamp.h so + * they can be used from frontends) + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/timestamp_type.h + * + *------------------------------------------------------------------------- + */ +#ifndef TIMESTAMP_TYPE_H +#define TIMESTAMP_TYPE_H + +/* + * Timestamp represents absolute time. + * + * Interval represents delta time. Keep track of months (and years), days, + * and hours/minutes/seconds separately since the elapsed time spanned is + * unknown until instantiated relative to an absolute time. + * + * Note that Postgres uses "time interval" to mean a bounded interval, + * consisting of a beginning and ending time, not a time span - thomas 97/03/20 + * + * We have two implementations, one that uses int64 values with units of + * microseconds, and one that uses double values with units of seconds. + * + * TimeOffset and fsec_t are convenience typedefs for temporary variables + * that are of different types in the two cases. Do not use fsec_t in values + * stored on-disk, since it is not the same size in both implementations. + * Also, fsec_t is only meant for *fractional* seconds; beware of overflow + * if the value you need to store could be many seconds. + */ + +#ifdef HAVE_INT64_TIMESTAMP + +typedef int64 Timestamp; +typedef int64 TimestampTz; +typedef int64 TimeOffset; +typedef int32 fsec_t; /* fractional seconds (in microseconds) */ +#else + +typedef double Timestamp; +typedef double TimestampTz; +typedef double TimeOffset; +typedef double fsec_t; /* fractional seconds (in seconds) */ +#endif + +typedef struct +{ + TimeOffset time; /* all time units other than days, months and + * years */ + int32 day; /* days, after time for alignment */ + int32 month; /* months and years, after time for alignment */ +} Interval; + + +#define MAX_TIMESTAMP_PRECISION 6 +#define MAX_INTERVAL_PRECISION 6 + +/* in both timestamp.h and ecpg/dt.h */ +#define DAYS_PER_YEAR 365.25 /* assumes leap year every four years */ +#define MONTHS_PER_YEAR 12 +/* + * DAYS_PER_MONTH is very imprecise. The more accurate value is + * 365.2425/12 = 30.436875, or '30 days 10:29:06'. Right now we only + * return an integral number of days, but someday perhaps we should + * also return a 'time' value to be used as well. ISO 8601 suggests + * 30 days. + */ +#define DAYS_PER_MONTH 30 /* assumes exactly 30 days per month */ +#define HOURS_PER_DAY 24 /* assume no daylight savings time changes */ + +/* + * This doesn't adjust for uneven daylight savings time intervals or leap + * seconds, and it crudely estimates leap years. A more accurate value + * for days per years is 365.2422. + */ +#define SECS_PER_YEAR (36525 * 864) /* avoid floating-point computation */ +#define SECS_PER_DAY 86400 +#define SECS_PER_HOUR 3600 +#define SECS_PER_MINUTE 60 +#define MINS_PER_HOUR 60 + +#ifdef HAVE_INT64_TIMESTAMP +#define USECS_PER_DAY INT64CONST(86400000000) +#define USECS_PER_HOUR INT64CONST(3600000000) +#define USECS_PER_MINUTE INT64CONST(60000000) +#define USECS_PER_SEC INT64CONST(1000000) +#endif + +#endif /* TIMESTAMP_TYPE */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 4eaa243..28848f4 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -112,57 +112,6 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; #define XLogPageHeaderSize(hdr) \ (((hdr)->xlp_info & XLP_LONG_HEADER) ? SizeOfXLogLongPHD : SizeOfXLogShortPHD) -/* - * We break each logical log file (xlogid value) into segment files of the - * size indicated by XLOG_SEG_SIZE. One possible segment at the end of each - * log file is wasted, to ensure that we don't have problems representing - * last-byte-position-plus-1. - */ -#define XLogSegSize ((uint32) XLOG_SEG_SIZE) -#define XLogSegsPerFile (((uint32) 0xffffffff) / XLogSegSize) -#define XLogFileSize (XLogSegsPerFile * XLogSegSize) - - -/* - * Macros for manipulating XLOG pointers - */ - -/* Increment an xlogid/segment pair */ -#define NextLogSeg(logId, logSeg) \ - do { \ - if ((logSeg) >= XLogSegsPerFile-1) \ - { \ - (logId)++; \ - (logSeg) = 0; \ - } \ - else \ - (logSeg)++; \ - } while (0) - -/* Decrement an xlogid/segment pair (assume it's not 0,0) */ -#define PrevLogSeg(logId, logSeg) \ - do { \ - if (logSeg) \ - (logSeg)--; \ - else \ - { \ - (logId)--; \ - (logSeg) = XLogSegsPerFile-1; \ - } \ - } while (0) - -/* Align a record pointer to next page */ -#define NextLogPage(recptr) \ - do { \ - if ((recptr).xrecoff % XLOG_BLCKSZ != 0) \ - (recptr).xrecoff += \ - (XLOG_BLCKSZ - (recptr).xrecoff % XLOG_BLCKSZ); \ - if ((recptr).xrecoff >= XLogFileSize) \ - { \ - ((recptr).xlogid)++; \ - (recptr).xrecoff = 0; \ - } \ - } while (0) /* * Compute ID and segment from an XLogRecPtr. @@ -207,36 +156,6 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; #define XLOGDIR "pg_xlog" #define XLOG_CONTROL_FILE "global/pg_control" -/* - * These macros encapsulate knowledge about the exact layout of XLog file - * names, timeline history file names, and archive-status file names. - */ -#define MAXFNAMELEN 64 - -#define XLogFileName(fname, tli, log, seg) \ - snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg) - -#define XLogFromFileName(fname, tli, log, seg) \ - sscanf(fname, "%08X%08X%08X", tli, log, seg) - -#define XLogFilePath(path, tli, log, seg) \ - snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, log, seg) - -#define TLHistoryFileName(fname, tli) \ - snprintf(fname, MAXFNAMELEN, "%08X.history", tli) - -#define TLHistoryFilePath(path, tli) \ - snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli) - -#define StatusFilePath(path, xlog, suffix) \ - snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) - -#define BackupHistoryFileName(fname, tli, log, seg, offset) \ - snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, log, seg, offset) - -#define BackupHistoryFilePath(path, tli, log, seg, offset) \ - snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, log, seg, offset) - /* * Method table for resource managers. diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h index 6530df0..6c0394d 100644 --- a/src/include/access/xlogdefs.h +++ b/src/include/access/xlogdefs.h @@ -71,6 +71,90 @@ typedef struct XLogRecPtr recptr.xrecoff += nbytes; \ } while (0) +/* + * We break each logical log file (xlogid value) into segment files of the + * size indicated by XLOG_SEG_SIZE. One possible segment at the end of each + * log file is wasted, to ensure that we don't have problems representing + * last-byte-position-plus-1. + */ +#define XLogSegSize ((uint32) XLOG_SEG_SIZE) +#define XLogSegsPerFile (((uint32) 0xffffffff) / XLogSegSize) +#define XLogFileSize (XLogSegsPerFile * XLogSegSize) + +/* + * Macros for manipulating XLOG pointers + */ + +/* Increment an xlogid/segment pair */ +#define NextLogSeg(logId, logSeg) \ + do { \ + if ((logSeg) >= XLogSegsPerFile-1) \ + { \ + (logId)++; \ + (logSeg) = 0; \ + } \ + else \ + (logSeg)++; \ + } while (0) + +/* Decrement an xlogid/segment pair (assume it's not 0,0) */ +#define PrevLogSeg(logId, logSeg) \ + do { \ + if (logSeg) \ + (logSeg)--; \ + else \ + { \ + (logId)--; \ + (logSeg) = XLogSegsPerFile-1; \ + } \ + } while (0) + +/* Align a record pointer to next page */ +#define NextLogPage(recptr) \ + do { \ + if ((recptr).xrecoff % XLOG_BLCKSZ != 0) \ + (recptr).xrecoff += \ + (XLOG_BLCKSZ - (recptr).xrecoff % XLOG_BLCKSZ); \ + if ((recptr).xrecoff >= XLogFileSize) \ + { \ + ((recptr).xlogid)++; \ + (recptr).xrecoff = 0; \ + } \ + } while (0) + + + +/* + * These macros encapsulate knowledge about the exact layout of XLog file + * names, timeline history file names, and archive-status file names. + */ +#define MAXFNAMELEN 64 + +#define XLogFileName(fname, tli, log, seg) \ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X", tli, log, seg) + +#define XLogFromFileName(fname, tli, log, seg) \ + sscanf(fname, "%08X%08X%08X", tli, log, seg) + +#define XLogFilePath(path, tli, log, seg) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X", tli, log, seg) + +#define TLHistoryFileName(fname, tli) \ + snprintf(fname, MAXFNAMELEN, "%08X.history", tli) + +#define TLHistoryFilePath(path, tli) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli) + +#define StatusFilePath(path, xlog, suffix) \ + snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) + +#define BackupHistoryFileName(fname, tli, log, seg, offset) \ + snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, log, seg, offset) + +#define BackupHistoryFilePath(path, tli, log, seg, offset) \ + snprintf(path, MAXPGPATH, XLOGDIR "/%08X%08X%08X.%08X.backup", tli, log, seg, offset) + + /* * TimeLineID (TLI) - identifies different database histories to prevent
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers