1/*-------------------------------------------------------------------------
4 * send basebackup archives using COPY OUT
6 * We send a result set with information about the tablespaces to be included
7 * in the backup before starting COPY OUT. Then, we start a single COPY OUT
8 * operation and transmits all the archives and the manifest if present during
9 * the course of that single COPY OUT. Each CopyData message begins with a
10 * type byte, allowing us to signal the start of a new archive, or the
11 * manifest, by some means other than ending the COPY stream. This also allows
12 * for future protocol extensions, since we can include arbitrary information
13 * in the message stream as long as we're certain that the client will know
16 * An older method that sent each archive using a separate COPY OUT
17 * operation is no longer supported.
19 * Portions Copyright (c) 2010-2025, PostgreSQL Global Development Group
22 * src/backend/backup/basebackup_copy.c
24 *-------------------------------------------------------------------------
31#include "catalog/pg_type_d.h"
41 /* Common information for all types of sink. */
44 /* Are we sending the archives to the client, or somewhere else? */
48 * Protocol message buffer. We assemble CopyData protocol messages by
49 * setting the first character of this buffer to 'd' (archive or manifest
50 * data) and then making base.bbs_buffer point to the second character so
51 * that the rest of the data gets copied into the message just where we
57 * When did we last report progress to the client, and how much progress
65 * We don't want to send progress messages to the client excessively
66 * frequently. Ideally, we'd like to send a message when the time since the
67 * last message reaches PROGRESS_REPORT_MILLISECOND_THRESHOLD, but checking
68 * the system time every time we send a tiny bit of data seems too expensive.
69 * So we only check it after the number of bytes sine the last check reaches
70 * PROGRESS_REPORT_BYTE_INTERVAL.
72 #define PROGRESS_REPORT_BYTE_INTERVAL 65536
73 #define PROGRESS_REPORT_MILLISECOND_THRESHOLD 1000
77 const char *archive_name);
105 * Create a new 'copystream' bbsink.
115 /* Set up for periodic progress reporting. */
123 * Send start-of-backup wire protocol messages.
133 * Initialize buffer. We ultimately want to send the archive and manifest
134 * data by means of CopyData messages where the payload portion of each
135 * message begins with a type byte. However, basebackup.c expects the
136 * buffer to be aligned, so we can't just allocate one extra byte for the
137 * type byte. Instead, allocate enough extra bytes that the portion of the
138 * buffer we reveal to our callers can be aligned, while leaving room to
139 * slip the type byte in just beforehand. That will allow us to ship the
140 * data with a single call to pq_putmessage and without needing any extra
148 /* Tell client the backup start location. */
151 /* Send client a list of tablespaces. */
154 /* Send a CommandComplete message */
157 /* Begin COPY stream. This will be used for all archives + manifest. */
162 * Send a CopyData message announcing the beginning of a new archive.
180 * Send a CopyData message containing a chunk of archive content.
190 /* Send the archive content to the client, if appropriate. */
193 /* Add one because we're also sending a leading type byte. */
197 /* Consider whether to send a progress report to the client. */
200 if (targetbytes <= state->bytes_done)
206 * OK, we've sent a decent number of bytes, so check the system time
207 * to see whether we're due to send a progress report.
214 * Send a progress report if enough time has passed. Also send one if
215 * the system clock was set backward, so that such occurrences don't
216 * have the effect of suppressing further progress messages.
219 now < mysink->last_progress_report_time)
233 * We don't need to explicitly signal the end of the archive; the client
234 * will figure out that we've reached the end when we begin the next one,
235 * or begin the manifest, or end the COPY stream. However, this seems like
236 * a good time to force out a progress report. One reason for that is that
237 * if this is the last archive, and we don't force a progress report now,
238 * the client will never be told that we sent all the bytes.
257 * Send a CopyData message announcing the beginning of the backup manifest.
270 * Each chunk of manifest data is sent using a CopyData message.
279 /* Add one because we're also sending a leading type byte. */
285 * We don't need an explicit terminator for the backup manifest.
294 * Send end-of-backup wire protocol messages.
314 * Send a CopyOutResponse message.
328 * Send a CopyDone message.
337 * Send a single resultset containing just a single
338 * XLogRecPtr record (in text format)
355 * int8 may seem like a surprising data type for this, but in theory int4
356 * would not be wide enough for this, as TimeLineID is unsigned.
360 /* send RowDescription */
370 /* Send a CommandComplete message */
375 * Send a result set via libpq describing the tablespace list.
392 /* send RowDescription */
395 /* Construct and send the directory information */
396 foreach(lc, tablespaces)
402 /* Send one datarow message */
403 if (ti->
path == NULL)
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
TimestampTz GetCurrentTimestamp(void)
Datum now(PG_FUNCTION_ARGS)
static void SendCopyDone(void)
bbsink * bbsink_copystream_new(bool send_to_client)
#define PROGRESS_REPORT_MILLISECOND_THRESHOLD
#define PROGRESS_REPORT_BYTE_INTERVAL
static void bbsink_copystream_manifest_contents(bbsink *sink, size_t len)
static void bbsink_copystream_cleanup(bbsink *sink)
static void bbsink_copystream_archive_contents(bbsink *sink, size_t len)
static void bbsink_copystream_end_backup(bbsink *sink, XLogRecPtr endptr, TimeLineID endtli)
static const bbsink_ops bbsink_copystream_ops
static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
static void bbsink_copystream_end_archive(bbsink *sink)
static void SendTablespaceList(List *tablespaces)
static void SendCopyOutResponse(void)
static void bbsink_copystream_begin_manifest(bbsink *sink)
static void bbsink_copystream_begin_archive(bbsink *sink, const char *archive_name)
struct bbsink_copystream bbsink_copystream
static void bbsink_copystream_begin_backup(bbsink *sink)
static void bbsink_copystream_end_manifest(bbsink *sink)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
DestReceiver * CreateDestReceiver(CommandDest dest)
void do_tup_output(TupOutputState *tstate, const Datum *values, const bool *isnull)
const TupleTableSlotOps TTSOpsVirtual
void end_tup_output(TupOutputState *tstate)
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
#define pq_flush_if_writable()
#define pq_putmessage(msgtype, s, len)
void * palloc0(Size size)
static void * list_nth(const List *list, int n)
static Datum Int64GetDatum(int64 X)
static Datum ObjectIdGetDatum(Oid X)
#define PqMsg_CommandComplete
#define PqBackupMsg_ProgressReport
#define PqBackupMsg_NewArchive
#define PqMsg_CopyOutResponse
#define PqBackupMsg_Manifest
char * psprintf(const char *fmt,...)
TimestampTz last_progress_report_time
uint64 bytes_done_at_last_time_check
void(* begin_backup)(bbsink *sink)
const bbsink_ops * bbs_ops
TupleDesc CreateTemplateTupleDesc(int natts)
void TupleDescInitBuiltinEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
#define LSN_FORMAT_ARGS(lsn)