/* * pgespresso_stop_backup: finish taking an on-line backup dump * * Only parameter is the labelfile returned from pg_start_concurrent_backup * * Return is the XLOG filename containing end of backup location, combining * both the TLI and the end location. NOTE: the user is responsible for * ensuring that the last file is correctly archived. */ Datum pgespresso_stop_backup(PG_FUNCTION_ARGS) { XLogRecPtr stoppoint; text *labelfile = PG_GETARG_TEXT_P(0); char *backupidstr; char xlogfilename[MAXFNAMELEN]; backupidstr = text_to_cstring(labelfile); if (!superuser() && !has_rolreplication(GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser or replication role to run a backup")))); #if PG_VERSION_NUM >= 90300 { XLogSegNo xlogsegno; TimeLineID endtli; stoppoint = do_pg_stop_backup(backupidstr, false, /* don't wait for archive */ &endtli); XLByteToPrevSeg(stoppoint, xlogsegno); XLogFileName(xlogfilename, endtli, xlogsegno); } #else { uint32 xlogid; uint32 xlogseg; stoppoint = do_pg_stop_backup(backupidstr, false); /* don't wait for archive */ /* * In 9.2 the do_pg_stop_backup doesn't return the timeline ID and * ThisTimeLineID is always 0 in a normal backend during recovery. * We get latest redo apply position timeline and we update it globally */ if (RecoveryInProgress()) { TimeLineID replayTLI; GetXLogReplayRecPtr(&replayTLI); ThisTimeLineID = replayTLI; elog(DEBUG1, "updated ThisTimeLineID = %u", ThisTimeLineID); } XLByteToPrevSeg(stoppoint, xlogid, xlogseg); XLogFileName(xlogfilename, ThisTimeLineID, xlogid, xlogseg); } #endif PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); }
/* * 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_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; if (!superuser() && !has_rolreplication(GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errmsg("must be superuser or replication role to run a backup")))); stoppoint = do_pg_stop_backup(NULL, true, NULL); PG_RETURN_LSN(stoppoint); }
/* * 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. * * Note: this version is only called to stop an exclusive backup. The function * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to * stop non-exclusive backups. * * Permission checking for this function is managed through the normal * GRANT system. */ Datum pg_stop_backup(PG_FUNCTION_ARGS) { XLogRecPtr stoppoint; if (nonexclusive_backup_running) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("non-exclusive backup in progress"), errhint("did you mean to use pg_stop_backup('f')?"))); /* * Exclusive backups were typically started in a different connection, * so don't try to verify that exclusive_backup_running is set in this one. * Actual verification that an exclusive backup is in fact running is handled * inside do_pg_stop_backup. */ stoppoint = do_pg_stop_backup(NULL, true, NULL); exclusive_backup_running = false; PG_RETURN_LSN(stoppoint); }
* If we're including WAL, and this is the main data directory we * don't terminate the tar stream here. Instead, we will append * the xlog files below and terminate it then. This is safe since * the main data directory is always sent *last*. */ if (opt->includewal && ti->path == NULL) { Assert(lnext(lc) == NULL); } else pq_putemptymessage('c'); /* CopyDone */ } } PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0); endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli); if (opt->includewal) { /* * We've left the last tar file "open", so we can now append the * required WAL files to it. */ char pathbuf[MAXPGPATH]; XLogSegNo segno; XLogSegNo startsegno; XLogSegNo endsegno; struct stat statbuf; List *historyFileList = NIL; List *walFileList = NIL; char **walFiles;
* If we're including WAL, and this is the main data directory we * don't terminate the tar stream here. Instead, we will append * the xlog files below and terminate it then. This is safe since * the main data directory is always sent *last*. */ if (opt->includewal && fi->xlogdir) { Assert(lnext(lc) == NULL); } else pq_putemptymessage('c'); /* CopyDone */ } } PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0); endptr = do_pg_stop_backup(labelfile); if (opt->includewal) { /* * We've left the last tar file "open", so we can now append the * required WAL files to it. */ uint32 logid, logseg; uint32 endlogid, endlogseg; struct stat statbuf; MemSet(&statbuf, 0, sizeof(statbuf)); statbuf.st_mode = S_IRUSR | S_IWUSR;
/* * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup. * * Works the same as pg_stop_backup, except for non-exclusive backups it returns * the backup label and tablespace map files as text fields in as part of the * resultset. * * Permission checking for this function is managed through the normal * GRANT system. */ Datum pg_stop_backup_v2(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; Datum values[3]; bool nulls[3]; bool exclusive = PG_GETARG_BOOL(0); XLogRecPtr stoppoint; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); if (exclusive) { if (nonexclusive_backup_running) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("non-exclusive backup in progress"), errhint("did you mean to use pg_stop_backup('f')?"))); /* * Stop the exclusive backup, and since we're in an exclusive backup * return NULL for both backup_label and tablespace_map. */ stoppoint = do_pg_stop_backup(NULL, true, NULL); exclusive_backup_running = false; nulls[1] = true; nulls[2] = true; } else { if (!nonexclusive_backup_running) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("non-exclusive backup is not in progress"), errhint("did you mean to use pg_stop_backup('t')?"))); /* * Stop the non-exclusive backup. Return a copy of the backup * label and tablespace map so they can be written to disk by * the caller. */ stoppoint = do_pg_stop_backup(label_file->data, true, NULL); nonexclusive_backup_running = false; cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0); values[1] = CStringGetTextDatum(label_file->data); values[2] = CStringGetTextDatum(tblspc_map_file->data); /* Free structures allocated in TopMemoryContext */ pfree(label_file->data); pfree(label_file); label_file = NULL; pfree(tblspc_map_file->data); pfree(tblspc_map_file); tblspc_map_file = NULL; } /* Stoppoint is included on both exclusive and nonexclusive backups */ values[0] = LSNGetDatum(stoppoint); tuplestore_putvalues(tupstore, tupdesc, values, nulls); tuplestore_donestoring(typstore); return (Datum) 0; }
/* * Actually do a base backup for the specified tablespaces. * * This is split out mainly to avoid complaints about "variable might be * clobbered by longjmp" from stupider versions of gcc. */ static void perform_base_backup(basebackup_options *opt) { TimeLineID starttli; XLogRecPtr endptr; TimeLineID endtli; StringInfo labelfile; StringInfo tblspc_map_file = NULL; int datadirpathlen; List *tablespaces = NIL; datadirpathlen = strlen(DataDir); backup_started_in_recovery = RecoveryInProgress(); labelfile = makeStringInfo(); tblspc_map_file = makeStringInfo(); total_checksum_failures = 0; startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli, labelfile, &tablespaces, tblspc_map_file, opt->progress, opt->sendtblspcmapfile); /* * Once do_pg_start_backup has been called, ensure that any failure causes * us to abort the backup so we don't "leak" a backup counter. For this * reason, *all* functionality between do_pg_start_backup() and * the end of do_pg_stop_backup() should be inside the error cleanup block! */ PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0); { ListCell *lc; tablespaceinfo *ti; SendXlogRecPtrResult(startptr, starttli); /* * Calculate the relative path of temporary statistics directory in * order to skip the files which are located in that directory later. */ if (is_absolute_path(pgstat_stat_directory) && strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0) statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1); else if (strncmp(pgstat_stat_directory, "./", 2) != 0) statrelpath = psprintf("./%s", pgstat_stat_directory); else statrelpath = pgstat_stat_directory; /* Add a node for the base directory at the end */ ti = palloc0(sizeof(tablespaceinfo)); ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1; tablespaces = lappend(tablespaces, ti); /* Send tablespace header */ SendBackupHeader(tablespaces); /* Setup and activate network throttling, if client requested it */ if (opt->maxrate > 0) { throttling_sample = (int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY; /* * The minimum amount of time for throttling_sample bytes to be * transferred. */ elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY; /* Enable throttling. */ throttling_counter = 0; /* The 'real data' starts now (header was ignored). */ throttled_last = GetCurrentTimestamp(); } else { /* Disable throttling. */ throttling_counter = -1; } /* Send off our tablespaces one by one */ foreach(lc, tablespaces) { tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc); StringInfoData buf; /* Send CopyOutResponse message */ pq_beginmessage(&buf, 'H'); pq_sendbyte(&buf, 0); /* overall format */ pq_sendint16(&buf, 0); /* natts */ pq_endmessage(&buf); if (ti->path == NULL) { struct stat statbuf; /* In the main tar, include the backup_label first... */ sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data); /* * Send tablespace_map file if required and then the bulk of * the files. */ if (tblspc_map_file && opt->sendtblspcmapfile) { sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data); sendDir(".", 1, false, tablespaces, false); } else sendDir(".", 1, false, tablespaces, true); /* ... and pg_control after everything else. */ if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not stat control file \"%s\": %m", XLOG_CONTROL_FILE))); sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false); } else sendTablespace(ti->path, false); /* * If we're including WAL, and this is the main data directory we * don't terminate the tar stream here. Instead, we will append * the xlog files below and terminate it then. This is safe since * the main data directory is always sent *last*. */ if (opt->includewal && ti->path == NULL) { Assert(lnext(lc) == NULL); } else pq_putemptymessage('c'); /* CopyDone */ } endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli); }