20
20
#include "access/genam.h"
21
21
#include "access/generic_xlog.h"
22
22
#include "catalog/pg_depend.h"
23
+ #include "catalog/pg_tablespace.h"
23
24
#include "access/htup_details.h"
24
25
#include "miscadmin.h"
25
26
#include "storage/bufmgr.h"
29
30
#include "utils/array.h"
30
31
#include "utils/relfilenodemap.h"
31
32
#include "utils/builtins.h"
33
+ #include "utils/pg_lsn.h"
32
34
#include <unistd.h>
33
35
#include <sys/stat.h>
34
36
@@ -55,6 +57,11 @@ void SetPtrackClearLSN(bool set_invalid);
55
57
Datum pg_ptrack_test (PG_FUNCTION_ARGS );
56
58
Datum pg_ptrack_clear (PG_FUNCTION_ARGS );
57
59
Datum pg_ptrack_get_and_clear (PG_FUNCTION_ARGS );
60
+ Datum pg_ptrack_get_and_clear_db (PG_FUNCTION_ARGS );
61
+ Datum pg_ptrack_control_lsn (PG_FUNCTION_ARGS );
62
+
63
+ void create_ptrack_init_file (char * dest_dir );
64
+ void drop_ptrack_init_file (char * dest_dir );
58
65
59
66
/*
60
67
* Mark tracked memory block during recovery.
@@ -471,196 +478,100 @@ assign_ptrack_enable(bool newval, void *extra)
471
478
SetPtrackClearLSN (true);
472
479
}
473
480
474
- /* Test ptrack file. */
481
+ /* Clear all ptrack files */
475
482
Datum
476
- pg_ptrack_test (PG_FUNCTION_ARGS )
483
+ pg_ptrack_clear (PG_FUNCTION_ARGS )
477
484
{
478
- Oid relation_oid = PG_GETARG_OID (0 );
479
- BlockNumber nblock , num_blocks ;
480
- Relation rel ;
481
- XLogRecPtr ptrack_control_lsn ;
482
- Buffer ptrack_buf = InvalidBuffer ;
483
- Page page ;
484
- char * map ;
485
- int fd ;
486
- unsigned int excess_data_counter = 0 ;
487
- unsigned int necessary_data_counter = 0 ;
488
- ArrayType * result_array ;
489
- Datum result_elems [2 ];
490
-
491
485
if (!superuser () && !has_rolreplication (GetUserId ()))
492
486
ereport (ERROR ,
493
487
(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
494
488
(errmsg ("must be superuser or replication role to clear ptrack files" ))));
495
489
496
- /* get LSN from ptrack_control file */
497
- fd = BasicOpenFile ("global/ptrack_control" ,
498
- O_RDONLY | PG_BINARY ,
499
- 0 );
500
-
501
- if (fd < 0 )
502
- ereport (PANIC ,
503
- (errcode_for_file_access (),
504
- errmsg ("could not open ptrack control file \"%s\": %m" ,
505
- "global/ptrack_control" )));
506
- errno = 0 ;
507
- if (read (fd , & ptrack_control_lsn , sizeof (XLogRecPtr )) != sizeof (XLogRecPtr ))
508
- {
509
- /* if write didn't set errno, assume problem is no disk space */
510
- if (errno == 0 )
511
- errno = ENOSPC ;
512
-
513
- ereport (PANIC ,
514
- (errcode_for_file_access (),
515
- errmsg ("could not read to ptrack control file: %m" )));
516
- }
517
-
518
- if (close (fd ))
519
- ereport (PANIC ,
520
- (errcode_for_file_access (),
521
- errmsg ("could not close ptrack control file: %m" )));
522
-
523
- rel = RelationIdGetRelation (relation_oid );
524
- if (rel == InvalidRelation )
525
- {
526
- elog (WARNING , "Relation not found." );
527
- goto end_return ;
528
- }
529
-
530
- LockRelationOid (relation_oid , AccessShareLock );
531
- RelationOpenSmgr (rel );
532
- if (rel -> rd_smgr == NULL )
533
- goto end_rel ;
534
-
535
- LockRelationForExtension (rel , ExclusiveLock );
536
-
537
- num_blocks = smgrnblocks (rel -> rd_smgr , MAIN_FORKNUM );
538
- if (rel -> rd_smgr -> smgr_ptrack_nblocks == InvalidBlockNumber )
539
- {
540
- if (smgrexists (rel -> rd_smgr , PAGESTRACK_FORKNUM ))
541
- rel -> rd_smgr -> smgr_ptrack_nblocks = smgrnblocks (rel -> rd_smgr , PAGESTRACK_FORKNUM );
542
- else
543
- rel -> rd_smgr -> smgr_ptrack_nblocks = 0 ;
544
- }
545
-
546
- for (nblock = 0 ; nblock < num_blocks ; nblock ++ )
547
- {
548
- Buffer main_buf = ReadBufferExtended (rel ,
549
- MAIN_FORKNUM ,
550
- nblock ,
551
- RBM_ZERO_ON_ERROR ,
552
- NULL );
553
- Page main_page ;
554
- XLogRecPtr main_page_lsn ;
555
-
556
- BlockNumber mapBlock = HEAPBLK_TO_MAPBLOCK (nblock );
557
- uint32 mapByte = HEAPBLK_TO_MAPBYTE (nblock );
558
- uint8 mapBit = HEAPBLK_TO_MAPBIT (nblock );
559
-
560
- /* Get page lsn */
561
- LockBuffer (main_buf , BUFFER_LOCK_SHARE );
562
- main_page = BufferGetPage (main_buf );
563
- main_page_lsn = PageGetLSN (main_page );
564
- LockBuffer (main_buf , BUFFER_LOCK_UNLOCK );
565
- ReleaseBuffer (main_buf );
566
-
567
- /* Reuse the old pinned buffer if possible */
568
- if (BufferIsValid (ptrack_buf ))
569
- {
570
- if (BufferGetBlockNumber (ptrack_buf ) == mapBlock )
571
- goto read_bit ;
572
- else
573
- ReleaseBuffer (ptrack_buf );
574
- }
575
- ptrack_buf = ptrack_readbuf (rel , mapBlock , false);
576
-
577
- read_bit :
578
- if (ptrack_buf == InvalidBuffer )
579
- {
580
- /* not tracked data */
581
- if (ptrack_control_lsn < main_page_lsn )
582
- {
583
- necessary_data_counter ++ ;
584
- elog (WARNING , "Block %ud not track. Ptrack lsn:%X/%X page lsn:%X/%X" ,
585
- nblock ,
586
- (uint32 ) (ptrack_control_lsn >> 32 ),
587
- (uint32 ) ptrack_control_lsn ,
588
- (uint32 ) (main_page_lsn >> 32 ),
589
- (uint32 ) main_page_lsn );
590
- }
591
- else
592
- continue ;
593
- }
594
-
595
- page = BufferGetPage (ptrack_buf );
596
- map = PageGetContents (page );
597
- LockBuffer (ptrack_buf , BUFFER_LOCK_SHARE );
598
- if (map [mapByte ] & (1 << mapBit ))
599
- {
600
- /* excess data */
601
- if (ptrack_control_lsn >= main_page_lsn )
602
- {
603
- excess_data_counter ++ ;
604
- elog (WARNING , "Block %ud not needed. Ptrack lsn:%X/%X page lsn:%X/%X" ,
605
- nblock ,
606
- (uint32 ) (ptrack_control_lsn >> 32 ),
607
- (uint32 ) ptrack_control_lsn ,
608
- (uint32 ) (main_page_lsn >> 32 ),
609
- (uint32 ) main_page_lsn );
610
- }
611
- }
612
- /* not tracked data */
613
- else if (ptrack_control_lsn < main_page_lsn )
614
- {
615
- necessary_data_counter ++ ;
616
- elog (WARNING , "Block %ud not tracked. Ptrack lsn:%X/%X page lsn:%X/%X" ,
617
- nblock ,
618
- (uint32 ) (ptrack_control_lsn >> 32 ),
619
- (uint32 ) ptrack_control_lsn ,
620
- (uint32 ) (main_page_lsn >> 32 ),
621
- (uint32 ) main_page_lsn );
622
- }
623
- LockBuffer (ptrack_buf , BUFFER_LOCK_UNLOCK );
624
- }
490
+ ptrack_clear ();
625
491
626
- end_rel :
627
- if (ptrack_buf != InvalidBuffer )
628
- ReleaseBuffer (ptrack_buf );
629
- UnlockRelationForExtension (rel , ExclusiveLock );
630
- RelationClose (rel );
631
- UnlockRelationOid (relation_oid , AccessShareLock );
632
-
633
- end_return :
634
- result_elems [0 ] = UInt32GetDatum (excess_data_counter );
635
- result_elems [1 ] = UInt32GetDatum (necessary_data_counter );
636
- result_array = construct_array (result_elems , 2 , 23 , 4 , true, 'i' );
637
- PG_RETURN_ARRAYTYPE_P (result_array );
492
+ PG_RETURN_VOID ();
638
493
}
639
494
640
- /* Clear all ptrack files */
495
+ /* Read all ptrack files and clear them afterwards */
641
496
Datum
642
- pg_ptrack_clear (PG_FUNCTION_ARGS )
497
+ pg_ptrack_get_and_clear (PG_FUNCTION_ARGS )
643
498
{
644
499
if (!superuser () && !has_rolreplication (GetUserId ()))
645
500
ereport (ERROR ,
646
501
(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
647
502
(errmsg ("must be superuser or replication role to clear ptrack files" ))));
648
503
649
- ptrack_clear ();
650
-
651
- PG_RETURN_VOID ();
504
+ PG_RETURN_BYTEA_P (ptrack_get_and_clear (PG_GETARG_OID (0 ), PG_GETARG_OID (1 )));
652
505
}
653
506
654
- /* Read all ptrack files and clear them afterwards */
507
+ /*
508
+ * Check if PTRACK_INIT_FILE exits in the given database
509
+ * and delete it.
510
+ * Args: dbOid and tblspcOid
511
+ * Return true if file existed.
512
+ */
655
513
Datum
656
- pg_ptrack_get_and_clear (PG_FUNCTION_ARGS )
514
+ pg_ptrack_get_and_clear_db (PG_FUNCTION_ARGS )
657
515
{
516
+ char * db_path = GetDatabasePath (PG_GETARG_OID (0 ), PG_GETARG_OID (1 ));
517
+ struct stat buf ;
518
+ char ptrack_init_file_path [MAXPGPATH ];
519
+
658
520
if (!superuser () && !has_rolreplication (GetUserId ()))
659
521
ereport (ERROR ,
660
522
(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
661
523
(errmsg ("must be superuser or replication role to clear ptrack files" ))));
662
524
663
- PG_RETURN_BYTEA_P (ptrack_get_and_clear (PG_GETARG_OID (0 ), PG_GETARG_OID (1 )));
525
+ snprintf (ptrack_init_file_path , sizeof (ptrack_init_file_path ), "%s/%s" , db_path , PTRACK_INIT_FILE );
526
+
527
+ if (stat (ptrack_init_file_path , & buf ) == -1 && errno == ENOENT )
528
+ PG_RETURN_BOOL (false);
529
+ else if (!S_ISREG (buf .st_mode ))
530
+ PG_RETURN_BOOL (false);
531
+ else
532
+ {
533
+ drop_ptrack_init_file (db_path );
534
+ PG_RETURN_BOOL (true);
535
+ }
536
+ }
537
+
538
+ /* create empty ptrack_init_file */
539
+ void
540
+ create_ptrack_init_file (char * dest_dir )
541
+ {
542
+ int dstfd ;
543
+
544
+ char ptrack_init_file_path [MAXPGPATH ];
545
+ snprintf (ptrack_init_file_path , sizeof (ptrack_init_file_path ), "%s/%s" , dest_dir , PTRACK_INIT_FILE );
546
+
547
+ dstfd = OpenTransientFile (ptrack_init_file_path , O_RDWR | O_CREAT | O_EXCL | PG_BINARY ,
548
+ S_IRUSR | S_IWUSR );
549
+ if (dstfd < 0 )
550
+ {
551
+ if (errno != EEXIST )
552
+ ereport (ERROR ,
553
+ (errcode_for_file_access (),
554
+ errmsg ("could not create file \"%s\": %m" , ptrack_init_file_path )));
555
+ }
556
+ else if (CloseTransientFile (dstfd ))
557
+ ereport (ERROR ,
558
+ (errcode_for_file_access (),
559
+ errmsg ("could not close file \"%s\": %m" , ptrack_init_file_path )));
560
+ }
561
+
562
+ void
563
+ drop_ptrack_init_file (char * dest_dir )
564
+ {
565
+ char ptrack_init_file_path [MAXPGPATH ];
566
+ snprintf (ptrack_init_file_path , sizeof (ptrack_init_file_path ), "%s/%s" , dest_dir , PTRACK_INIT_FILE );
567
+
568
+ if (unlink (ptrack_init_file_path ) != 0 )
569
+ {
570
+ if (errno != ENOENT )
571
+ ereport (WARNING ,
572
+ (errcode_for_file_access (),
573
+ errmsg ("could not remove file \"%s\": %m" , ptrack_init_file_path )));
574
+ }
664
575
}
665
576
666
577
/*
@@ -672,3 +583,36 @@ ptrack_version(PG_FUNCTION_ARGS)
672
583
{
673
584
PG_RETURN_TEXT_P (cstring_to_text (PTRACK_VERSION ));
674
585
}
586
+
587
+ /* Get lsn from ptrack_control file */
588
+ Datum
589
+ pg_ptrack_control_lsn (PG_FUNCTION_ARGS )
590
+ {
591
+ int fd ;
592
+ char file_path [MAXPGPATH ];
593
+ XLogRecPtr lsn = 0 ;
594
+
595
+ if (!superuser () && !has_rolreplication (GetUserId ()))
596
+ ereport (ERROR ,
597
+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
598
+ (errmsg ("must be superuser or replication role read ptrack files" ))));
599
+ join_path_components (file_path , DataDir , "global/ptrack_control" );
600
+ canonicalize_path (file_path );
601
+
602
+ fd = BasicOpenFile (file_path , O_RDONLY | PG_BINARY , 0 );
603
+ if (fd < 0 )
604
+ ereport (ERROR ,
605
+ (errcode_for_file_access (),
606
+ errmsg ("could not open file \"%s\" for reading: %m" ,
607
+ file_path )));
608
+
609
+ if (read (fd , & lsn , sizeof (XLogRecPtr )) != sizeof (XLogRecPtr ))
610
+ ereport (ERROR ,
611
+ (errcode_for_file_access (),
612
+ errmsg ("could not read content of the file \"%s\" %m" ,
613
+ file_path )));
614
+
615
+ close (fd );
616
+
617
+ PG_RETURN_LSN (lsn );
618
+ }
0 commit comments