]> granicus.if.org Git - postgresql/commitdiff
Move user functions related to WAL into xlogfuncs.c
authorSimon Riggs <simon@2ndQuadrant.com>
Fri, 4 Nov 2011 09:37:17 +0000 (09:37 +0000)
committerSimon Riggs <simon@2ndQuadrant.com>
Fri, 4 Nov 2011 09:37:17 +0000 (09:37 +0000)
src/backend/access/transam/Makefile
src/backend/access/transam/xlog.c
src/backend/access/transam/xlogfuncs.c [new file with mode: 0644]
src/include/access/xlog.h

index 4179433bc1413e81c3be8af6c8a42005f3caf4ec..f82f10e989ef645dd58988c6d7c2c941e4e9e1df 100644 (file)
@@ -12,7 +12,8 @@ subdir = src/backend/access/transam
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = clog.o transam.o varsup.o xact.o xlog.o xlogutils.o rmgr.o slru.o subtrans.o multixact.o twophase.o twophase_rmgr.o
+OBJS = clog.o transam.o varsup.o xact.o rmgr.o slru.o subtrans.o multixact.o \
+       twophase.o twophase_rmgr.o xlog.o xlogfuncs.o xlogutils.o
 
 include $(top_srcdir)/src/backend/common.mk
 
index 85f79b9685134b24e58ba5a3750d3314884aade7..0d494e2e3bfdef46dad20a5da1b5295e4a079a07 100644 (file)
@@ -35,8 +35,6 @@
 #include "catalog/catversion.h"
 #include "catalog/pg_control.h"
 #include "catalog/pg_database.h"
-#include "catalog/pg_type.h"
-#include "funcapi.h"
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "pgstat.h"
@@ -596,10 +594,7 @@ static void exitArchiveRecovery(TimeLineID endTLI,
                                        uint32 endLogId, uint32 endLogSeg);
 static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
 static void recoveryPausesHere(void);
-static bool RecoveryIsPaused(void);
-static void SetRecoveryPause(bool recoveryPause);
 static void SetLatestXTime(TimestampTz xtime);
-static TimestampTz GetLatestXTime(void);
 static void CheckRequiredParameterValues(void);
 static void XLogReportParameters(void);
 static void LocalSetXLogInsertAllowed(void);
@@ -5762,7 +5757,7 @@ recoveryPausesHere(void)
        }
 }
 
-static bool
+bool
 RecoveryIsPaused(void)
 {
        /* use volatile pointer to prevent code rearrangement */
@@ -5776,7 +5771,7 @@ RecoveryIsPaused(void)
        return recoveryPause;
 }
 
-static void
+void
 SetRecoveryPause(bool recoveryPause)
 {
        /* use volatile pointer to prevent code rearrangement */
@@ -5787,70 +5782,6 @@ SetRecoveryPause(bool recoveryPause)
        SpinLockRelease(&xlogctl->info_lck);
 }
 
-/*
- * pg_xlog_replay_pause - pause recovery now
- */
-Datum
-pg_xlog_replay_pause(PG_FUNCTION_ARGS)
-{
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to control recovery"))));
-
-       if (!RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is not in progress"),
-                                errhint("Recovery control functions can only be executed during recovery.")));
-
-       SetRecoveryPause(true);
-
-       PG_RETURN_VOID();
-}
-
-/*
- * pg_xlog_replay_resume - resume recovery now
- */
-Datum
-pg_xlog_replay_resume(PG_FUNCTION_ARGS)
-{
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to control recovery"))));
-
-       if (!RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is not in progress"),
-                                errhint("Recovery control functions can only be executed during recovery.")));
-
-       SetRecoveryPause(false);
-
-       PG_RETURN_VOID();
-}
-
-/*
- * pg_is_xlog_replay_paused
- */
-Datum
-pg_is_xlog_replay_paused(PG_FUNCTION_ARGS)
-{
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to control recovery"))));
-
-       if (!RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is not in progress"),
-                                errhint("Recovery control functions can only be executed during recovery.")));
-
-       PG_RETURN_BOOL(RecoveryIsPaused());
-}
-
 /*
  * Save timestamp of latest processed commit/abort record.
  *
@@ -5872,7 +5803,7 @@ SetLatestXTime(TimestampTz xtime)
 /*
  * Fetch timestamp of latest processed commit/abort record.
  */
-static TimestampTz
+TimestampTz
 GetLatestXTime(void)
 {
        /* use volatile pointer to prevent code rearrangement */
@@ -5886,33 +5817,6 @@ GetLatestXTime(void)
        return xtime;
 }
 
-/*
- * Returns timestamp of latest processed commit/abort record.
- *
- * When the server has been started normally without recovery the function
- * returns NULL.
- */
-Datum
-pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
-{
-       TimestampTz xtime;
-
-       xtime = GetLatestXTime();
-       if (xtime == 0)
-               PG_RETURN_NULL();
-
-       PG_RETURN_TIMESTAMPTZ(xtime);
-}
-
-/*
- * Returns bool with current recovery mode, a global state.
- */
-Datum
-pg_is_in_recovery(PG_FUNCTION_ARGS)
-{
-       PG_RETURN_BOOL(RecoveryInProgress());
-}
-
 /*
  * Returns time of receipt of current chunk of XLOG data, as well as
  * whether it was received from streaming replication or from archives.
@@ -8835,34 +8739,6 @@ issue_xlog_fsync(int fd, uint32 log, uint32 seg)
        }
 }
 
-
-/*
- * pg_start_backup: set up for taking an on-line backup dump
- *
- * Essentially what this does is to create a backup label file in $PGDATA,
- * where it will be archived as part of the backup dump.  The label file
- * contains the user-supplied label string (typically this would be used
- * to tell where the backup dump will be stored) and the starting time and
- * starting WAL location for the dump.
- */
-Datum
-pg_start_backup(PG_FUNCTION_ARGS)
-{
-       text       *backupid = PG_GETARG_TEXT_P(0);
-       bool            fast = PG_GETARG_BOOL(1);
-       char       *backupidstr;
-       XLogRecPtr      startpoint;
-       char            startxlogstr[MAXFNAMELEN];
-
-       backupidstr = text_to_cstring(backupid);
-
-       startpoint = do_pg_start_backup(backupidstr, fast, NULL);
-
-       snprintf(startxlogstr, sizeof(startxlogstr), "%X/%X",
-                        startpoint.xlogid, startpoint.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
-}
-
 /*
  * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
  * function. It creates the necessary starting checkpoint and constructs the
@@ -9122,32 +8998,6 @@ pg_start_backup_callback(int code, Datum arg)
        LWLockRelease(WALInsertLock);
 }
 
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_xlog
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
-       XLogRecPtr      stoppoint;
-       char            stopxlogstr[MAXFNAMELEN];
-
-       stoppoint = do_pg_stop_backup(NULL, true);
-
-       snprintf(stopxlogstr, sizeof(stopxlogstr), "%X/%X",
-                        stoppoint.xlogid, stoppoint.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
-}
-
 /*
  * do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
  * function.
@@ -9433,166 +9283,6 @@ do_pg_abort_backup(void)
        LWLockRelease(WALInsertLock);
 }
 
-/*
- * pg_switch_xlog: switch to next xlog file
- */
-Datum
-pg_switch_xlog(PG_FUNCTION_ARGS)
-{
-       XLogRecPtr      switchpoint;
-       char            location[MAXFNAMELEN];
-
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                        (errmsg("must be superuser to switch transaction log files"))));
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("WAL control functions cannot be executed during recovery.")));
-
-       switchpoint = RequestXLogSwitch();
-
-       /*
-        * As a convenience, return the WAL location of the switch record
-        */
-       snprintf(location, sizeof(location), "%X/%X",
-                        switchpoint.xlogid, switchpoint.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
-/*
- * pg_create_restore_point: a named point for restore
- */
-Datum
-pg_create_restore_point(PG_FUNCTION_ARGS)
-{
-       text       *restore_name = PG_GETARG_TEXT_P(0);
-       char       *restore_name_str;
-       XLogRecPtr      restorepoint;
-       char            location[MAXFNAMELEN];
-
-       if (!superuser())
-               ereport(ERROR,
-                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-                                (errmsg("must be superuser to create a restore point"))));
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                (errmsg("recovery is in progress"),
-                                 errhint("WAL control functions cannot be executed during recovery."))));
-
-       if (!XLogIsNeeded())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                        errmsg("WAL level not sufficient for creating a restore point"),
-                                errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
-
-       restore_name_str = text_to_cstring(restore_name);
-
-       if (strlen(restore_name_str) >= MAXFNAMELEN)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
-
-       restorepoint = XLogRestorePoint(restore_name_str);
-
-       /*
-        * As a convenience, return the WAL location of the restore point record
-        */
-       snprintf(location, sizeof(location), "%X/%X",
-                        restorepoint.xlogid, restorepoint.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
-/*
- * Report the current WAL write location (same format as pg_start_backup etc)
- *
- * This is useful for determining how much of WAL is visible to an external
- * archiving process.  Note that the data before this point is written out
- * to the kernel, but is not necessarily synced to disk.
- */
-Datum
-pg_current_xlog_location(PG_FUNCTION_ARGS)
-{
-       char            location[MAXFNAMELEN];
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("WAL control functions cannot be executed during recovery.")));
-
-       /* Make sure we have an up-to-date local LogwrtResult */
-       {
-               /* use volatile pointer to prevent code rearrangement */
-               volatile XLogCtlData *xlogctl = XLogCtl;
-
-               SpinLockAcquire(&xlogctl->info_lck);
-               LogwrtResult = xlogctl->LogwrtResult;
-               SpinLockRelease(&xlogctl->info_lck);
-       }
-
-       snprintf(location, sizeof(location), "%X/%X",
-                        LogwrtResult.Write.xlogid, LogwrtResult.Write.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
-/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
- *
- * This function is mostly for debugging purposes.
- */
-Datum
-pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
-{
-       XLogCtlInsert *Insert = &XLogCtl->Insert;
-       XLogRecPtr      current_recptr;
-       char            location[MAXFNAMELEN];
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("WAL control functions cannot be executed during recovery.")));
-
-       /*
-        * Get the current end-of-WAL position ... shared lock is sufficient
-        */
-       LWLockAcquire(WALInsertLock, LW_SHARED);
-       INSERT_RECPTR(current_recptr, Insert, Insert->curridx);
-       LWLockRelease(WALInsertLock);
-
-       snprintf(location, sizeof(location), "%X/%X",
-                        current_recptr.xlogid, current_recptr.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
-/*
- * 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.
- */
-Datum
-pg_last_xlog_receive_location(PG_FUNCTION_ARGS)
-{
-       XLogRecPtr      recptr;
-       char            location[MAXFNAMELEN];
-
-       recptr = GetWalRcvWriteRecPtr(NULL);
-
-       if (recptr.xlogid == 0 && recptr.xrecoff == 0)
-               PG_RETURN_NULL();
-
-       snprintf(location, sizeof(location), "%X/%X",
-                        recptr.xlogid, recptr.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
 /*
  * Get latest redo apply position.
  *
@@ -9639,149 +9329,39 @@ GetStandbyFlushRecPtr(void)
 }
 
 /*
- * 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.
- */
-Datum
-pg_last_xlog_replay_location(PG_FUNCTION_ARGS)
-{
-       XLogRecPtr      recptr;
-       char            location[MAXFNAMELEN];
-
-       recptr = GetXLogReplayRecPtr(NULL);
-
-       if (recptr.xlogid == 0 && recptr.xrecoff == 0)
-               PG_RETURN_NULL();
-
-       snprintf(location, sizeof(location), "%X/%X",
-                        recptr.xlogid, recptr.xrecoff);
-       PG_RETURN_TEXT_P(cstring_to_text(location));
-}
-
-/*
- * 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().
- *
- * 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.
+ * Get latest WAL insert pointer
  */
-Datum
-pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
+XLogRecPtr
+GetXLogInsertRecPtr(bool needlock)
 {
-       text       *location = PG_GETARG_TEXT_P(0);
-       char       *locationstr;
-       unsigned int uxlogid;
-       unsigned int uxrecoff;
-       uint32          xlogid;
-       uint32          xlogseg;
-       uint32          xrecoff;
-       XLogRecPtr      locationpoint;
-       char            xlogfilename[MAXFNAMELEN];
-       Datum           values[2];
-       bool            isnull[2];
-       TupleDesc       resultTupleDesc;
-       HeapTuple       resultHeapTuple;
-       Datum           result;
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("pg_xlogfile_name_offset() cannot be executed during recovery.")));
-
-       /*
-        * Read input and parse
-        */
-       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\"",
-                                               locationstr)));
-
-       locationpoint.xlogid = uxlogid;
-       locationpoint.xrecoff = uxrecoff;
-
-       /*
-        * Construct a tuple descriptor for the result row.  This must match this
-        * function's pg_proc entry!
-        */
-       resultTupleDesc = CreateTemplateTupleDesc(2, false);
-       TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
-                                          TEXTOID, -1, 0);
-       TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
-                                          INT4OID, -1, 0);
-
-       resultTupleDesc = BlessTupleDesc(resultTupleDesc);
-
-       /*
-        * xlogfilename
-        */
-       XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
-       XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
-
-       values[0] = CStringGetTextDatum(xlogfilename);
-       isnull[0] = false;
-
-       /*
-        * offset
-        */
-       xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize;
-
-       values[1] = UInt32GetDatum(xrecoff);
-       isnull[1] = false;
-
-       /*
-        * Tuple jam: Having first prepared your Datums, then squash together
-        */
-       resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
+       XLogCtlInsert *Insert = &XLogCtl->Insert;
+       XLogRecPtr      current_recptr;
 
-       result = HeapTupleGetDatum(resultHeapTuple);
+       if (needlock)
+               LWLockAcquire(WALInsertLock, LW_SHARED);
+       INSERT_RECPTR(current_recptr, Insert, Insert->curridx);
+       if (needlock)
+               LWLockRelease(WALInsertLock);
 
-       PG_RETURN_DATUM(result);
+       return current_recptr;
 }
 
 /*
- * Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_xlog_switch().
+ * Get latest WAL write pointer
  */
-Datum
-pg_xlogfile_name(PG_FUNCTION_ARGS)
+XLogRecPtr
+GetXLogWriteRecPtr(void)
 {
-       text       *location = PG_GETARG_TEXT_P(0);
-       char       *locationstr;
-       unsigned int uxlogid;
-       unsigned int uxrecoff;
-       uint32          xlogid;
-       uint32          xlogseg;
-       XLogRecPtr      locationpoint;
-       char            xlogfilename[MAXFNAMELEN];
-
-       if (RecoveryInProgress())
-               ereport(ERROR,
-                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                errhint("pg_xlogfile_name() cannot be executed during recovery.")));
-
-       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\"",
-                                               locationstr)));
-
-       locationpoint.xlogid = uxlogid;
-       locationpoint.xrecoff = uxrecoff;
+       {
+               /* use volatile pointer to prevent code rearrangement */
+               volatile XLogCtlData *xlogctl = XLogCtl;
 
-       XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
-       XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
+               SpinLockAcquire(&xlogctl->info_lck);
+               LogwrtResult = xlogctl->LogwrtResult;
+               SpinLockRelease(&xlogctl->info_lck);
+       }
 
-       PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
+       return LogwrtResult.Write;
 }
 
 /*
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
new file mode 100644 (file)
index 0000000..22c6ca0
--- /dev/null
@@ -0,0 +1,467 @@
+/*-------------------------------------------------------------------------
+ *
+ * xlogfuncs.c
+ *
+ * PostgreSQL transaction log manager user interface functions
+ *
+ * This file contains WAL control and information functions.
+ *
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/backend/access/transam/xlogfuncs.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/xlog.h"
+#include "access/xlog_internal.h"
+#include "access/xlogutils.h"
+#include "catalog/catalog.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "replication/walreceiver.h"
+#include "storage/smgr.h"
+#include "utils/builtins.h"
+#include "utils/guc.h"
+#include "utils/timestamp.h"
+
+/*
+ * pg_start_backup: set up for taking an on-line backup dump
+ *
+ * Essentially what this does is to create a backup label file in $PGDATA,
+ * where it will be archived as part of the backup dump.  The label file
+ * contains the user-supplied label string (typically this would be used
+ * to tell where the backup dump will be stored) and the starting time and
+ * starting WAL location for the dump.
+ */
+Datum
+pg_start_backup(PG_FUNCTION_ARGS)
+{
+       text       *backupid = PG_GETARG_TEXT_P(0);
+       bool            fast = PG_GETARG_BOOL(1);
+       char       *backupidstr;
+       XLogRecPtr      startpoint;
+       char            startxlogstr[MAXFNAMELEN];
+
+       backupidstr = text_to_cstring(backupid);
+
+       startpoint = do_pg_start_backup(backupidstr, fast, NULL);
+
+       snprintf(startxlogstr, sizeof(startxlogstr), "%X/%X",
+                        startpoint.xlogid, startpoint.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
+}
+
+/*
+ * pg_stop_backup: finish taking an on-line backup dump
+ *
+ * We write an end-of-backup WAL record, and remove the backup label file
+ * created by pg_start_backup, creating a backup history file in pg_xlog
+ * instead (whence it will immediately be archived). The backup history file
+ * contains the same info found in the label file, plus the backup-end time
+ * and WAL location. Before 9.0, the backup-end time was read from the backup
+ * history file at the beginning of archive recovery, but we now use the WAL
+ * record for that and the file is for informational and debug purposes only.
+ *
+ * Note: different from CancelBackup which just cancels online backup mode.
+ */
+Datum
+pg_stop_backup(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      stoppoint;
+       char            stopxlogstr[MAXFNAMELEN];
+
+       stoppoint = do_pg_stop_backup(NULL, true);
+
+       snprintf(stopxlogstr, sizeof(stopxlogstr), "%X/%X",
+                        stoppoint.xlogid, stoppoint.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
+}
+
+/*
+ * pg_switch_xlog: switch to next xlog file
+ */
+Datum
+pg_switch_xlog(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      switchpoint;
+       char            location[MAXFNAMELEN];
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to switch transaction log files"))));
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is in progress"),
+                                errhint("WAL control functions cannot be executed during recovery.")));
+
+       switchpoint = RequestXLogSwitch();
+
+       /*
+        * As a convenience, return the WAL location of the switch record
+        */
+       snprintf(location, sizeof(location), "%X/%X",
+                        switchpoint.xlogid, switchpoint.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(location));
+}
+
+/*
+ * pg_create_restore_point: a named point for restore
+ */
+Datum
+pg_create_restore_point(PG_FUNCTION_ARGS)
+{
+       text       *restore_name = PG_GETARG_TEXT_P(0);
+       char       *restore_name_str;
+       XLogRecPtr      restorepoint;
+       char            location[MAXFNAMELEN];
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("must be superuser to create a restore point"))));
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                (errmsg("recovery is in progress"),
+                                 errhint("WAL control functions cannot be executed during recovery."))));
+
+       if (!XLogIsNeeded())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                        errmsg("WAL level not sufficient for creating a restore point"),
+                                errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
+
+       restore_name_str = text_to_cstring(restore_name);
+
+       if (strlen(restore_name_str) >= MAXFNAMELEN)
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
+
+       restorepoint = XLogRestorePoint(restore_name_str);
+
+       /*
+        * As a convenience, return the WAL location of the restore point record
+        */
+       snprintf(location, sizeof(location), "%X/%X",
+                        restorepoint.xlogid, restorepoint.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(location));
+}
+
+/*
+ * Report the current WAL write location (same format as pg_start_backup etc)
+ *
+ * This is useful for determining how much of WAL is visible to an external
+ * archiving process.  Note that the data before this point is written out
+ * to the kernel, but is not necessarily synced to disk.
+ */
+Datum
+pg_current_xlog_location(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      current_recptr;
+       char            location[MAXFNAMELEN];
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is in progress"),
+                                errhint("WAL control functions cannot be executed during recovery.")));
+
+       current_recptr = GetXLogWriteRecPtr();
+
+       snprintf(location, sizeof(location), "%X/%X",
+                        current_recptr.xlogid, current_recptr.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(location));
+}
+
+/*
+ * Report the current WAL insert location (same format as pg_start_backup etc)
+ *
+ * This function is mostly for debugging purposes.
+ */
+Datum
+pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      current_recptr;
+       char            location[MAXFNAMELEN];
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is in progress"),
+                                errhint("WAL control functions cannot be executed during recovery.")));
+
+       current_recptr = GetXLogInsertRecPtr(true);
+
+       snprintf(location, sizeof(location), "%X/%X",
+                        current_recptr.xlogid, current_recptr.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(location));
+}
+
+/*
+ * 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.
+ */
+Datum
+pg_last_xlog_receive_location(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      recptr;
+       char            location[MAXFNAMELEN];
+
+       recptr = GetWalRcvWriteRecPtr(NULL);
+
+       if (recptr.xlogid == 0 && recptr.xrecoff == 0)
+               PG_RETURN_NULL();
+
+       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.
+ */
+Datum
+pg_last_xlog_replay_location(PG_FUNCTION_ARGS)
+{
+       XLogRecPtr      recptr;
+       char            location[MAXFNAMELEN];
+
+       recptr = GetXLogReplayRecPtr(NULL);
+
+       if (recptr.xlogid == 0 && recptr.xrecoff == 0)
+               PG_RETURN_NULL();
+
+       snprintf(location, sizeof(location), "%X/%X",
+                        recptr.xlogid, recptr.xrecoff);
+       PG_RETURN_TEXT_P(cstring_to_text(location));
+}
+
+/*
+ * 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().
+ *
+ * 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.
+ */
+Datum
+pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
+{
+       text       *location = PG_GETARG_TEXT_P(0);
+       char       *locationstr;
+       unsigned int uxlogid;
+       unsigned int uxrecoff;
+       uint32          xlogid;
+       uint32          xlogseg;
+       uint32          xrecoff;
+       XLogRecPtr      locationpoint;
+       char            xlogfilename[MAXFNAMELEN];
+       Datum           values[2];
+       bool            isnull[2];
+       TupleDesc       resultTupleDesc;
+       HeapTuple       resultHeapTuple;
+       Datum           result;
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is in progress"),
+                                errhint("pg_xlogfile_name_offset() cannot be executed during recovery.")));
+
+       /*
+        * Read input and parse
+        */
+       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\"",
+                                               locationstr)));
+
+       locationpoint.xlogid = uxlogid;
+       locationpoint.xrecoff = uxrecoff;
+
+       /*
+        * Construct a tuple descriptor for the result row.  This must match this
+        * function's pg_proc entry!
+        */
+       resultTupleDesc = CreateTemplateTupleDesc(2, false);
+       TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
+                                          TEXTOID, -1, 0);
+       TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
+                                          INT4OID, -1, 0);
+
+       resultTupleDesc = BlessTupleDesc(resultTupleDesc);
+
+       /*
+        * xlogfilename
+        */
+       XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
+       XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
+
+       values[0] = CStringGetTextDatum(xlogfilename);
+       isnull[0] = false;
+
+       /*
+        * offset
+        */
+       xrecoff = locationpoint.xrecoff - xlogseg * XLogSegSize;
+
+       values[1] = UInt32GetDatum(xrecoff);
+       isnull[1] = false;
+
+       /*
+        * Tuple jam: Having first prepared your Datums, then squash together
+        */
+       resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
+
+       result = HeapTupleGetDatum(resultHeapTuple);
+
+       PG_RETURN_DATUM(result);
+}
+
+/*
+ * 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];
+
+       if (RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is in progress"),
+                errhint("pg_xlogfile_name() cannot be executed during recovery.")));
+
+       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\"",
+                                               locationstr)));
+
+       locationpoint.xlogid = uxlogid;
+       locationpoint.xrecoff = uxrecoff;
+
+       XLByteToPrevSeg(locationpoint, xlogid, xlogseg);
+       XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg);
+
+       PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
+}
+
+/*
+ * pg_xlog_replay_pause - pause recovery now
+ */
+Datum
+pg_xlog_replay_pause(PG_FUNCTION_ARGS)
+{
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("must be superuser to control recovery"))));
+
+       if (!RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is not in progress"),
+                                errhint("Recovery control functions can only be executed during recovery.")));
+
+       SetRecoveryPause(true);
+
+       PG_RETURN_VOID();
+}
+
+/*
+ * pg_xlog_replay_resume - resume recovery now
+ */
+Datum
+pg_xlog_replay_resume(PG_FUNCTION_ARGS)
+{
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("must be superuser to control recovery"))));
+
+       if (!RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is not in progress"),
+                                errhint("Recovery control functions can only be executed during recovery.")));
+
+       SetRecoveryPause(false);
+
+       PG_RETURN_VOID();
+}
+
+/*
+ * pg_is_xlog_replay_paused
+ */
+Datum
+pg_is_xlog_replay_paused(PG_FUNCTION_ARGS)
+{
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                (errmsg("must be superuser to control recovery"))));
+
+       if (!RecoveryInProgress())
+               ereport(ERROR,
+                               (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("recovery is not in progress"),
+                                errhint("Recovery control functions can only be executed during recovery.")));
+
+       PG_RETURN_BOOL(RecoveryIsPaused());
+}
+
+/*
+ * Returns timestamp of latest processed commit/abort record.
+ *
+ * When the server has been started normally without recovery the function
+ * returns NULL.
+ */
+Datum
+pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
+{
+       TimestampTz xtime;
+
+       xtime = GetLatestXTime();
+       if (xtime == 0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_TIMESTAMPTZ(xtime);
+}
+
+/*
+ * Returns bool with current recovery mode, a global state.
+ */
+Datum
+pg_is_in_recovery(PG_FUNCTION_ARGS)
+{
+       PG_RETURN_BOOL(RecoveryInProgress());
+}
index 6c7b0216730f4aedc71b4f49898e1cda07b0492c..83106b80e4ec4b11b62a980673a73588b0b763dd 100644 (file)
@@ -293,6 +293,11 @@ extern bool XLogInsertAllowed(void);
 extern void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream);
 extern XLogRecPtr GetXLogReplayRecPtr(XLogRecPtr *restoreLastRecPtr);
 extern XLogRecPtr GetStandbyFlushRecPtr(void);
+extern XLogRecPtr GetXLogInsertRecPtr(bool needlock);
+extern XLogRecPtr GetXLogWriteRecPtr(void);
+extern bool RecoveryIsPaused(void);
+extern void SetRecoveryPause(bool recoveryPause);
+extern TimestampTz GetLatestXTime(void);
 
 extern void UpdateControlFile(void);
 extern uint64 GetSystemIdentifier(void);