Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * basebackup_progress.c
4 : * Basebackup sink implementing progress tracking, including but not
5 : * limited to command progress reporting.
6 : *
7 : * This should be used even if the PROGRESS option to the replication
8 : * command BASE_BACKUP is not specified. Without that option, we won't
9 : * have tallied up the size of the files that are going to need to be
10 : * backed up, but we can still report to the command progress reporting
11 : * facility how much data we've processed.
12 : *
13 : * Moreover, we also use this as a convenient place to update certain
14 : * fields of the bbsink_state. That work is accurately described as
15 : * keeping track of our progress, but it's not just for introspection.
16 : * We need those fields to be updated properly in order for base backups
17 : * to work.
18 : *
19 : * This particular basebackup sink requires extra callbacks that most base
20 : * backup sinks don't. Rather than cramming those into the interface, we just
21 : * have a few extra functions here that basebackup.c can call. (We could put
22 : * the logic directly into that file as it's fairly simple, but it seems
23 : * cleaner to have everything related to progress reporting in one place.)
24 : *
25 : * Portions Copyright (c) 2010-2023, PostgreSQL Global Development Group
26 : *
27 : * IDENTIFICATION
28 : * src/backend/backup/basebackup_progress.c
29 : *
30 : *-------------------------------------------------------------------------
31 : */
32 : #include "postgres.h"
33 :
34 : #include "backup/basebackup.h"
35 : #include "backup/basebackup_sink.h"
36 : #include "commands/progress.h"
37 : #include "miscadmin.h"
38 : #include "pgstat.h"
39 : #include "storage/latch.h"
40 : #include "utils/timestamp.h"
41 :
42 : static void bbsink_progress_begin_backup(bbsink *sink);
43 : static void bbsink_progress_archive_contents(bbsink *sink, size_t len);
44 : static void bbsink_progress_end_archive(bbsink *sink);
45 :
46 : static const bbsink_ops bbsink_progress_ops = {
47 : .begin_backup = bbsink_progress_begin_backup,
48 : .begin_archive = bbsink_forward_begin_archive,
49 : .archive_contents = bbsink_progress_archive_contents,
50 : .end_archive = bbsink_progress_end_archive,
51 : .begin_manifest = bbsink_forward_begin_manifest,
52 : .manifest_contents = bbsink_forward_manifest_contents,
53 : .end_manifest = bbsink_forward_end_manifest,
54 : .end_backup = bbsink_forward_end_backup,
55 : .cleanup = bbsink_forward_cleanup
56 : };
57 :
58 : /*
59 : * Create a new basebackup sink that performs progress tracking functions and
60 : * forwards data to a successor sink.
61 : */
62 : bbsink *
520 rhaas 63 CBC 126 : bbsink_progress_new(bbsink *next, bool estimate_backup_size)
64 : {
65 : bbsink *sink;
66 :
67 126 : Assert(next != NULL);
68 :
69 126 : sink = palloc0(sizeof(bbsink));
70 126 : *((const bbsink_ops **) &sink->bbs_ops) = &bbsink_progress_ops;
71 126 : sink->bbs_next = next;
72 :
73 : /*
74 : * Report that a base backup is in progress, and set the total size of the
75 : * backup to -1, which will get translated to NULL. If we're estimating
76 : * the backup size, we'll insert the real estimate when we have it.
77 : */
78 126 : pgstat_progress_start_command(PROGRESS_COMMAND_BASEBACKUP, InvalidOid);
79 126 : pgstat_progress_update_param(PROGRESS_BASEBACKUP_BACKUP_TOTAL, -1);
80 :
81 126 : return sink;
82 : }
83 :
84 : /*
85 : * Progress reporting at start of backup.
86 : */
87 : static void
88 126 : bbsink_progress_begin_backup(bbsink *sink)
89 : {
90 126 : const int index[] = {
91 : PROGRESS_BASEBACKUP_PHASE,
92 : PROGRESS_BASEBACKUP_BACKUP_TOTAL,
93 : PROGRESS_BASEBACKUP_TBLSPC_TOTAL
94 : };
95 : int64 val[3];
96 :
97 : /*
98 : * Report that we are now streaming database files as a base backup. Also
99 : * advertise the number of tablespaces, and, if known, the estimated total
100 : * backup size.
101 : */
102 126 : val[0] = PROGRESS_BASEBACKUP_PHASE_STREAM_BACKUP;
103 126 : if (sink->bbs_state->bytes_total_is_valid)
104 126 : val[1] = sink->bbs_state->bytes_total;
105 : else
520 rhaas 106 UBC 0 : val[1] = -1;
520 rhaas 107 CBC 126 : val[2] = list_length(sink->bbs_state->tablespaces);
108 126 : pgstat_progress_update_multi_param(3, index, val);
109 :
110 : /* Delegate to next sink. */
111 126 : bbsink_forward_begin_backup(sink);
112 126 : }
113 :
114 : /*
115 : * End-of archive progress reporting.
116 : */
117 : static void
118 136 : bbsink_progress_end_archive(bbsink *sink)
119 : {
120 : /*
121 : * We expect one archive per tablespace, so reaching the end of an archive
122 : * also means reaching the end of a tablespace. (Some day we might have a
123 : * reason to decouple these concepts.)
124 : *
125 : * If WAL is included in the backup, we'll mark the last tablespace
126 : * complete before the last archive is complete, so we need a guard here
127 : * to ensure that the number of tablespaces streamed doesn't exceed the
128 : * total.
129 : */
130 136 : if (sink->bbs_state->tablespace_num < list_length(sink->bbs_state->tablespaces))
131 136 : pgstat_progress_update_param(PROGRESS_BASEBACKUP_TBLSPC_STREAMED,
132 136 : sink->bbs_state->tablespace_num + 1);
133 :
134 : /* Delegate to next sink. */
135 136 : bbsink_forward_end_archive(sink);
136 :
137 : /*
138 : * This is a convenient place to update the bbsink_state's notion of which
139 : * is the current tablespace. Note that the bbsink_state object is shared
140 : * across all bbsink objects involved, but we're the outermost one and
141 : * this is the very last thing we do.
142 : */
143 136 : sink->bbs_state->tablespace_num++;
144 136 : }
145 :
146 : /*
147 : * Handle progress tracking for new archive contents.
148 : *
149 : * Increment the counter for the amount of data already streamed
150 : * by the given number of bytes, and update the progress report for
151 : * pg_stat_progress_basebackup.
152 : */
153 : static void
154 281059 : bbsink_progress_archive_contents(bbsink *sink, size_t len)
155 : {
156 281059 : bbsink_state *state = sink->bbs_state;
157 281059 : const int index[] = {
158 : PROGRESS_BASEBACKUP_BACKUP_STREAMED,
159 : PROGRESS_BASEBACKUP_BACKUP_TOTAL
160 : };
161 : int64 val[2];
162 281059 : int nparam = 0;
163 :
164 : /* First update bbsink_state with # of bytes done. */
165 281059 : state->bytes_done += len;
166 :
167 : /* Now forward to next sink. */
168 281059 : bbsink_forward_archive_contents(sink, len);
169 :
170 : /* Prepare to set # of bytes done for command progress reporting. */
171 281059 : val[nparam++] = state->bytes_done;
172 :
173 : /*
174 : * We may also want to update # of total bytes, to avoid overflowing past
175 : * 100% or the full size. This may make the total size number change as we
176 : * approach the end of the backup (the estimate will always be wrong if
177 : * WAL is included), but that's better than having the done column be
178 : * bigger than the total.
179 : */
180 281059 : if (state->bytes_total_is_valid && state->bytes_done > state->bytes_total)
181 10885 : val[nparam++] = state->bytes_done;
182 :
183 281059 : pgstat_progress_update_multi_param(nparam, index, val);
184 281059 : }
185 :
186 : /*
187 : * Advertise that we are waiting for the start-of-backup checkpoint.
188 : */
189 : void
190 126 : basebackup_progress_wait_checkpoint(void)
191 : {
192 126 : pgstat_progress_update_param(PROGRESS_BASEBACKUP_PHASE,
193 : PROGRESS_BASEBACKUP_PHASE_WAIT_CHECKPOINT);
194 126 : }
195 :
196 : /*
197 : * Advertise that we are estimating the backup size.
198 : */
199 : void
200 126 : basebackup_progress_estimate_backup_size(void)
201 : {
202 126 : pgstat_progress_update_param(PROGRESS_BASEBACKUP_PHASE,
203 : PROGRESS_BASEBACKUP_PHASE_ESTIMATE_BACKUP_SIZE);
204 126 : }
205 :
206 : /*
207 : * Advertise that we are waiting for WAL archiving at end-of-backup.
208 : */
209 : void
210 120 : basebackup_progress_wait_wal_archive(bbsink_state *state)
211 : {
212 120 : const int index[] = {
213 : PROGRESS_BASEBACKUP_PHASE,
214 : PROGRESS_BASEBACKUP_TBLSPC_STREAMED
215 : };
216 : int64 val[2];
217 :
218 : /*
219 : * We report having finished all tablespaces at this point, even if the
220 : * archive for the main tablespace is still open, because what's going to
221 : * be added is WAL files, not files that are really from the main
222 : * tablespace.
223 : */
224 120 : val[0] = PROGRESS_BASEBACKUP_PHASE_WAIT_WAL_ARCHIVE;
225 120 : val[1] = list_length(state->tablespaces);
226 120 : pgstat_progress_update_multi_param(2, index, val);
227 120 : }
228 :
229 : /*
230 : * Advertise that we are transferring WAL files into the final archive.
231 : */
232 : void
233 20 : basebackup_progress_transfer_wal(void)
234 : {
235 20 : pgstat_progress_update_param(PROGRESS_BASEBACKUP_PHASE,
236 : PROGRESS_BASEBACKUP_PHASE_TRANSFER_WAL);
237 20 : }
238 :
239 : /*
240 : * Advertise that we are no longer performing a backup.
241 : */
242 : void
243 117 : basebackup_progress_done(void)
244 : {
245 117 : pgstat_progress_end_command();
246 117 : }
|