2020#include "access/genam.h"
2121#include "access/generic_xlog.h"
2222#include "catalog/pg_depend.h"
23+ #include "catalog/pg_tablespace.h"
2324#include "access/htup_details.h"
2425#include "miscadmin.h"
2526#include "storage/bufmgr.h"
2930#include "utils/array.h"
3031#include "utils/relfilenodemap.h"
3132#include "utils/builtins.h"
33+ #include "utils/pg_lsn.h"
3234#include <unistd.h>
3335#include <sys/stat.h>
3436
@@ -55,6 +57,11 @@ void SetPtrackClearLSN(bool set_invalid);
5557Datum pg_ptrack_test (PG_FUNCTION_ARGS );
5658Datum pg_ptrack_clear (PG_FUNCTION_ARGS );
5759Datum 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 );
5865
5966/*
6067 * Mark tracked memory block during recovery.
@@ -471,196 +478,100 @@ assign_ptrack_enable(bool newval, void *extra)
471478 SetPtrackClearLSN (true);
472479}
473480
474- /* Test ptrack file. */
481+ /* Clear all ptrack files */
475482Datum
476- pg_ptrack_test (PG_FUNCTION_ARGS )
483+ pg_ptrack_clear (PG_FUNCTION_ARGS )
477484{
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-
491485 if (!superuser () && !has_rolreplication (GetUserId ()))
492486 ereport (ERROR ,
493487 (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
494488 (errmsg ("must be superuser or replication role to clear ptrack files" ))));
495489
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 ();
625491
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 ();
638493}
639494
640- /* Clear all ptrack files */
495+ /* Read all ptrack files and clear them afterwards */
641496Datum
642- pg_ptrack_clear (PG_FUNCTION_ARGS )
497+ pg_ptrack_get_and_clear (PG_FUNCTION_ARGS )
643498{
644499 if (!superuser () && !has_rolreplication (GetUserId ()))
645500 ereport (ERROR ,
646501 (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
647502 (errmsg ("must be superuser or replication role to clear ptrack files" ))));
648503
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 )));
652505}
653506
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+ */
655513Datum
656- pg_ptrack_get_and_clear (PG_FUNCTION_ARGS )
514+ pg_ptrack_get_and_clear_db (PG_FUNCTION_ARGS )
657515{
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+
658520 if (!superuser () && !has_rolreplication (GetUserId ()))
659521 ereport (ERROR ,
660522 (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
661523 (errmsg ("must be superuser or replication role to clear ptrack files" ))));
662524
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+ }
664575}
665576
666577/*
@@ -672,3 +583,36 @@ ptrack_version(PG_FUNCTION_ARGS)
672583{
673584 PG_RETURN_TEXT_P (cstring_to_text (PTRACK_VERSION ));
674585}
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