55
55
#include "utils/resowner_private.h"
56
56
#include "postmaster/bgworker.h"
57
57
58
+
58
59
/*
59
60
* GUC variable that defines compression level.
60
61
* 0 - no compression, 1 - max speed,
@@ -417,15 +418,21 @@ int cfs_msync(FileMap* map)
417
418
FileMap * cfs_mmap (int md )
418
419
{
419
420
FileMap * map ;
421
+ if (ftruncate (md , sizeof (FileMap )) != 0 )
422
+ {
423
+ return (FileMap * )MAP_FAILED ;
424
+ }
425
+
420
426
#ifdef WIN32
421
- HANDLE mh = CreateFileMapping (_get_osfhandle (md ), NULL , PAGE_READWRITE ,
427
+ {
428
+ HANDLE mh = CreateFileMapping (_get_osfhandle (md ), NULL , PAGE_READWRITE ,
422
429
0 , (DWORD )sizeof (FileMap ), NULL );
423
- if (mh == NULL )
424
- return (FileMap * )MAP_FAILED ;
425
-
426
- map = (FileMap * )MapViewOfFile (mh , FILE_MAP_ALL_ACCESS , 0 , 0 , 0 );
427
- CloseHandle (mh );
430
+ if (mh == NULL )
431
+ return (FileMap * )MAP_FAILED ;
428
432
433
+ map = (FileMap * )MapViewOfFile (mh , FILE_MAP_ALL_ACCESS , 0 , 0 , 0 );
434
+ CloseHandle (mh );
435
+ }
429
436
if (map == NULL )
430
437
return (FileMap * )MAP_FAILED ;
431
438
@@ -533,17 +540,44 @@ static bool cfs_write_file(int fd, void const* data, uint32 size)
533
540
void cfs_lock_file (FileMap * map , char const * file_path )
534
541
{
535
542
long delay = CFS_LOCK_MIN_TIMEOUT ;
543
+ int n_attempts = 0 ;
536
544
537
545
while (true)
538
546
{
539
547
uint64 count = pg_atomic_fetch_add_u32 (& map -> lock , 1 );
548
+ bool revokeLock = false;
540
549
541
550
if (count < CFS_GC_LOCK )
542
551
break ;
543
-
544
- if (InRecovery )
552
+
553
+ if (InRecovery )
554
+ {
555
+ revokeLock = true;
556
+ }
557
+ else
545
558
{
546
- /* Uhhh... looks like last GC was interrupted.
559
+ if (!pg_atomic_unlocked_test_flag (& cfs_state -> gc_started ))
560
+ {
561
+ if (++ n_attempts > MAX_LOCK_ATTEMPTS )
562
+ {
563
+ /* So there is GC lock, but no active GC process during MAX_LOCK_ATTEMPTS.
564
+ * Most likely it means that GC is crashed (may be together with other postgres processes or even OS)
565
+ * without releasing lock. And for some reasons recovery was not performed and this page left locked.
566
+ * We should revoke the the lock to allow access to this segment.
567
+ */
568
+ revokeLock = true;
569
+ }
570
+ }
571
+ else
572
+ {
573
+ n_attempts = 0 ; /* Reset counter of attempts because GC is in progress */
574
+ }
575
+ }
576
+ if (revokeLock
577
+ /* use gc_started flag to prevent race condition with other backends and GC */
578
+ && pg_atomic_test_set_flag (& cfs_state -> gc_started ))
579
+ {
580
+ /* Ugggh... looks like last GC was interrupted.
547
581
* Try to recover the file.
548
582
*/
549
583
char * map_bck_path = psprintf ("%s.cfm.bck" , file_path );
@@ -565,18 +599,20 @@ void cfs_lock_file(FileMap* map, char const* file_path)
565
599
else
566
600
{
567
601
/* Presence of backup file means that we still have
568
- * unchanged data and map files. Just remove backup files,
569
- * grab lock and continue processing
602
+ * unchanged data and map files. Just remove backup files and
603
+ * revoke GC lock.
570
604
*/
571
605
unlink (file_bck_path );
572
606
unlink (map_bck_path );
573
607
}
574
608
609
+ pg_atomic_clear_flag (& cfs_state -> gc_started );
610
+ count = pg_atomic_fetch_sub_u32 (& map -> lock , CFS_GC_LOCK ); /* revoke GC lock */
611
+ Assert ((int )count > 0 );
575
612
pfree (file_bck_path );
576
613
pfree (map_bck_path );
577
614
break ;
578
- }
579
-
615
+ }
580
616
pg_atomic_fetch_sub_u32 (& map -> lock , 1 );
581
617
pg_usleep (delay );
582
618
if (delay < CFS_LOCK_MAX_TIMEOUT )
0 commit comments