@@ -32,45 +32,56 @@ static void copy_file_attributes(const char *from_path,
32
32
33
33
typedef struct
34
34
{
35
- TimeLineID tli ;
36
- XLogSegNo segno ;
37
- uint32 xlog_seg_size ;
35
+ TimeLineID tli ;
36
+ uint32 xlog_seg_size ;
38
37
39
38
const char * pg_xlog_dir ;
40
39
const char * archive_dir ;
41
- bool overwrite ;
42
- bool compress ;
43
- bool no_sync ;
44
- bool no_ready_rename ;
40
+ bool overwrite ;
41
+ bool compress ;
42
+ bool no_sync ;
43
+ bool no_ready_rename ;
45
44
46
45
CompressAlg compress_alg ;
47
- int compress_level ;
48
- int thread_num ;
46
+ int compress_level ;
47
+ int thread_num ;
48
+
49
+ parray * files ;
50
+
51
+ int n_pushed_files ;
49
52
50
53
/*
51
54
* Return value from the thread.
52
55
* 0 means there is no error,
53
56
* 1 - there is an error.
54
57
* 2 - no error, but nothing to push
55
58
*/
56
- int ret ;
59
+ int ret ;
57
60
} archive_push_arg ;
58
61
62
+ typedef struct WALSegno
63
+ {
64
+ XLogSegNo segno ;
65
+ volatile pg_atomic_flag lock ;
66
+ } WALSegno ;
67
+
59
68
/*
60
69
* At this point, we already done one roundtrip to archive server
61
70
* to get instance config.
62
71
*
63
72
* pg_probackup specific archive command for archive backups
64
- * set archive_command = 'pg_probackup archive-push -B /home/anastasia/backup
65
- * --wal-file-path %p --wal-file-name %f', to move backups into arclog_path.
73
+ * set archive_command to
74
+ * 'pg_probackup archive-push -B /home/anastasia/backup --wal-file-name %f',
75
+ * to move backups into arclog_path.
66
76
* Where archlog_path is $BACKUP_PATH/wal/system_id.
67
77
* Currently it just copies wal files to the new location.
68
78
*/
69
79
int
70
80
do_archive_push (InstanceConfig * instance , char * wal_file_path ,
71
- char * wal_file_name , bool overwrite , bool no_sync , bool no_ready_rename )
81
+ char * wal_file_name , int batch_size , bool overwrite ,
82
+ bool no_sync , bool no_ready_rename )
72
83
{
73
- int i ;
84
+ uint64 i ;
74
85
char current_dir [MAXPGPATH ];
75
86
char pg_xlog_dir [MAXPGPATH ];
76
87
uint64 system_id ;
@@ -86,9 +97,11 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
86
97
bool push_isok = true;
87
98
88
99
/* reporting */
89
- int n_pushed_files = 0 ;
100
+ int total_pushed_files = 0 ;
90
101
pid_t my_pid ;
91
102
103
+ parray * files = NULL ;
104
+
92
105
my_pid = getpid ();
93
106
94
107
if (wal_file_name == NULL )
@@ -123,21 +136,28 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
123
136
124
137
/* Single-thread push
125
138
* There are two cases, when we don`t want to start multi-thread push:
126
- * - number of threads is equal to 1, multithreading isn`t cheap to start,
127
- * so creating, running and terminating one thread using generic
128
- * multithread approach can take almost as much time as copying itself.
139
+ * - batch size is equal to 1; multithreading isn`t cheap to start,
140
+ * so creating, running and terminating threads using generic
141
+ * multithread approach to copy just one file can take almost as much
142
+ * time as copying itself.
129
143
* - file to push is not WAL file, but .history, .backup or .partial file.
130
144
* we do not apply compression to such files.
131
145
*/
132
- if (num_threads == 1 || !IsXLogFileName (wal_file_name ))
146
+
147
+ if (num_threads > batch_size )
148
+ num_threads = batch_size ;
149
+
150
+ elog (INFO , "PID [%d]: pg_probackup push file %s into archive, "
151
+ "threads: %i, batch size: %i, compression: %s" ,
152
+ my_pid , wal_file_name , num_threads ,
153
+ batch_size , is_compress ? "zlib" : "none" );
154
+
155
+ if (!IsXLogFileName (wal_file_name ) || batch_size == 1 )
133
156
{
134
157
/* do not apply compression to .backup, .history and .partial files */
135
158
if (!IsXLogFileName (wal_file_name ))
136
159
is_compress = false;
137
160
138
- elog (INFO , "PID [%d]: pg_probackup push file %s into archive, threads: 1, compression: %s" ,
139
- my_pid , wal_file_name , is_compress ? "zlib" : "none" );
140
-
141
161
if (is_compress )
142
162
gz_push_wal_file_internal (wal_file_name , pg_xlog_dir ,
143
163
instance -> arclog_path , overwrite ,
@@ -147,16 +167,25 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
147
167
instance -> arclog_path , overwrite , no_sync , 1 );
148
168
149
169
push_isok = true;
150
- n_pushed_files ++ ;
170
+ total_pushed_files ++ ;
151
171
goto push_done ;
152
172
}
153
173
154
174
/* parse WAL filename */
155
175
if (IsXLogFileName (wal_file_name ))
156
176
GetXLogFromFileName (wal_file_name , & tli , & first_segno , instance -> xlog_seg_size );
157
177
158
- elog (INFO , "PID [%d]: pg_probackup push file %s into archive, threads: %i, compression: %s" ,
159
- my_pid , wal_file_name , num_threads , is_compress ? "zlib" : "none" );
178
+ files = parray_new ();
179
+ /* setup locks */
180
+ for (i = first_segno ; i < first_segno + batch_size ; i ++ )
181
+ {
182
+ WALSegno * xlogfile = palloc (sizeof (WALSegno ));
183
+
184
+ xlogfile -> segno = i ;
185
+ pg_atomic_init_flag (& xlogfile -> lock );
186
+
187
+ parray_append (files , xlogfile );
188
+ }
160
189
161
190
/* TODO: report actual executed command */
162
191
@@ -169,7 +198,6 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
169
198
archive_push_arg * arg = & (threads_args [i ]);
170
199
171
200
arg -> tli = tli ;
172
- arg -> segno = first_segno + i ;
173
201
arg -> xlog_seg_size = instance -> xlog_seg_size ;
174
202
arg -> archive_dir = instance -> arclog_path ;
175
203
arg -> pg_xlog_dir = pg_xlog_dir ;
@@ -181,6 +209,9 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
181
209
arg -> compress_alg = instance -> compress_alg ;
182
210
arg -> compress_level = instance -> compress_level ;
183
211
212
+ arg -> files = files ;
213
+ arg -> n_pushed_files = 0 ;
214
+
184
215
arg -> thread_num = i + 1 ;
185
216
/* By default there are some error */
186
217
arg -> ret = 1 ;
@@ -199,8 +230,8 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
199
230
pthread_join (threads [i ], NULL );
200
231
if (threads_args [i ].ret == 1 )
201
232
push_isok = false;
202
- else if ( threads_args [ i ]. ret == 0 )
203
- n_pushed_files ++ ;
233
+
234
+ total_pushed_files += threads_args [ i ]. n_pushed_files ;
204
235
}
205
236
206
237
/* Note, that we don`t do garbage collection here,
@@ -213,7 +244,7 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
213
244
/* report number of files pushed into archive */
214
245
elog (INFO , "PID [%d]: pg_probackup archive-push completed successfully, "
215
246
"number of pushed files: %i" ,
216
- my_pid , n_pushed_files );
247
+ my_pid , total_pushed_files );
217
248
return 0 ;
218
249
}
219
250
@@ -228,56 +259,66 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
228
259
static void *
229
260
push_wal_segno (void * arg )
230
261
{
262
+ int i ;
231
263
int rc ;
232
- char wal_filename [MAXPGPATH ];
233
- archive_push_arg * args = (archive_push_arg * ) arg ;
234
-
235
- char archive_status_dir [MAXPGPATH ];
236
- char wal_file_dummy [MAXPGPATH ];
237
- char wal_file_ready [MAXPGPATH ];
238
- char wal_file_done [MAXPGPATH ];
264
+ char wal_filename [MAXPGPATH ];
239
265
240
- /* At first we must construct WAL filename from segno, tli and xlog_seg_size */
241
- GetXLogFileName (wal_filename , args -> tli , args -> segno , args -> xlog_seg_size );
266
+ char archive_status_dir [MAXPGPATH ];
267
+ char wal_file_dummy [MAXPGPATH ];
268
+ char wal_file_ready [MAXPGPATH ];
269
+ char wal_file_done [MAXPGPATH ];
270
+ archive_push_arg * args = (archive_push_arg * ) arg ;
242
271
243
272
join_path_components (archive_status_dir , args -> pg_xlog_dir , "archive_status" );
244
- join_path_components (wal_file_dummy , archive_status_dir , wal_filename );
245
- snprintf (wal_file_ready , MAXPGPATH , "%s.%s" , wal_file_dummy , "ready" );
246
- snprintf (wal_file_done , MAXPGPATH , "%s.%s" , wal_file_dummy , "done" );
247
273
248
- /* For additional threads we must check the existence of .ready file */
249
- if (args -> thread_num != 1 )
274
+ for (i = 0 ; i < parray_num (args -> files ); i ++ )
250
275
{
276
+ WALSegno * xlogfile = (WALSegno * ) parray_get (args -> files , i );
277
+
278
+ if (!pg_atomic_test_set_flag (& xlogfile -> lock ))
279
+ continue ;
280
+
281
+ /* At first we must construct WAL filename from segno, tli and xlog_seg_size */
282
+ GetXLogFileName (wal_filename , args -> tli , xlogfile -> segno , args -> xlog_seg_size );
283
+
284
+ join_path_components (wal_file_dummy , archive_status_dir , wal_filename );
285
+ snprintf (wal_file_ready , MAXPGPATH , "%s.%s" , wal_file_dummy , "ready" );
286
+ snprintf (wal_file_done , MAXPGPATH , "%s.%s" , wal_file_dummy , "done" );
287
+
288
+ /* Check the existence of .ready file */
251
289
if (!fileExists (wal_file_ready , FIO_DB_HOST ))
252
290
{
253
291
/* no ready file, nothing to do here */
254
- args -> ret = 2 ;
255
- return NULL ;
292
+ continue ;
256
293
}
257
- }
258
- elog (LOG , "Thread [%d]: pushing file \"%s\"" , args -> thread_num , wal_filename );
259
294
260
- /* If compression is not required, then just copy it as is */
261
- if (!args -> compress )
262
- rc = push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
263
- args -> archive_dir , args -> overwrite ,
264
- args -> no_sync , args -> thread_num );
295
+ elog (LOG , "Thread [%d]: pushing file \"%s\"" , args -> thread_num , wal_filename );
296
+
297
+ /* If compression is not required, then just copy it as is */
298
+ if (!args -> compress )
299
+ rc = push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
300
+ args -> archive_dir , args -> overwrite ,
301
+ args -> no_sync , args -> thread_num );
265
302
#ifdef HAVE_LIBZ
266
- else
267
- rc = gz_push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
303
+ else
304
+ rc = gz_push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
268
305
args -> archive_dir , args -> overwrite , args -> no_sync ,
269
306
args -> compress_level , args -> thread_num );
270
307
#endif
271
308
272
- /* take '--no-ready-rename' flag into account */
273
- if (!args -> no_ready_rename && rc == 0 && args -> thread_num != 1 )
274
- {
275
- /* It is ok to rename status file in archive_status directory */
276
- elog (VERBOSE , "Thread [%d]: Rename \"%s\" to \"%s\"" , args -> thread_num ,
277
- wal_file_ready , wal_file_done );
278
- if (fio_rename (wal_file_ready , wal_file_done , FIO_DB_HOST ) < 0 )
279
- elog (ERROR , "Thread [%d]: Cannot rename file \"%s\" to \"%s\": %s" ,
280
- args -> thread_num , wal_file_ready , wal_file_done , strerror (errno ));
309
+ /* take '--no-ready-rename' flag into account */
310
+ if (!args -> no_ready_rename && rc == 0 )
311
+ {
312
+ /* It is ok to rename status file in archive_status directory */
313
+ elog (VERBOSE , "Thread [%d]: Rename \"%s\" to \"%s\"" , args -> thread_num ,
314
+ wal_file_ready , wal_file_done );
315
+ if (fio_rename (wal_file_ready , wal_file_done , FIO_DB_HOST ) < 0 )
316
+ elog (ERROR , "Thread [%d]: Cannot rename file \"%s\" to \"%s\": %s" ,
317
+ args -> thread_num , wal_file_ready , wal_file_done , strerror (errno ));
318
+ }
319
+
320
+ args -> n_pushed_files ++ ;
321
+
281
322
}
282
323
283
324
args -> ret = 0 ;
0 commit comments