Sorry for the delay. On Fri, Feb 26, 2010 at 6:26 AM, Erik Rijkers <e...@xs4all.nl> wrote: > With this patch the standby compiles, tests, installs OK. > I wanted to check with you if the following is expected.
Thanks for the test and bug report! > With standby (correctly) as follows : > LOG: redo starts at 0/1000020 > LOG: consistent recovery state reached at 0/2000000 > LOG: database system is ready to accept read only connections > > This is OK. > > However, initially (even after the above 'ready' message) > the timeline value as reported by > pg_xlogfile_name_offset(pg_last_xlog_replay_location()) > is zero. When we try to read the WAL record discontinuously (e.g., the REDO starting record and the last applied record), the lastPageTLI is always reset. If that record is not in the buffer, it's read from the disk and the lastPageTLI is set to the right timeline. Otherwise, the lastPageTLI remains at zero wrongly. This is the cause of the problem that you reported. I revised the patch so that the lastPageTLI is always set correctly. Please try this new patch. Regards, -- Fujii Masao NIPPON TELEGRAPH AND TELEPHONE CORPORATION NTT Open Source Software Center
*** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 13199,13204 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); --- 13199,13208 ---- This is usually the desired behavior for managing transaction log archiving behavior, since the preceding file is the last one that currently needs to be archived. + These functions also accept as a parameter the string that consists of timeline and + location, separated by a slash. In this case a transaction log file name is computed + by using the given timeline. On the other hand, if timeline is not supplied, the + current timeline is used for the computation. </para> <para> *************** *** 13245,13257 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); <literal><function>pg_last_xlog_receive_location</function>()</literal> </entry> <entry><type>text</type></entry> ! <entry>Get last transaction log location received and synced to disk during ! streaming recovery. If streaming recovery is still in progress this will increase monotonically. If streaming recovery has completed then this value will remain static at the value of the last WAL record received and synced to disk during that recovery. When the server has been started without a streaming recovery then the return value will be ! InvalidXLogRecPtr (0/0). </entry> </row> <row> --- 13249,13263 ---- <literal><function>pg_last_xlog_receive_location</function>()</literal> </entry> <entry><type>text</type></entry> ! <entry>Get timeline and location of last transaction log received and synced ! to disk during streaming recovery. The return string is separated by a slash, ! the first value indicates the timeline and the other the location. ! If streaming recovery is still in progress this will increase monotonically. If streaming recovery has completed then this value will remain static at the value of the last WAL record received and synced to disk during that recovery. When the server has been started without a streaming recovery then the return value will be ! <literal>0/0/0</>. </entry> </row> <row> *************** *** 13259,13270 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); <literal><function>pg_last_xlog_replay_location</function>()</literal> </entry> <entry><type>text</type></entry> ! <entry>Get last transaction log location replayed during recovery. If recovery is still in progress this will increase monotonically. If recovery has completed then this value will remain static at the value of the last WAL record applied during that recovery. When the server has been started normally without a recovery ! then the return value will be InvalidXLogRecPtr (0/0). </entry> </row> </tbody> --- 13265,13278 ---- <literal><function>pg_last_xlog_replay_location</function>()</literal> </entry> <entry><type>text</type></entry> ! <entry>Get timeline and location of last transaction log replayed during ! recovery. The return string is separated by a slash, the first value ! indicates the timeline and the other the location. If recovery is still in progress this will increase monotonically. If recovery has completed then this value will remain static at the value of the last WAL record applied during that recovery. When the server has been started normally without a recovery ! then the return value will be <literal>0/0/0</>. </entry> </row> </tbody> *** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 392,397 **** typedef struct XLogCtlData --- 392,399 ---- TimestampTz recoveryLastXTime; /* end+1 of the last record replayed */ XLogRecPtr recoveryLastRecPtr; + /* tli of last record replayed */ + TimeLineID recoveryLastTLI; slock_t info_lck; /* locks shared variables shown above */ } XLogCtlData; *************** *** 3581,3594 **** ReadRecord(XLogRecPtr *RecPtr, int emode_arg, bool fetching_ckpt) RecPtr->xlogid, RecPtr->xrecoff))); /* ! * Since we are going to a random position in WAL, forget any prior ! * state about what timeline we were in, and allow it to be any ! * timeline in expectedTLIs. We also set a flag to allow curFileTLI ! * to go backwards (but we can't reset that variable right here, since ! * we might not change files at all). */ ! lastPageTLI = 0; /* see comment in ValidXLOGHeader */ ! randAccess = true; /* allow curFileTLI to go backwards too */ } /* Read the page containing the record */ --- 3583,3593 ---- RecPtr->xlogid, RecPtr->xrecoff))); /* ! * Since we are going to a random position in WAL, set a flag ! * to allow curFileTLI to go backwards (but we can't reset that ! * variable right here, since we might not change files at all). */ ! randAccess = true; /* allow curFileTLI to go backwards */ } /* Read the page containing the record */ *************** *** 5782,5791 **** StartupXLOG(void) /* use volatile pointer to prevent code rearrangement */ volatile XLogCtlData *xlogctl = XLogCtl; ! /* initialize shared replayEndRecPtr and recoveryLastRecPtr */ SpinLockAcquire(&xlogctl->info_lck); xlogctl->replayEndRecPtr = ReadRecPtr; xlogctl->recoveryLastRecPtr = ReadRecPtr; SpinLockRelease(&xlogctl->info_lck); InRedo = true; --- 5781,5797 ---- /* use volatile pointer to prevent code rearrangement */ volatile XLogCtlData *xlogctl = XLogCtl; ! /* ! * initialize shared replayEndRecPtr, recoveryLastRecPtr and ! * recoveryLastTLI. Actually, the latter two variables don't need to ! * be initialized here since they are expected to be updated at least ! * once until read only connections will have read them. But just in ! * case. ! */ SpinLockAcquire(&xlogctl->info_lck); xlogctl->replayEndRecPtr = ReadRecPtr; xlogctl->recoveryLastRecPtr = ReadRecPtr; + xlogctl->recoveryLastTLI = lastPageTLI; SpinLockRelease(&xlogctl->info_lck); InRedo = true; *************** *** 5913,5923 **** StartupXLOG(void) error_context_stack = errcontext.previous; /* ! * Update shared recoveryLastRecPtr after this record has been ! * replayed. */ SpinLockAcquire(&xlogctl->info_lck); xlogctl->recoveryLastRecPtr = EndRecPtr; SpinLockRelease(&xlogctl->info_lck); LastRec = ReadRecPtr; --- 5919,5930 ---- error_context_stack = errcontext.previous; /* ! * Update shared recoveryLastRecPtr and recoveryLastTLI ! * after this record has been replayed. */ SpinLockAcquire(&xlogctl->info_lck); xlogctl->recoveryLastRecPtr = EndRecPtr; + xlogctl->recoveryLastTLI = lastPageTLI; SpinLockRelease(&xlogctl->info_lck); LastRec = ReadRecPtr; *************** *** 8274,8280 **** pg_current_xlog_insert_location(PG_FUNCTION_ARGS) } /* ! * Report the last WAL receive location (same format as pg_start_backup etc) * * This is useful for determining how much of WAL is guaranteed to be received * and synced to disk by walreceiver. --- 8281,8287 ---- } /* ! * Report the last WAL receive tli and location * * This is useful for determining how much of WAL is guaranteed to be received * and synced to disk by walreceiver. *************** *** 8287,8299 **** pg_last_xlog_receive_location(PG_FUNCTION_ARGS) recptr = GetWalRcvWriteRecPtr(); ! snprintf(location, sizeof(location), "%X/%X", recptr.xlogid, recptr.xrecoff); PG_RETURN_TEXT_P(cstring_to_text(location)); } /* ! * Report the last WAL replay location (same format as pg_start_backup etc) * * This is useful for determining how much of WAL is visible to read-only * connections during recovery. --- 8294,8307 ---- recptr = GetWalRcvWriteRecPtr(); ! snprintf(location, sizeof(location), "%X/%X/%X", ! XLogRecPtrIsInvalid(recptr) ? 0 : GetRecoveryTargetTLI(), recptr.xlogid, recptr.xrecoff); PG_RETURN_TEXT_P(cstring_to_text(location)); } /* ! * Report the last WAL replay tli and location * * This is useful for determining how much of WAL is visible to read-only * connections during recovery. *************** *** 8303,8317 **** pg_last_xlog_replay_location(PG_FUNCTION_ARGS) { /* use volatile pointer to prevent code rearrangement */ volatile XLogCtlData *xlogctl = XLogCtl; XLogRecPtr recptr; char location[MAXFNAMELEN]; SpinLockAcquire(&xlogctl->info_lck); recptr = xlogctl->recoveryLastRecPtr; SpinLockRelease(&xlogctl->info_lck); ! snprintf(location, sizeof(location), "%X/%X", ! recptr.xlogid, recptr.xrecoff); PG_RETURN_TEXT_P(cstring_to_text(location)); } --- 8311,8327 ---- { /* use volatile pointer to prevent code rearrangement */ volatile XLogCtlData *xlogctl = XLogCtl; + TimeLineID tli; XLogRecPtr recptr; char location[MAXFNAMELEN]; SpinLockAcquire(&xlogctl->info_lck); + tli = xlogctl->recoveryLastTLI; recptr = xlogctl->recoveryLastRecPtr; SpinLockRelease(&xlogctl->info_lck); ! snprintf(location, sizeof(location), "%X/%X/%X", ! tli, recptr.xlogid, recptr.xrecoff); PG_RETURN_TEXT_P(cstring_to_text(location)); } *************** *** 8319,8324 **** pg_last_xlog_replay_location(PG_FUNCTION_ARGS) --- 8329,8338 ---- * Compute an xlog file name and decimal byte offset given a WAL location, * such as is returned by pg_stop_backup() or pg_xlog_switch(). * + * Also use the tli for the computation if it's given with a location, + * such as is returned by pg_last_xlog_receive_location() or + * pg_last_xlog_replay_location(). + * * Note that a location exactly at a segment boundary is taken to be in * the previous segment. This is usually the right thing, since the * expected usage is to determine which xlog file(s) are ready to archive. *************** *** 8328,8338 **** pg_xlogfile_name_offset(PG_FUNCTION_ARGS) --- 8342,8354 ---- { text *location = PG_GETARG_TEXT_P(0); char *locationstr; + unsigned int utli; unsigned int uxlogid; unsigned int uxrecoff; uint32 xlogid; uint32 xlogseg; uint32 xrecoff; + TimeLineID tli = ThisTimeLineID; XLogRecPtr locationpoint; char xlogfilename[MAXFNAMELEN]; Datum values[2]; *************** *** 8346,8352 **** pg_xlogfile_name_offset(PG_FUNCTION_ARGS) */ locationstr = text_to_cstring(location); ! if (sscanf(locationstr, "%X/%X", &uxlogid, &uxrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", --- 8362,8370 ---- */ locationstr = text_to_cstring(location); ! if (sscanf(locationstr, "%X/%X/%X", &utli, &uxlogid, &uxrecoff) == 3) ! tli = (TimeLineID) utli; ! else if (sscanf(locationstr, "%X/%X", &uxlogid, &uxrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", *************** *** 8371,8377 **** pg_xlogfile_name_offset(PG_FUNCTION_ARGS) * xlogfilename */ XLByteToPrevSeg(locationpoint, xlogid, xlogseg); ! XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg); values[0] = CStringGetTextDatum(xlogfilename); isnull[0] = false; --- 8389,8395 ---- * xlogfilename */ XLByteToPrevSeg(locationpoint, xlogid, xlogseg); ! XLogFileName(xlogfilename, tli, xlogid, xlogseg); values[0] = CStringGetTextDatum(xlogfilename); isnull[0] = false; *************** *** 8397,8418 **** pg_xlogfile_name_offset(PG_FUNCTION_ARGS) /* * Compute an xlog file name given a WAL location, * such as is returned by pg_stop_backup() or pg_xlog_switch(). */ Datum pg_xlogfile_name(PG_FUNCTION_ARGS) { text *location = PG_GETARG_TEXT_P(0); char *locationstr; unsigned int uxlogid; unsigned int uxrecoff; uint32 xlogid; uint32 xlogseg; XLogRecPtr locationpoint; char xlogfilename[MAXFNAMELEN]; locationstr = text_to_cstring(location); ! if (sscanf(locationstr, "%X/%X", &uxlogid, &uxrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", --- 8415,8444 ---- /* * Compute an xlog file name given a WAL location, * such as is returned by pg_stop_backup() or pg_xlog_switch(). + * + * Also use the tli for the computation if it's given with a location, + * such as is returned by pg_last_xlog_receive_location() or + * pg_last_xlog_replay_location(). */ Datum pg_xlogfile_name(PG_FUNCTION_ARGS) { text *location = PG_GETARG_TEXT_P(0); char *locationstr; + unsigned int utli; unsigned int uxlogid; unsigned int uxrecoff; uint32 xlogid; uint32 xlogseg; + TimeLineID tli = ThisTimeLineID; XLogRecPtr locationpoint; char xlogfilename[MAXFNAMELEN]; locationstr = text_to_cstring(location); ! if (sscanf(locationstr, "%X/%X/%X", &utli, &uxlogid, &uxrecoff) == 3) ! tli = (TimeLineID) utli; ! else if (sscanf(locationstr, "%X/%X", &uxlogid, &uxrecoff) != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("could not parse transaction log location \"%s\"", *************** *** 8422,8428 **** pg_xlogfile_name(PG_FUNCTION_ARGS) locationpoint.xrecoff = uxrecoff; XLByteToPrevSeg(locationpoint, xlogid, xlogseg); ! XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); } --- 8448,8454 ---- locationpoint.xrecoff = uxrecoff; XLByteToPrevSeg(locationpoint, xlogid, xlogseg); ! XLogFileName(xlogfilename, tli, xlogid, xlogseg); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); } *************** *** 8721,8726 **** XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt, --- 8747,8760 ---- return true; /* + * Since we are going to a random position in WAL, forget any prior + * state about what timeline we were in, and allow it to be any + * timeline in expectedTLIs. + */ + if (randAccess) + lastPageTLI = 0; /* see comment in ValidXLOGHeader */ + + /* * See if we need to switch to a new segment because the requested record * is not in the currently open one. */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers