Header And Logo

PostgreSQL
| The world's most advanced open source database.

xlogfuncs.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * xlogfuncs.c
00004  *
00005  * PostgreSQL transaction log manager user interface functions
00006  *
00007  * This file contains WAL control and information functions.
00008  *
00009  *
00010  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00011  * Portions Copyright (c) 1994, Regents of the University of California
00012  *
00013  * src/backend/access/transam/xlogfuncs.c
00014  *
00015  *-------------------------------------------------------------------------
00016  */
00017 #include "postgres.h"
00018 
00019 #include "access/htup_details.h"
00020 #include "access/xlog.h"
00021 #include "access/xlog_fn.h"
00022 #include "access/xlog_internal.h"
00023 #include "access/xlogutils.h"
00024 #include "catalog/catalog.h"
00025 #include "catalog/pg_type.h"
00026 #include "funcapi.h"
00027 #include "miscadmin.h"
00028 #include "replication/walreceiver.h"
00029 #include "storage/smgr.h"
00030 #include "utils/builtins.h"
00031 #include "utils/numeric.h"
00032 #include "utils/guc.h"
00033 #include "utils/timestamp.h"
00034 #include "storage/fd.h"
00035 
00036 static void validate_xlog_location(char *str);
00037 
00038 
00039 /*
00040  * pg_start_backup: set up for taking an on-line backup dump
00041  *
00042  * Essentially what this does is to create a backup label file in $PGDATA,
00043  * where it will be archived as part of the backup dump.  The label file
00044  * contains the user-supplied label string (typically this would be used
00045  * to tell where the backup dump will be stored) and the starting time and
00046  * starting WAL location for the dump.
00047  */
00048 Datum
00049 pg_start_backup(PG_FUNCTION_ARGS)
00050 {
00051     text       *backupid = PG_GETARG_TEXT_P(0);
00052     bool        fast = PG_GETARG_BOOL(1);
00053     char       *backupidstr;
00054     XLogRecPtr  startpoint;
00055     char        startxlogstr[MAXFNAMELEN];
00056 
00057     backupidstr = text_to_cstring(backupid);
00058 
00059     startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL);
00060 
00061     snprintf(startxlogstr, sizeof(startxlogstr), "%X/%X",
00062              (uint32) (startpoint >> 32), (uint32) startpoint);
00063     PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
00064 }
00065 
00066 /*
00067  * pg_stop_backup: finish taking an on-line backup dump
00068  *
00069  * We write an end-of-backup WAL record, and remove the backup label file
00070  * created by pg_start_backup, creating a backup history file in pg_xlog
00071  * instead (whence it will immediately be archived). The backup history file
00072  * contains the same info found in the label file, plus the backup-end time
00073  * and WAL location. Before 9.0, the backup-end time was read from the backup
00074  * history file at the beginning of archive recovery, but we now use the WAL
00075  * record for that and the file is for informational and debug purposes only.
00076  *
00077  * Note: different from CancelBackup which just cancels online backup mode.
00078  */
00079 Datum
00080 pg_stop_backup(PG_FUNCTION_ARGS)
00081 {
00082     XLogRecPtr  stoppoint;
00083     char        stopxlogstr[MAXFNAMELEN];
00084 
00085     stoppoint = do_pg_stop_backup(NULL, true, NULL);
00086 
00087     snprintf(stopxlogstr, sizeof(stopxlogstr), "%X/%X",
00088              (uint32) (stoppoint >> 32), (uint32) stoppoint);
00089     PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
00090 }
00091 
00092 /*
00093  * pg_switch_xlog: switch to next xlog file
00094  */
00095 Datum
00096 pg_switch_xlog(PG_FUNCTION_ARGS)
00097 {
00098     XLogRecPtr  switchpoint;
00099     char        location[MAXFNAMELEN];
00100 
00101     if (!superuser())
00102         ereport(ERROR,
00103                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00104              (errmsg("must be superuser to switch transaction log files"))));
00105 
00106     if (RecoveryInProgress())
00107         ereport(ERROR,
00108                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00109                  errmsg("recovery is in progress"),
00110                  errhint("WAL control functions cannot be executed during recovery.")));
00111 
00112     switchpoint = RequestXLogSwitch();
00113 
00114     /*
00115      * As a convenience, return the WAL location of the switch record
00116      */
00117     snprintf(location, sizeof(location), "%X/%X",
00118              (uint32) (switchpoint >> 32), (uint32) switchpoint);
00119     PG_RETURN_TEXT_P(cstring_to_text(location));
00120 }
00121 
00122 /*
00123  * pg_create_restore_point: a named point for restore
00124  */
00125 Datum
00126 pg_create_restore_point(PG_FUNCTION_ARGS)
00127 {
00128     text       *restore_name = PG_GETARG_TEXT_P(0);
00129     char       *restore_name_str;
00130     XLogRecPtr  restorepoint;
00131     char        location[MAXFNAMELEN];
00132 
00133     if (!superuser())
00134         ereport(ERROR,
00135                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00136                  (errmsg("must be superuser to create a restore point"))));
00137 
00138     if (RecoveryInProgress())
00139         ereport(ERROR,
00140                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00141                  (errmsg("recovery is in progress"),
00142                   errhint("WAL control functions cannot be executed during recovery."))));
00143 
00144     if (!XLogIsNeeded())
00145         ereport(ERROR,
00146                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00147              errmsg("WAL level not sufficient for creating a restore point"),
00148                  errhint("wal_level must be set to \"archive\" or \"hot_standby\" at server start.")));
00149 
00150     restore_name_str = text_to_cstring(restore_name);
00151 
00152     if (strlen(restore_name_str) >= MAXFNAMELEN)
00153         ereport(ERROR,
00154                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00155                  errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
00156 
00157     restorepoint = XLogRestorePoint(restore_name_str);
00158 
00159     /*
00160      * As a convenience, return the WAL location of the restore point record
00161      */
00162     snprintf(location, sizeof(location), "%X/%X",
00163              (uint32) (restorepoint >> 32), (uint32) restorepoint);
00164     PG_RETURN_TEXT_P(cstring_to_text(location));
00165 }
00166 
00167 /*
00168  * Report the current WAL write location (same format as pg_start_backup etc)
00169  *
00170  * This is useful for determining how much of WAL is visible to an external
00171  * archiving process.  Note that the data before this point is written out
00172  * to the kernel, but is not necessarily synced to disk.
00173  */
00174 Datum
00175 pg_current_xlog_location(PG_FUNCTION_ARGS)
00176 {
00177     XLogRecPtr  current_recptr;
00178     char        location[MAXFNAMELEN];
00179 
00180     if (RecoveryInProgress())
00181         ereport(ERROR,
00182                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00183                  errmsg("recovery is in progress"),
00184                  errhint("WAL control functions cannot be executed during recovery.")));
00185 
00186     current_recptr = GetXLogWriteRecPtr();
00187 
00188     snprintf(location, sizeof(location), "%X/%X",
00189              (uint32) (current_recptr >> 32), (uint32) current_recptr);
00190     PG_RETURN_TEXT_P(cstring_to_text(location));
00191 }
00192 
00193 /*
00194  * Report the current WAL insert location (same format as pg_start_backup etc)
00195  *
00196  * This function is mostly for debugging purposes.
00197  */
00198 Datum
00199 pg_current_xlog_insert_location(PG_FUNCTION_ARGS)
00200 {
00201     XLogRecPtr  current_recptr;
00202     char        location[MAXFNAMELEN];
00203 
00204     if (RecoveryInProgress())
00205         ereport(ERROR,
00206                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00207                  errmsg("recovery is in progress"),
00208                  errhint("WAL control functions cannot be executed during recovery.")));
00209 
00210     current_recptr = GetXLogInsertRecPtr();
00211 
00212     snprintf(location, sizeof(location), "%X/%X",
00213              (uint32) (current_recptr >> 32), (uint32) current_recptr);
00214     PG_RETURN_TEXT_P(cstring_to_text(location));
00215 }
00216 
00217 /*
00218  * Report the last WAL receive location (same format as pg_start_backup etc)
00219  *
00220  * This is useful for determining how much of WAL is guaranteed to be received
00221  * and synced to disk by walreceiver.
00222  */
00223 Datum
00224 pg_last_xlog_receive_location(PG_FUNCTION_ARGS)
00225 {
00226     XLogRecPtr  recptr;
00227     char        location[MAXFNAMELEN];
00228 
00229     recptr = GetWalRcvWriteRecPtr(NULL, NULL);
00230 
00231     if (recptr == 0)
00232         PG_RETURN_NULL();
00233 
00234     snprintf(location, sizeof(location), "%X/%X",
00235              (uint32) (recptr >> 32), (uint32) recptr);
00236     PG_RETURN_TEXT_P(cstring_to_text(location));
00237 }
00238 
00239 /*
00240  * Report the last WAL replay location (same format as pg_start_backup etc)
00241  *
00242  * This is useful for determining how much of WAL is visible to read-only
00243  * connections during recovery.
00244  */
00245 Datum
00246 pg_last_xlog_replay_location(PG_FUNCTION_ARGS)
00247 {
00248     XLogRecPtr  recptr;
00249     char        location[MAXFNAMELEN];
00250 
00251     recptr = GetXLogReplayRecPtr(NULL);
00252 
00253     if (recptr == 0)
00254         PG_RETURN_NULL();
00255 
00256     snprintf(location, sizeof(location), "%X/%X",
00257              (uint32) (recptr >> 32), (uint32) recptr);
00258     PG_RETURN_TEXT_P(cstring_to_text(location));
00259 }
00260 
00261 /*
00262  * Compute an xlog file name and decimal byte offset given a WAL location,
00263  * such as is returned by pg_stop_backup() or pg_xlog_switch().
00264  *
00265  * Note that a location exactly at a segment boundary is taken to be in
00266  * the previous segment.  This is usually the right thing, since the
00267  * expected usage is to determine which xlog file(s) are ready to archive.
00268  */
00269 Datum
00270 pg_xlogfile_name_offset(PG_FUNCTION_ARGS)
00271 {
00272     text       *location = PG_GETARG_TEXT_P(0);
00273     char       *locationstr;
00274     uint32      hi,
00275                 lo;
00276     XLogSegNo   xlogsegno;
00277     uint32      xrecoff;
00278     XLogRecPtr  locationpoint;
00279     char        xlogfilename[MAXFNAMELEN];
00280     Datum       values[2];
00281     bool        isnull[2];
00282     TupleDesc   resultTupleDesc;
00283     HeapTuple   resultHeapTuple;
00284     Datum       result;
00285 
00286     if (RecoveryInProgress())
00287         ereport(ERROR,
00288                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00289                  errmsg("recovery is in progress"),
00290                  errhint("pg_xlogfile_name_offset() cannot be executed during recovery.")));
00291 
00292     /*
00293      * Read input and parse
00294      */
00295     locationstr = text_to_cstring(location);
00296 
00297     validate_xlog_location(locationstr);
00298 
00299     if (sscanf(locationstr, "%X/%X", &hi, &lo) != 2)
00300         ereport(ERROR,
00301                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00302                  errmsg("could not parse transaction log location \"%s\"",
00303                         locationstr)));
00304     locationpoint = ((uint64) hi) << 32 | lo;
00305 
00306     /*
00307      * Construct a tuple descriptor for the result row.  This must match this
00308      * function's pg_proc entry!
00309      */
00310     resultTupleDesc = CreateTemplateTupleDesc(2, false);
00311     TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
00312                        TEXTOID, -1, 0);
00313     TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
00314                        INT4OID, -1, 0);
00315 
00316     resultTupleDesc = BlessTupleDesc(resultTupleDesc);
00317 
00318     /*
00319      * xlogfilename
00320      */
00321     XLByteToPrevSeg(locationpoint, xlogsegno);
00322     XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
00323 
00324     values[0] = CStringGetTextDatum(xlogfilename);
00325     isnull[0] = false;
00326 
00327     /*
00328      * offset
00329      */
00330     xrecoff = locationpoint % XLogSegSize;
00331 
00332     values[1] = UInt32GetDatum(xrecoff);
00333     isnull[1] = false;
00334 
00335     /*
00336      * Tuple jam: Having first prepared your Datums, then squash together
00337      */
00338     resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
00339 
00340     result = HeapTupleGetDatum(resultHeapTuple);
00341 
00342     PG_RETURN_DATUM(result);
00343 }
00344 
00345 /*
00346  * Compute an xlog file name given a WAL location,
00347  * such as is returned by pg_stop_backup() or pg_xlog_switch().
00348  */
00349 Datum
00350 pg_xlogfile_name(PG_FUNCTION_ARGS)
00351 {
00352     text       *location = PG_GETARG_TEXT_P(0);
00353     char       *locationstr;
00354     uint32      hi,
00355                 lo;
00356     XLogSegNo   xlogsegno;
00357     XLogRecPtr  locationpoint;
00358     char        xlogfilename[MAXFNAMELEN];
00359 
00360     if (RecoveryInProgress())
00361         ereport(ERROR,
00362                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00363                  errmsg("recovery is in progress"),
00364          errhint("pg_xlogfile_name() cannot be executed during recovery.")));
00365 
00366     locationstr = text_to_cstring(location);
00367 
00368     validate_xlog_location(locationstr);
00369 
00370     if (sscanf(locationstr, "%X/%X", &hi, &lo) != 2)
00371         ereport(ERROR,
00372                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00373                  errmsg("could not parse transaction log location \"%s\"",
00374                         locationstr)));
00375     locationpoint = ((uint64) hi) << 32 | lo;
00376 
00377     XLByteToPrevSeg(locationpoint, xlogsegno);
00378     XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
00379 
00380     PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
00381 }
00382 
00383 /*
00384  * pg_xlog_replay_pause - pause recovery now
00385  */
00386 Datum
00387 pg_xlog_replay_pause(PG_FUNCTION_ARGS)
00388 {
00389     if (!superuser())
00390         ereport(ERROR,
00391                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00392                  (errmsg("must be superuser to control recovery"))));
00393 
00394     if (!RecoveryInProgress())
00395         ereport(ERROR,
00396                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00397                  errmsg("recovery is not in progress"),
00398                  errhint("Recovery control functions can only be executed during recovery.")));
00399 
00400     SetRecoveryPause(true);
00401 
00402     PG_RETURN_VOID();
00403 }
00404 
00405 /*
00406  * pg_xlog_replay_resume - resume recovery now
00407  */
00408 Datum
00409 pg_xlog_replay_resume(PG_FUNCTION_ARGS)
00410 {
00411     if (!superuser())
00412         ereport(ERROR,
00413                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00414                  (errmsg("must be superuser to control recovery"))));
00415 
00416     if (!RecoveryInProgress())
00417         ereport(ERROR,
00418                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00419                  errmsg("recovery is not in progress"),
00420                  errhint("Recovery control functions can only be executed during recovery.")));
00421 
00422     SetRecoveryPause(false);
00423 
00424     PG_RETURN_VOID();
00425 }
00426 
00427 /*
00428  * pg_is_xlog_replay_paused
00429  */
00430 Datum
00431 pg_is_xlog_replay_paused(PG_FUNCTION_ARGS)
00432 {
00433     if (!superuser())
00434         ereport(ERROR,
00435                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00436                  (errmsg("must be superuser to control recovery"))));
00437 
00438     if (!RecoveryInProgress())
00439         ereport(ERROR,
00440                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00441                  errmsg("recovery is not in progress"),
00442                  errhint("Recovery control functions can only be executed during recovery.")));
00443 
00444     PG_RETURN_BOOL(RecoveryIsPaused());
00445 }
00446 
00447 /*
00448  * Returns timestamp of latest processed commit/abort record.
00449  *
00450  * When the server has been started normally without recovery the function
00451  * returns NULL.
00452  */
00453 Datum
00454 pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
00455 {
00456     TimestampTz xtime;
00457 
00458     xtime = GetLatestXTime();
00459     if (xtime == 0)
00460         PG_RETURN_NULL();
00461 
00462     PG_RETURN_TIMESTAMPTZ(xtime);
00463 }
00464 
00465 /*
00466  * Returns bool with current recovery mode, a global state.
00467  */
00468 Datum
00469 pg_is_in_recovery(PG_FUNCTION_ARGS)
00470 {
00471     PG_RETURN_BOOL(RecoveryInProgress());
00472 }
00473 
00474 /*
00475  * Validate the text form of a transaction log location.
00476  * (Just using sscanf() input allows incorrect values such as
00477  * negatives, so we have to be a bit more careful about that).
00478  */
00479 static void
00480 validate_xlog_location(char *str)
00481 {
00482 #define MAXLSNCOMPONENT     8
00483 
00484     int         len1,
00485                 len2;
00486 
00487     len1 = strspn(str, "0123456789abcdefABCDEF");
00488     if (len1 < 1 || len1 > MAXLSNCOMPONENT || str[len1] != '/')
00489         ereport(ERROR,
00490                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00491                  errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
00492 
00493     len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF");
00494     if (len2 < 1 || len2 > MAXLSNCOMPONENT || str[len1 + 1 + len2] != '\0')
00495         ereport(ERROR,
00496                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00497                  errmsg("invalid input syntax for transaction log location: \"%s\"", str)));
00498 }
00499 
00500 /*
00501  * Compute the difference in bytes between two WAL locations.
00502  */
00503 Datum
00504 pg_xlog_location_diff(PG_FUNCTION_ARGS)
00505 {
00506     text       *location1 = PG_GETARG_TEXT_P(0);
00507     text       *location2 = PG_GETARG_TEXT_P(1);
00508     char       *str1,
00509                *str2;
00510     XLogRecPtr  loc1,
00511                 loc2;
00512     Numeric     result;
00513     uint64      bytes1,
00514                 bytes2;
00515     uint32      hi,
00516                 lo;
00517 
00518     /*
00519      * Read and parse input
00520      */
00521     str1 = text_to_cstring(location1);
00522     str2 = text_to_cstring(location2);
00523 
00524     validate_xlog_location(str1);
00525     validate_xlog_location(str2);
00526 
00527     if (sscanf(str1, "%X/%X", &hi, &lo) != 2)
00528         ereport(ERROR,
00529                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00530            errmsg("could not parse transaction log location \"%s\"", str1)));
00531     loc1 = ((uint64) hi) << 32 | lo;
00532 
00533     if (sscanf(str2, "%X/%X", &hi, &lo) != 2)
00534         ereport(ERROR,
00535                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00536            errmsg("could not parse transaction log location \"%s\"", str2)));
00537     loc2 = ((uint64) hi) << 32 | lo;
00538 
00539     bytes1 = (uint64) loc1;
00540     bytes2 = (uint64) loc2;
00541 
00542     /*
00543      * result = bytes1 - bytes2.
00544      *
00545      * XXX: this won't handle values higher than 2^63 correctly.
00546      */
00547     result = DatumGetNumeric(DirectFunctionCall2(numeric_sub,
00548        DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) bytes1)),
00549        DirectFunctionCall1(int8_numeric, Int64GetDatum((int64) bytes2))));
00550 
00551     PG_RETURN_NUMERIC(result);
00552 }
00553 
00554 /*
00555  * Returns bool with current on-line backup mode, a global state.
00556  */
00557 Datum
00558 pg_is_in_backup(PG_FUNCTION_ARGS)
00559 {
00560     PG_RETURN_BOOL(BackupInProgress());
00561 }
00562 
00563 /*
00564  * Returns start time of an online exclusive backup.
00565  *
00566  * When there's no exclusive backup in progress, the function
00567  * returns NULL.
00568  */
00569 Datum
00570 pg_backup_start_time(PG_FUNCTION_ARGS)
00571 {
00572     Datum       xtime;
00573     FILE       *lfp;
00574     char        fline[MAXPGPATH];
00575     char        backup_start_time[30];
00576 
00577     /*
00578      * See if label file is present
00579      */
00580     lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
00581     if (lfp == NULL)
00582     {
00583         if (errno != ENOENT)
00584             ereport(ERROR,
00585                     (errcode_for_file_access(),
00586                      errmsg("could not read file \"%s\": %m",
00587                         BACKUP_LABEL_FILE)));
00588         PG_RETURN_NULL();
00589     }
00590 
00591     /*
00592      * Parse the file to find the the START TIME line.
00593      */
00594     backup_start_time[0] = '\0';
00595     while (fgets(fline, sizeof(fline), lfp) != NULL)
00596     {
00597         if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
00598             break;
00599     }
00600 
00601     /* Check for a read error. */
00602     if (ferror(lfp))
00603         ereport(ERROR,
00604                 (errcode_for_file_access(),
00605                  errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
00606 
00607     /* Close the backup label file. */
00608     if (FreeFile(lfp))
00609         ereport(ERROR,
00610                 (errcode_for_file_access(),
00611                  errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
00612 
00613     if (strlen(backup_start_time) == 0)
00614         ereport(ERROR,
00615                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
00616                  errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
00617 
00618     /*
00619      * Convert the time string read from file to TimestampTz form.
00620      */
00621     xtime = DirectFunctionCall3(timestamptz_in,
00622                                 CStringGetDatum(backup_start_time),
00623                                 ObjectIdGetDatum(InvalidOid),
00624                                 Int32GetDatum(-1));
00625 
00626     PG_RETURN_DATUM(xtime);
00627 }