14
14
15
15
static int push_wal_file_internal (const char * wal_file_name , const char * pg_xlog_dir ,
16
16
const char * archive_dir , bool overwrite , bool no_sync ,
17
- int thread_num );
17
+ int thread_num , uint32 archive_timeout );
18
18
#ifdef HAVE_LIBZ
19
19
static int gz_push_wal_file_internal (const char * wal_file_name , const char * pg_xlog_dir ,
20
20
const char * archive_dir , bool overwrite , bool no_sync ,
21
- int compress_level , int thread_num );
21
+ int compress_level , int thread_num , uint32 archive_timeout );
22
22
#endif
23
23
static void * push_wal_segno (void * arg );
24
24
static void get_wal_file (const char * from_path , const char * to_path );
@@ -33,14 +33,17 @@ static void copy_file_attributes(const char *from_path,
33
33
typedef struct
34
34
{
35
35
TimeLineID tli ;
36
+ XLogSegNo first_segno ;
36
37
uint32 xlog_seg_size ;
37
38
38
39
const char * pg_xlog_dir ;
39
40
const char * archive_dir ;
41
+ const char * archive_status_dir ;
40
42
bool overwrite ;
41
43
bool compress ;
42
44
bool no_sync ;
43
45
bool no_ready_rename ;
46
+ uint32 archive_timeout ;
44
47
45
48
CompressAlg compress_alg ;
46
49
int compress_level ;
@@ -73,8 +76,7 @@ typedef struct WALSegno
73
76
* set archive_command to
74
77
* 'pg_probackup archive-push -B /home/anastasia/backup --wal-file-name %f',
75
78
* to move backups into arclog_path.
76
- * Where archlog_path is $BACKUP_PATH/wal/system_id.
77
- * Currently it just copies wal files to the new location.
79
+ * Where archlog_path is $BACKUP_PATH/wal/instance_name
78
80
*/
79
81
int
80
82
do_archive_push (InstanceConfig * instance , char * wal_file_path ,
@@ -84,6 +86,7 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
84
86
uint64 i ;
85
87
char current_dir [MAXPGPATH ];
86
88
char pg_xlog_dir [MAXPGPATH ];
89
+ char archive_status_dir [MAXPGPATH ];
87
90
uint64 system_id ;
88
91
bool is_compress = false;
89
92
@@ -125,6 +128,7 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
125
128
elog (ERROR , "Cannot use pglz for WAL compression" );
126
129
127
130
join_path_components (pg_xlog_dir , current_dir , XLOGDIR );
131
+ join_path_components (archive_status_dir , pg_xlog_dir , "archive_status" );
128
132
129
133
/* Create 'archlog_path' directory. Do nothing if it already exists. */
130
134
//fio_mkdir(instance->arclog_path, DIR_PERMISSION, FIO_BACKUP_HOST);
@@ -161,10 +165,12 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
161
165
if (is_compress )
162
166
gz_push_wal_file_internal (wal_file_name , pg_xlog_dir ,
163
167
instance -> arclog_path , overwrite ,
164
- no_sync , instance -> compress_level , 1 );
168
+ no_sync , instance -> compress_level , 1 ,
169
+ instance -> archive_timeout );
165
170
else
166
171
push_wal_file_internal (wal_file_name , pg_xlog_dir ,
167
- instance -> arclog_path , overwrite , no_sync , 1 );
172
+ instance -> arclog_path , overwrite ,
173
+ no_sync , 1 , instance -> archive_timeout );
168
174
169
175
push_isok = true;
170
176
total_pushed_files ++ ;
@@ -175,8 +181,8 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
175
181
if (IsXLogFileName (wal_file_name ))
176
182
GetXLogFromFileName (wal_file_name , & tli , & first_segno , instance -> xlog_seg_size );
177
183
184
+ /* setup filelist and locks */
178
185
files = parray_new ();
179
- /* setup locks */
180
186
for (i = first_segno ; i < first_segno + batch_size ; i ++ )
181
187
{
182
188
WALSegno * xlogfile = palloc (sizeof (WALSegno ));
@@ -198,13 +204,16 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
198
204
archive_push_arg * arg = & (threads_args [i ]);
199
205
200
206
arg -> tli = tli ;
207
+ arg -> first_segno = first_segno ;
201
208
arg -> xlog_seg_size = instance -> xlog_seg_size ;
202
209
arg -> archive_dir = instance -> arclog_path ;
203
210
arg -> pg_xlog_dir = pg_xlog_dir ;
211
+ arg -> archive_status_dir = archive_status_dir ;
204
212
arg -> overwrite = overwrite ;
205
213
arg -> compress = is_compress ;
206
214
arg -> no_sync = no_sync ;
207
215
arg -> no_ready_rename = no_ready_rename ;
216
+ arg -> archive_timeout = instance -> archive_timeout ;
208
217
209
218
arg -> compress_alg = instance -> compress_alg ;
210
219
arg -> compress_level = instance -> compress_level ;
@@ -234,8 +243,9 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
234
243
total_pushed_files += threads_args [i ].n_pushed_files ;
235
244
}
236
245
237
- /* Note, that we don`t do garbage collection here,
238
- * because pushing into archive is a very time-sensetive operation.
246
+ /* Note, that we are leaking memory here,
247
+ * because pushing into archive is a very
248
+ * time-sensetive operation, so we skip freeing stuff.
239
249
*/
240
250
241
251
push_done :
@@ -254,23 +264,20 @@ do_archive_push(InstanceConfig *instance, char *wal_file_path,
254
264
/* ------------- INTERNAL FUNCTIONS ---------- */
255
265
/*
256
266
* Copy WAL segment from pgdata to archive catalog with possible compression.
257
- *
267
+ * TODO: make it possible to be greedy here, i.e. pushing everything
268
+ * that is ready to be pushed.
258
269
*/
259
270
static void *
260
271
push_wal_segno (void * arg )
261
272
{
262
273
int i ;
263
274
int rc ;
264
275
char wal_filename [MAXPGPATH ];
265
-
266
- char archive_status_dir [MAXPGPATH ];
267
276
char wal_file_dummy [MAXPGPATH ];
268
277
char wal_file_ready [MAXPGPATH ];
269
278
char wal_file_done [MAXPGPATH ];
270
279
archive_push_arg * args = (archive_push_arg * ) arg ;
271
280
272
- join_path_components (archive_status_dir , args -> pg_xlog_dir , "archive_status" );
273
-
274
281
for (i = 0 ; i < parray_num (args -> files ); i ++ )
275
282
{
276
283
WALSegno * xlogfile = (WALSegno * ) parray_get (args -> files , i );
@@ -281,7 +288,7 @@ push_wal_segno(void *arg)
281
288
/* At first we must construct WAL filename from segno, tli and xlog_seg_size */
282
289
GetXLogFileName (wal_filename , args -> tli , xlogfile -> segno , args -> xlog_seg_size );
283
290
284
- join_path_components (wal_file_dummy , archive_status_dir , wal_filename );
291
+ join_path_components (wal_file_dummy , args -> archive_status_dir , wal_filename );
285
292
snprintf (wal_file_ready , MAXPGPATH , "%s.%s" , wal_file_dummy , "ready" );
286
293
snprintf (wal_file_done , MAXPGPATH , "%s.%s" , wal_file_dummy , "done" );
287
294
@@ -298,17 +305,24 @@ push_wal_segno(void *arg)
298
305
if (!args -> compress )
299
306
rc = push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
300
307
args -> archive_dir , args -> overwrite ,
301
- args -> no_sync , args -> thread_num );
308
+ args -> no_sync , args -> thread_num ,
309
+ args -> archive_timeout );
302
310
#ifdef HAVE_LIBZ
303
311
else
304
312
rc = gz_push_wal_file_internal (wal_filename , args -> pg_xlog_dir ,
305
313
args -> archive_dir , args -> overwrite , args -> no_sync ,
306
- args -> compress_level , args -> thread_num );
314
+ args -> compress_level , args -> thread_num ,
315
+ args -> archive_timeout );
307
316
#endif
308
317
309
318
/* take '--no-ready-rename' flag into account */
310
- if (!args -> no_ready_rename && rc == 0 )
319
+ if (!args -> no_ready_rename && rc == 0 &&
320
+ /* don`t rename ready file for the first segment,
321
+ * postgres will complain via WARNING if we do that */
322
+ args -> first_segno != xlogfile -> segno )
311
323
{
324
+ canonicalize_path (wal_file_ready );
325
+ canonicalize_path (wal_file_done );
312
326
/* It is ok to rename status file in archive_status directory */
313
327
elog (VERBOSE , "Thread [%d]: Rename \"%s\" to \"%s\"" , args -> thread_num ,
314
328
wal_file_ready , wal_file_done );
@@ -318,7 +332,6 @@ push_wal_segno(void *arg)
318
332
}
319
333
320
334
args -> n_pushed_files ++ ;
321
-
322
335
}
323
336
324
337
args -> ret = 0 ;
@@ -336,7 +349,7 @@ push_wal_segno(void *arg)
336
349
int
337
350
push_wal_file_internal (const char * wal_file_name , const char * pg_xlog_dir ,
338
351
const char * archive_dir , bool overwrite , bool no_sync ,
339
- int thread_num )
352
+ int thread_num , uint32 archive_timeout )
340
353
{
341
354
FILE * in = NULL ;
342
355
int out = -1 ;
@@ -353,8 +366,10 @@ push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
353
366
354
367
/* from path */
355
368
join_path_components (from_fullpath , pg_xlog_dir , wal_file_name );
369
+ canonicalize_path (from_fullpath );
356
370
/* to path */
357
371
join_path_components (to_fullpath , archive_dir , wal_file_name );
372
+ canonicalize_path (to_fullpath );
358
373
359
374
/* Open source file for read */
360
375
in = fio_fopen (from_fullpath , PG_BINARY_R , FIO_DB_HOST );
@@ -377,11 +392,20 @@ push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
377
392
else
378
393
goto part_opened ;
379
394
380
- /* Partial file already exists, it could have happened due to failed archive-push,
381
- * in this case partial file can be discarded, or due to concurrent archiving.
395
+ /*
396
+ * Partial file already exists, it could have happened due to:
397
+ * 1. failed archive-push
398
+ * 2. concurrent archiving
399
+ *
400
+ * For ARCHIVE_TIMEOUT period we will try to create partial file
401
+ * and look for the size of already existing partial file, to
402
+ * determine if it is changing or not.
403
+ * If after ARCHIVE_TIMEOUT we still failed to create partial
404
+ * file, we will make a decision about discarding
405
+ * already existing partial file.
382
406
*/
383
- /* TODO: use --archive-timeout */
384
- while (partial_try_count < PARTIAL_WAL_TIMER )
407
+
408
+ while (partial_try_count < archive_timeout )
385
409
{
386
410
if (fio_stat (to_fullpath_part , & st , false, FIO_BACKUP_HOST ) < 0 )
387
411
{
@@ -407,8 +431,9 @@ push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
407
431
/* first round */
408
432
if (!partial_try_count )
409
433
{
410
- elog (VERBOSE , "Thread [%d]: Temp WAL file already exists, waiting on it: \"%s\"" ,
411
- thread_num , to_fullpath_part );
434
+ elog (VERBOSE , "Thread [%d]: Temp WAL file already exists, "
435
+ "waiting on it %s seconds: \"%s\"" ,
436
+ thread_num , archive_timeout , to_fullpath_part );
412
437
partial_file_size = st .st_size ;
413
438
}
414
439
@@ -433,7 +458,7 @@ push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
433
458
{
434
459
if (!partial_is_stale )
435
460
elog (ERROR , "Thread [%d]: Failed to open temp WAL file \"%s\" in %i seconds" ,
436
- thread_num , to_fullpath_part , PARTIAL_WAL_TIMER );
461
+ thread_num , to_fullpath_part , archive_timeout );
437
462
438
463
/* Partial segment is considered stale, so reuse it */
439
464
elog (LOG , "Thread [%d]: Reusing stale temp WAL file \"%s\"" ,
@@ -562,7 +587,7 @@ push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
562
587
int
563
588
gz_push_wal_file_internal (const char * wal_file_name , const char * pg_xlog_dir ,
564
589
const char * archive_dir , bool overwrite , bool no_sync ,
565
- int compress_level , int thread_num )
590
+ int compress_level , int thread_num , uint32 archive_timeout )
566
591
{
567
592
FILE * in = NULL ;
568
593
gzFile out = NULL ;
@@ -582,8 +607,10 @@ gz_push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
582
607
583
608
/* from path */
584
609
join_path_components (from_fullpath , pg_xlog_dir , wal_file_name );
610
+ canonicalize_path (from_fullpath );
585
611
/* to path */
586
612
join_path_components (to_fullpath , archive_dir , wal_file_name );
613
+ canonicalize_path (to_fullpath );
587
614
588
615
/* destination file with .gz suffix */
589
616
snprintf (to_fullpath_gz , sizeof (to_fullpath_gz ), "%s.gz" , to_fullpath );
@@ -608,10 +635,20 @@ gz_push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
608
635
else
609
636
goto part_opened ;
610
637
611
- /* Partial file already exists, it could have happened due to failed archive-push,
612
- * in this case partial file can be discarded, or due to concurrent archiving.
638
+ /*
639
+ * Partial file already exists, it could have happened due to:
640
+ * 1. failed archive-push
641
+ * 2. concurrent archiving
642
+ *
643
+ * For ARCHIVE_TIMEOUT period we will try to create partial file
644
+ * and look for the size of already existing partial file, to
645
+ * determine if it is changing or not.
646
+ * If after ARCHIVE_TIMEOUT we still failed to create partial
647
+ * file, we will make a decision about discarding
648
+ * already existing partial file.
613
649
*/
614
- while (partial_try_count < PARTIAL_WAL_TIMER )
650
+
651
+ while (partial_try_count < archive_timeout )
615
652
{
616
653
if (fio_stat (to_fullpath_gz_part , & st , false, FIO_BACKUP_HOST ) < 0 )
617
654
{
@@ -637,8 +674,9 @@ gz_push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
637
674
/* first round */
638
675
if (!partial_try_count )
639
676
{
640
- elog (VERBOSE , "Thread [%d]: Temp WAL file already exists, waiting on it: \"%s\"" ,
641
- thread_num , to_fullpath_gz_part );
677
+ elog (VERBOSE , "Thread [%d]: Temp WAL file already exists, "
678
+ "waiting on it %s seconds: \"%s\"" ,
679
+ thread_num , archive_timeout , to_fullpath_gz_part );
642
680
partial_file_size = st .st_size ;
643
681
}
644
682
@@ -663,7 +701,7 @@ gz_push_wal_file_internal(const char *wal_file_name, const char *pg_xlog_dir,
663
701
{
664
702
if (!partial_is_stale )
665
703
elog (ERROR , "Thread [%d]: Failed to open temp WAL file \"%s\" in %i seconds" ,
666
- thread_num , to_fullpath_gz_part , PARTIAL_WAL_TIMER );
704
+ thread_num , to_fullpath_gz_part , archive_timeout );
667
705
668
706
/* Partial segment is considered stale, so reuse it */
669
707
elog (LOG , "Thread [%d]: Reusing stale temp WAL file \"%s\"" ,
0 commit comments