@@ -65,8 +65,7 @@ static bool pg_is_in_recovery(PGconn *conn);
65
65
static bool pg_is_superuser (PGconn * conn );
66
66
static void check_server_version (PGconn * conn ,PGNodeInfo * nodeInfo );
67
67
static void confirm_block_size (PGconn * conn ,const char * name ,int blcksz );
68
- static size_t rewind_and_mark_cfs_datafiles (parray * files ,const char * root ,char * relative ,size_t i );
69
- static void group_cfs_segments (parray * files ,size_t first ,size_t last );
68
+ static void rewind_and_mark_cfs_datafiles (parray * files ,const char * root ,char * relative ,size_t i );
70
69
static bool remove_excluded_files_criterion (void * value ,void * exclude_args );
71
70
static void backup_cfs_segment (int i ,pgFile * file ,backup_files_arg * arguments );
72
71
static void process_file (int i ,pgFile * file ,backup_files_arg * arguments );
@@ -2228,7 +2227,11 @@ backup_cfs_segment(int i, pgFile *file, backup_files_arg *arguments) {
2228
2227
cfm_bck_file = data_file ;
2229
2228
}
2230
2229
data_file = file ;
2231
- Assert (cfm_file );/* ensure we always have cfm exist */
2230
+ if (data_file -> relOid >=FirstNormalObjectId && cfm_file == NULL )
2231
+ {
2232
+ elog (ERROR ,"'CFS' file '%s' have to have '%s.cfm' companion file" ,
2233
+ data_file -> rel_path ,data_file -> name );
2234
+ }
2232
2235
2233
2236
elog (LOG ,"backup CFS segment %s, data_file=%s, cfm_file=%s, data_bck_file=%s, cfm_bck_file=%s" ,
2234
2237
data_file -> name ,data_file -> name ,cfm_file -> name ,data_bck_file == NULL ?"NULL" :data_bck_file -> name ,cfm_bck_file == NULL ?"NULL" :cfm_bck_file -> name );
@@ -2251,7 +2254,10 @@ backup_cfs_segment(int i, pgFile *file, backup_files_arg *arguments) {
2251
2254
process_file (i ,cfm_bck_file ,arguments );
2252
2255
2253
2256
/* storing cfs segment in order cfm_file -> datafile to guarantee their consistency */
2254
- process_file (i ,cfm_file ,arguments );
2257
+ /* cfm_file could be NULL for system tables. But we don't clear is_cfs flag
2258
+ * for compatibility with older pg_probackup. */
2259
+ if (cfm_file )
2260
+ process_file (i ,cfm_file ,arguments );
2255
2261
process_file (i ,data_file ,arguments );
2256
2262
elog (LOG ,"Backup CFS segment %s done" ,data_file -> name );
2257
2263
}
@@ -2299,9 +2305,7 @@ parse_filelist_filenames(parray *files, const char *root)
2299
2305
strncmp (tmp_rel_path ,TABLESPACE_VERSION_DIRECTORY ,
2300
2306
strlen (TABLESPACE_VERSION_DIRECTORY ))== 0 ) {
2301
2307
/* rewind index to the beginning of cfs tablespace */
2302
- size_t start = rewind_and_mark_cfs_datafiles (files ,root ,file -> rel_path ,i );
2303
- /* group every to cfs segments chains */
2304
- group_cfs_segments (files ,start ,i );
2308
+ rewind_and_mark_cfs_datafiles (files ,root ,file -> rel_path ,i );
2305
2309
}
2306
2310
}
2307
2311
}
@@ -2349,57 +2353,11 @@ remove_excluded_files_criterion(void *value, void *exclude_args) {
2349
2353
return file -> remove_from_list ;
2350
2354
}
2351
2355
2352
- /*
2353
- * For every cfs segment do group its files to linked list, datafile on the head.
2354
- * All non data files of segment moved to linked list and marked to skip in backup processing threads.
2355
- * @param first - first index of cfs tablespace files
2356
- * @param last - last index of cfs tablespace files
2357
- */
2358
- void group_cfs_segments (parray * files ,size_t first ,size_t last ) {/* grouping cfs files by relOid.segno, removing leafs of group */
2359
-
2360
- for (;first <=last ;first ++ )
2361
- {
2362
- pgFile * file = parray_get (files ,first );
2363
-
2364
- if (file -> is_cfs )
2365
- {
2366
- pgFile * cfs_file = file ;
2367
- size_t counter = first + 1 ;
2368
- pgFile * chain_file = parray_get (files ,counter );
2369
-
2370
- bool has_cfm = false;/* flag for later assertion the cfm file also exist */
2371
-
2372
- elog (LOG ,"Preprocessing cfs file %s, %u.%d" ,cfs_file -> name ,cfs_file -> relOid ,cfs_file -> segno );
2373
-
2374
- elog (LOG ,"Checking file %s, %u.%d as cfs chain" ,chain_file -> name ,chain_file -> relOid ,chain_file -> segno );
2375
-
2376
- /* scanning cfs segment files */
2377
- while (cfs_file -> relOid == chain_file -> relOid &&
2378
- cfs_file -> segno == chain_file -> segno )
2379
- {
2380
- elog (LOG ,"Grouping cfs chain file %s, %d.%d" ,chain_file -> name ,chain_file -> relOid ,chain_file -> segno );
2381
- chain_file -> skip_cfs_nested = true;
2382
- cfs_file -> cfs_chain = chain_file ;/* adding to cfs group */
2383
- cfs_file = chain_file ;
2384
-
2385
- /* next file */
2386
- counter ++ ;
2387
- chain_file = parray_get (files ,counter );
2388
- elog (LOG ,"Checking file %s, %u.%d as cfs chain" ,chain_file -> name ,chain_file -> relOid ,chain_file -> segno );
2389
- }
2390
-
2391
- /* assertion - we always have cfs data + cfs map files */
2392
- cfs_file = file ;
2393
- for (;cfs_file ;cfs_file = cfs_file -> cfs_chain ) {
2394
- elog (LOG ,"searching cfm in %s, chain is %s" ,cfs_file -> name ,cfs_file -> cfs_chain == NULL ?"NULL" :cfs_file -> cfs_chain -> name );
2395
- has_cfm = cfs_file -> forkName == cfm ;
2396
- }
2397
- Assert (has_cfm );
2398
-
2399
- /* shifting to last cfs segment file */
2400
- first = counter - 1 ;
2401
- }
2402
- }
2356
+ static uint32_t
2357
+ hash_rel_seg (pgFile * file )
2358
+ {
2359
+ uint32 hash = hash_mix32_2 (file -> relOid ,file -> segno );
2360
+ return hash_mix32_2 (hash ,0xcf5 );
2403
2361
}
2404
2362
2405
2363
/* If file is equal to pg_compression, then we consider this tablespace as
@@ -2416,13 +2374,24 @@ void group_cfs_segments(parray *files, size_t first, size_t last) {/* grouping c
2416
2374
*
2417
2375
* @returns index of first tablespace entry, i.e tblspcOid/TABLESPACE_VERSION_DIRECTORY
2418
2376
*/
2419
- static size_t
2377
+ static void
2420
2378
rewind_and_mark_cfs_datafiles (parray * files ,const char * root ,char * relative ,size_t i )
2421
2379
{
2422
2380
int len ;
2423
2381
int p ;
2382
+ int j ;
2424
2383
pgFile * prev_file ;
2384
+ pgFile * tmp_file ;
2425
2385
char * cfs_tblspc_path ;
2386
+ uint32_t h ;
2387
+
2388
+ /* hash table for cfm files */
2389
+ #define HASHN 128
2390
+ parray * hashtab [HASHN ]= {NULL };
2391
+ parray * bucket ;
2392
+ for (p = 0 ;p < HASHN ;p ++ )
2393
+ hashtab [p ]= parray_new ();
2394
+
2426
2395
2427
2396
cfs_tblspc_path = strdup (relative );
2428
2397
if (!cfs_tblspc_path )
@@ -2437,23 +2406,60 @@ rewind_and_mark_cfs_datafiles(parray *files, const char *root, char *relative, s
2437
2406
2438
2407
elog (LOG ,"Checking file in cfs tablespace %s" ,prev_file -> rel_path );
2439
2408
2440
- if (strstr (prev_file -> rel_path ,cfs_tblspc_path )!= NULL )
2409
+ if (strstr (prev_file -> rel_path ,cfs_tblspc_path )== NULL )
2410
+ {
2411
+ elog (LOG ,"Breaking on %s" ,prev_file -> rel_path );
2412
+ break ;
2413
+ }
2414
+
2415
+ if (!S_ISREG (prev_file -> mode ))
2416
+ continue ;
2417
+
2418
+ h = hash_rel_seg (prev_file );
2419
+ bucket = hashtab [h %HASHN ];
2420
+
2421
+ if (prev_file -> forkName == cfm || prev_file -> forkName == cfm_bck ||
2422
+ prev_file -> forkName == cfs_bck )
2441
2423
{
2442
- if (S_ISREG (prev_file -> mode )&& prev_file -> is_datafile )
2424
+ parray_append (bucket ,prev_file );
2425
+ }
2426
+ else if (prev_file -> is_datafile && prev_file -> forkName == none )
2427
+ {
2428
+ elog (LOG ,"Processing 'cfs' file %s" ,prev_file -> rel_path );
2429
+ /* have to mark as is_cfs even for system-tables for compatibility
2430
+ * with older pg_probackup */
2431
+ prev_file -> is_cfs = true;
2432
+ prev_file -> cfs_chain = NULL ;
2433
+ for (j = 0 ;j < parray_num (bucket );j ++ )
2443
2434
{
2444
- elog (LOG ,"Setting 'is_cfs' on file %s, name %s" ,
2445
- prev_file -> rel_path ,prev_file -> name );
2446
- prev_file -> is_cfs = true;
2435
+ tmp_file = parray_get (bucket ,j );
2436
+ elog (LOG ,"Linking 'cfs' file '%s' to '%s'" ,
2437
+ tmp_file -> rel_path ,prev_file -> rel_path );
2438
+ if (tmp_file -> relOid == prev_file -> relOid &&
2439
+ tmp_file -> segno == prev_file -> segno )
2440
+ {
2441
+ tmp_file -> cfs_chain = prev_file -> cfs_chain ;
2442
+ prev_file -> cfs_chain = tmp_file ;
2443
+ parray_remove (bucket ,j );
2444
+ j -- ;
2445
+ }
2447
2446
}
2448
2447
}
2449
- else
2448
+ }
2449
+
2450
+ for (p = 0 ;p < HASHN ;p ++ )
2451
+ {
2452
+ bucket = hashtab [p ];
2453
+ for (j = 0 ;j < parray_num (bucket );j ++ )
2450
2454
{
2451
- elog ( LOG , "Breaking on %s" , prev_file -> rel_path );
2452
- break ;
2455
+ tmp_file = parray_get ( bucket , j );
2456
+ elog ( WARNING , "Orphaned cfs related file '%s'" , tmp_file -> rel_path ) ;
2453
2457
}
2458
+ parray_free (bucket );
2459
+ hashtab [p ]= NULL ;
2454
2460
}
2461
+ #undef HASHN
2455
2462
free (cfs_tblspc_path );
2456
- return p + 1 ;
2457
2463
}
2458
2464
2459
2465
/*