-Date: Mon Oct 19 14:53:06 2020 +0300
-
- add ptrack 2.0
-
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 50ae1f16d0..721b926ad2 100644
--- a/src/backend/replication/basebackup.c
@@ -113,18 +107,6 @@ index 3ded2cdd71..3a596a59f7 100644
/* Flag successful completion of ProcessSyncRequests */
sync_in_progress = false;
}
-diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
-index 1683629ee3..d2fc154576 100644
---- a/src/backend/utils/misc/guc.c
-+++ b/src/backend/utils/misc/guc.c
-@@ -620,7 +620,6 @@ static char *recovery_target_xid_string;
- static char *recovery_target_name_string;
- static char *recovery_target_lsn_string;
-
--
- /* should be static, but commands/variable.c needs to get at this */
- char *role_string;
-
diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
index ffdc23945c..7ae95866ce 100644
--- a/src/bin/pg_checksums/pg_checksums.c
@@ -243,24 +225,6 @@ index 72e3352398..5c2e016501 100644
#define IsBootstrapProcessingMode() (Mode == BootstrapProcessing)
#define IsInitProcessingMode() (Mode == InitProcessing)
-diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h
-index 3c6f906683..a7355f7ad1 100644
---- a/src/include/port/pg_crc32c.h
-+++ b/src/include/port/pg_crc32c.h
-@@ -69,8 +69,11 @@ extern pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t le
- #define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF)
-
- extern pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len);
--extern pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len);
--
-+extern
-+#ifndef FRONTEND
-+PGDLLIMPORT
-+#endif
-+pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len);
- #ifdef USE_SSE42_CRC32C_WITH_RUNTIME_CHECK
- extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len);
- #endif
diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
index 5d28f59c1d..0d3f04d8af 100644
--- a/src/include/storage/copydir.h
@@ -307,3 +271,16 @@ index e16ab8e711..88da9686eb 100644
extern void InitSync(void);
extern void SyncPreCheckpoint(void);
extern void SyncPostCheckpoint(void);
+diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
+index 67b2ea9ee9b..e9a282d5647 100644
+--- a/src/tools/msvc/Mkvcbuild.pm
++++ b/src/tools/msvc/Mkvcbuild.pm
+@@ -34,7 +34,7 @@ my @unlink_on_exit;
+ # Set of variables for modules in contrib/ and src/test/modules/
+ my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' };
+ my @contrib_uselibpq = ('dblink', 'oid2name', 'postgres_fdw', 'vacuumlo');
+-my @contrib_uselibpgport = ('oid2name', 'pg_standby', 'vacuumlo');
++my @contrib_uselibpgport = ('oid2name', 'pg_standby', 'vacuumlo', 'ptrack');
+ my @contrib_uselibpgcommon = ('oid2name', 'pg_standby', 'vacuumlo');
+ my $contrib_extralibs = undef;
+ my $contrib_extraincludes = { 'dblink' => ['src/backend'] };
diff --git a/patches/REL_14_STABLE-ptrack-core.diff b/patches/REL_14_STABLE-ptrack-core.diff
new file mode 100644
index 0000000..88ffcdc
--- /dev/null
+++ b/patches/REL_14_STABLE-ptrack-core.diff
@@ -0,0 +1,286 @@
+diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
+index 50ae1f16d0..721b926ad2 100644
+--- a/src/backend/replication/basebackup.c
++++ b/src/backend/replication/basebackup.c
+@@ -233,6 +233,13 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ /*
++ * Skip all transient ptrack files, but do copy ptrack.map, since it may
++ * be successfully used immediately after backup. TODO: check, test?
++ */
++ {"ptrack.map.mmap", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+@@ -248,6 +255,11 @@ static const struct exclude_list_item noChecksumFiles[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
+index 0cf598dd0c..c9c44a4ae7 100644
+--- a/src/backend/storage/file/copydir.c
++++ b/src/backend/storage/file/copydir.c
+@@ -27,6 +27,8 @@
+ #include "storage/copydir.h"
+ #include "storage/fd.h"
+
++copydir_hook_type copydir_hook = NULL;
++
+ /*
+ * copydir: copy a directory
+ *
+@@ -78,6 +80,9 @@ copydir(char *fromdir, char *todir, bool recurse)
+ }
+ FreeDir(xldir);
+
++ if (copydir_hook)
++ copydir_hook(todir);
++
+ /*
+ * Be paranoid here and fsync all files to ensure the copy is really done.
+ * But if fsync is disabled, we're done.
+diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
+index 0eacd461cd..c2ef404a1a 100644
+--- a/src/backend/storage/smgr/md.c
++++ b/src/backend/storage/smgr/md.c
+@@ -87,6 +87,8 @@ typedef struct _MdfdVec
+
+ static MemoryContext MdCxt; /* context for all MdfdVec objects */
+
++mdextend_hook_type mdextend_hook = NULL;
++mdwrite_hook_type mdwrite_hook = NULL;
+
+ /* Populate a file tag describing an md.c segment file. */
+ #define INIT_MD_FILETAG(a,xx_rnode,xx_forknum,xx_segno) \
+@@ -435,6 +437,9 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ register_dirty_segment(reln, forknum, v);
+
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
++
++ if (mdextend_hook)
++ mdextend_hook(reln->smgr_rnode, forknum, blocknum);
+ }
+
+ /*
+@@ -721,6 +726,9 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+
+ if (!skipFsync && !SmgrIsTemp(reln))
+ register_dirty_segment(reln, forknum, v);
++
++ if (mdwrite_hook)
++ mdwrite_hook(reln->smgr_rnode, forknum, blocknum);
+ }
+
+ /*
+diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
+index 3ded2cdd71..3a596a59f7 100644
+--- a/src/backend/storage/sync/sync.c
++++ b/src/backend/storage/sync/sync.c
+@@ -75,6 +75,8 @@ static MemoryContext pendingOpsCxt; /* context for the above */
+ static CycleCtr sync_cycle_ctr = 0;
+ static CycleCtr checkpoint_cycle_ctr = 0;
+
++ProcessSyncRequests_hook_type ProcessSyncRequests_hook = NULL;
++
+ /* Intervals for calling AbsorbSyncRequests */
+ #define FSYNCS_PER_ABSORB 10
+ #define UNLINKS_PER_ABSORB 10
+@@ -420,6 +422,9 @@ ProcessSyncRequests(void)
+ CheckpointStats.ckpt_longest_sync = longest;
+ CheckpointStats.ckpt_agg_sync_time = total_elapsed;
+
++ if (ProcessSyncRequests_hook)
++ ProcessSyncRequests_hook();
++
+ /* Flag successful completion of ProcessSyncRequests */
+ sync_in_progress = false;
+ }
+diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
+index ffdc23945c..7ae95866ce 100644
+--- a/src/bin/pg_checksums/pg_checksums.c
++++ b/src/bin/pg_checksums/pg_checksums.c
+@@ -114,6 +114,11 @@ static const struct exclude_list_item skip[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
+index 233441837f..cf7bd073bf 100644
+--- a/src/bin/pg_resetwal/pg_resetwal.c
++++ b/src/bin/pg_resetwal/pg_resetwal.c
+@@ -84,6 +84,7 @@ static void RewriteControlFile(void);
+ static void FindEndOfXLOG(void);
+ static void KillExistingXLOG(void);
+ static void KillExistingArchiveStatus(void);
++static void KillExistingPtrack(void);
+ static void WriteEmptyXLOG(void);
+ static void usage(void);
+
+@@ -513,6 +514,7 @@ main(int argc, char *argv[])
+ RewriteControlFile();
+ KillExistingXLOG();
+ KillExistingArchiveStatus();
++ KillExistingPtrack();
+ WriteEmptyXLOG();
+
+ printf(_("Write-ahead log reset\n"));
+@@ -1102,6 +1104,53 @@ KillExistingArchiveStatus(void)
+ }
+ }
+
++/*
++ * Remove existing ptrack files
++ */
++static void
++KillExistingPtrack(void)
++{
++#define PTRACKDIR "global"
++
++ DIR *xldir;
++ struct dirent *xlde;
++ char path[MAXPGPATH + sizeof(PTRACKDIR)];
++
++ xldir = opendir(PTRACKDIR);
++ if (xldir == NULL)
++ {
++ pg_log_error("could not open directory \"%s\": %m", PTRACKDIR);
++ exit(1);
++ }
++
++ while (errno = 0, (xlde = readdir(xldir)) != NULL)
++ {
++ if (strcmp(xlde->d_name, "ptrack.map.mmap") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map.tmp") == 0)
++ {
++ snprintf(path, sizeof(path), "%s/%s", PTRACKDIR, xlde->d_name);
++ if (unlink(path) < 0)
++ {
++ pg_log_error("could not delete file \"%s\": %m", path);
++ exit(1);
++ }
++ }
++ }
++
++ if (errno)
++ {
++ pg_log_error("could not read directory \"%s\": %m", PTRACKDIR);
++ exit(1);
++ }
++
++ if (closedir(xldir))
++ {
++ pg_log_error("could not close directory \"%s\": %m", PTRACKDIR);
++ exit(1);
++ }
++}
++
+
+ /*
+ * Write an empty XLOG file, containing only the checkpoint record
+diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
+index fbb97b5cf1..6cd7f2ae3e 100644
+--- a/src/bin/pg_rewind/filemap.c
++++ b/src/bin/pg_rewind/filemap.c
+@@ -124,6 +124,10 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
+index 72e3352398..5c2e016501 100644
+--- a/src/include/miscadmin.h
++++ b/src/include/miscadmin.h
+@@ -388,7 +388,7 @@ typedef enum ProcessingMode
+ NormalProcessing /* normal processing */
+ } ProcessingMode;
+
+-extern ProcessingMode Mode;
++extern PGDLLIMPORT ProcessingMode Mode;
+
+ #define IsBootstrapProcessingMode() (Mode == BootstrapProcessing)
+ #define IsInitProcessingMode() (Mode == InitProcessing)
+diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
+index 5d28f59c1d..0d3f04d8af 100644
+--- a/src/include/storage/copydir.h
++++ b/src/include/storage/copydir.h
+@@ -13,6 +13,9 @@
+ #ifndef COPYDIR_H
+ #define COPYDIR_H
+
++typedef void (*copydir_hook_type) (const char *path);
++extern PGDLLIMPORT copydir_hook_type copydir_hook;
++
+ extern void copydir(char *fromdir, char *todir, bool recurse);
+ extern void copy_file(char *fromfile, char *tofile);
+
+diff --git a/src/include/storage/md.h b/src/include/storage/md.h
+index 07fd1bb7d0..5294811bc8 100644
+--- a/src/include/storage/md.h
++++ b/src/include/storage/md.h
+@@ -19,6 +19,13 @@
+ #include "storage/smgr.h"
+ #include "storage/sync.h"
+
++typedef void (*mdextend_hook_type) (RelFileNodeBackend smgr_rnode,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdextend_hook_type mdextend_hook;
++typedef void (*mdwrite_hook_type) (RelFileNodeBackend smgr_rnode,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdwrite_hook_type mdwrite_hook;
++
+ /* md storage manager functionality */
+ extern void mdinit(void);
+ extern void mdopen(SMgrRelation reln);
+diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h
+index e16ab8e711..88da9686eb 100644
+--- a/src/include/storage/sync.h
++++ b/src/include/storage/sync.h
+@@ -50,6 +50,9 @@ typedef struct FileTag
+ uint32 segno;
+ } FileTag;
+
++typedef void (*ProcessSyncRequests_hook_type) (void);
++extern PGDLLIMPORT ProcessSyncRequests_hook_type ProcessSyncRequests_hook;
++
+ extern void InitSync(void);
+ extern void SyncPreCheckpoint(void);
+ extern void SyncPostCheckpoint(void);
+diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
+index 9b6539fb15d..4b2bcdb6b88 100644
+--- a/src/tools/msvc/Mkvcbuild.pm
++++ b/src/tools/msvc/Mkvcbuild.pm
+@@ -38,7 +38,7 @@ my @unlink_on_exit;
+ my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' };
+ my @contrib_uselibpq =
+ ('dblink', 'oid2name', 'postgres_fdw', 'vacuumlo', 'libpq_pipeline');
+-my @contrib_uselibpgport = ('libpq_pipeline', 'oid2name', 'vacuumlo');
++my @contrib_uselibpgport = ('libpq_pipeline', 'oid2name', 'vacuumlo', 'ptrack');
+ my @contrib_uselibpgcommon = ('libpq_pipeline', 'oid2name', 'vacuumlo');
+ my $contrib_extralibs = { 'libpq_pipeline' => ['ws2_32.lib'] };
+ my $contrib_extraincludes = { 'dblink' => ['src/backend'] };
diff --git a/patches/REL_15_STABLE-ptrack-core.diff b/patches/REL_15_STABLE-ptrack-core.diff
new file mode 100644
index 0000000..2adc5f3
--- /dev/null
+++ b/patches/REL_15_STABLE-ptrack-core.diff
@@ -0,0 +1,248 @@
+diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
+index cc16c4b331f..69b1af16cf5 100644
+--- a/src/backend/backup/basebackup.c
++++ b/src/backend/backup/basebackup.c
+@@ -197,6 +197,13 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ /*
++ * Skip all transient ptrack files, but do copy ptrack.map, since it may
++ * be successfully used immediately after backup. TODO: check, test?
++ */
++ {"ptrack.map.mmap", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+@@ -212,6 +219,11 @@ static const struct exclude_list_item noChecksumFiles[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
+index 658fd95ba95..eee38eba176 100644
+--- a/src/backend/storage/file/copydir.c
++++ b/src/backend/storage/file/copydir.c
+@@ -27,6 +27,8 @@
+ #include "storage/copydir.h"
+ #include "storage/fd.h"
+
++copydir_hook_type copydir_hook = NULL;
++
+ /*
+ * copydir: copy a directory
+ *
+@@ -78,6 +80,9 @@ copydir(char *fromdir, char *todir, bool recurse)
+ }
+ FreeDir(xldir);
+
++ if (copydir_hook)
++ copydir_hook(todir);
++
+ /*
+ * Be paranoid here and fsync all files to ensure the copy is really done.
+ * But if fsync is disabled, we're done.
+diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
+index a0fc60b32a3..7f091951c0d 100644
+--- a/src/backend/storage/smgr/md.c
++++ b/src/backend/storage/smgr/md.c
+@@ -87,6 +87,8 @@ typedef struct _MdfdVec
+
+ static MemoryContext MdCxt; /* context for all MdfdVec objects */
+
++mdextend_hook_type mdextend_hook = NULL;
++mdwrite_hook_type mdwrite_hook = NULL;
+
+ /* Populate a file tag describing an md.c segment file. */
+ #define INIT_MD_FILETAG(a,xx_rnode,xx_forknum,xx_segno) \
+@@ -484,6 +486,9 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ register_dirty_segment(reln, forknum, v);
+
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
++
++ if (mdextend_hook)
++ mdextend_hook(reln->smgr_rnode, forknum, blocknum);
+ }
+
+ /*
+@@ -773,6 +778,9 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+
+ if (!skipFsync && !SmgrIsTemp(reln))
+ register_dirty_segment(reln, forknum, v);
++
++ if (mdwrite_hook)
++ mdwrite_hook(reln->smgr_rnode, forknum, blocknum);
+ }
+
+ /*
+diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
+index e1fb6310038..76d75680b31 100644
+--- a/src/backend/storage/sync/sync.c
++++ b/src/backend/storage/sync/sync.c
+@@ -81,6 +81,8 @@ static MemoryContext pendingOpsCxt; /* context for the above */
+ static CycleCtr sync_cycle_ctr = 0;
+ static CycleCtr checkpoint_cycle_ctr = 0;
+
++ProcessSyncRequests_hook_type ProcessSyncRequests_hook = NULL;
++
+ /* Intervals for calling AbsorbSyncRequests */
+ #define FSYNCS_PER_ABSORB 10
+ #define UNLINKS_PER_ABSORB 10
+@@ -477,6 +479,9 @@ ProcessSyncRequests(void)
+ CheckpointStats.ckpt_longest_sync = longest;
+ CheckpointStats.ckpt_agg_sync_time = total_elapsed;
+
++ if (ProcessSyncRequests_hook)
++ ProcessSyncRequests_hook();
++
+ /* Flag successful completion of ProcessSyncRequests */
+ sync_in_progress = false;
+ }
+diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
+index 21dfe1b6ee5..266ac1ef40a 100644
+--- a/src/bin/pg_checksums/pg_checksums.c
++++ b/src/bin/pg_checksums/pg_checksums.c
+@@ -118,6 +118,11 @@ static const struct exclude_list_item skip[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
+index d4772a29650..3318f64359d 100644
+--- a/src/bin/pg_resetwal/pg_resetwal.c
++++ b/src/bin/pg_resetwal/pg_resetwal.c
+@@ -85,6 +85,7 @@ static void RewriteControlFile(void);
+ static void FindEndOfXLOG(void);
+ static void KillExistingXLOG(void);
+ static void KillExistingArchiveStatus(void);
++static void KillExistingPtrack(void);
+ static void WriteEmptyXLOG(void);
+ static void usage(void);
+
+@@ -488,6 +489,7 @@ main(int argc, char *argv[])
+ RewriteControlFile();
+ KillExistingXLOG();
+ KillExistingArchiveStatus();
++ KillExistingPtrack();
+ WriteEmptyXLOG();
+
+ printf(_("Write-ahead log reset\n"));
+@@ -1036,6 +1038,41 @@ KillExistingArchiveStatus(void)
+ pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
+ }
+
++/*
++ * Remove existing ptrack files
++ */
++static void
++KillExistingPtrack(void)
++{
++#define PTRACKDIR "global"
++
++ DIR *xldir;
++ struct dirent *xlde;
++ char path[MAXPGPATH + sizeof(PTRACKDIR)];
++
++ xldir = opendir(PTRACKDIR);
++ if (xldir == NULL)
++ pg_fatal("could not open directory \"%s\": %m", PTRACKDIR);
++
++ while (errno = 0, (xlde = readdir(xldir)) != NULL)
++ {
++ if (strcmp(xlde->d_name, "ptrack.map.mmap") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map.tmp") == 0)
++ {
++ snprintf(path, sizeof(path), "%s/%s", PTRACKDIR, xlde->d_name);
++ if (unlink(path) < 0)
++ pg_fatal("could not delete file \"%s\": %m", path);
++ }
++ }
++
++ if (errno)
++ pg_fatal("could not read directory \"%s\": %m", PTRACKDIR);
++
++ if (closedir(xldir))
++ pg_fatal("could not close directory \"%s\": %m", PTRACKDIR);
++}
++
+
+ /*
+ * Write an empty XLOG file, containing only the checkpoint record
+diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
+index 62529310415..b496f54fb06 100644
+--- a/src/bin/pg_rewind/filemap.c
++++ b/src/bin/pg_rewind/filemap.c
+@@ -157,6 +157,10 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
+index 50a26edeb06..af1602f5154 100644
+--- a/src/include/storage/copydir.h
++++ b/src/include/storage/copydir.h
+@@ -13,6 +13,9 @@
+ #ifndef COPYDIR_H
+ #define COPYDIR_H
+
++typedef void (*copydir_hook_type) (const char *path);
++extern PGDLLIMPORT copydir_hook_type copydir_hook;
++
+ extern void copydir(char *fromdir, char *todir, bool recurse);
+ extern void copy_file(char *fromfile, char *tofile);
+
+diff --git a/src/include/storage/md.h b/src/include/storage/md.h
+index ffffa40db71..3ff98e0bf01 100644
+--- a/src/include/storage/md.h
++++ b/src/include/storage/md.h
+@@ -19,6 +19,13 @@
+ #include "storage/smgr.h"
+ #include "storage/sync.h"
+
++typedef void (*mdextend_hook_type) (RelFileNodeBackend smgr_rnode,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdextend_hook_type mdextend_hook;
++typedef void (*mdwrite_hook_type) (RelFileNodeBackend smgr_rnode,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdwrite_hook_type mdwrite_hook;
++
+ /* md storage manager functionality */
+ extern void mdinit(void);
+ extern void mdopen(SMgrRelation reln);
+diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h
+index 9737e1eb67c..914ad86328f 100644
+--- a/src/include/storage/sync.h
++++ b/src/include/storage/sync.h
+@@ -55,6 +55,9 @@ typedef struct FileTag
+ uint32 segno;
+ } FileTag;
+
++typedef void (*ProcessSyncRequests_hook_type) (void);
++extern PGDLLIMPORT ProcessSyncRequests_hook_type ProcessSyncRequests_hook;
++
+ extern void InitSync(void);
+ extern void SyncPreCheckpoint(void);
+ extern void SyncPostCheckpoint(void);
diff --git a/patches/REL_16_STABLE-ptrack-core.diff b/patches/REL_16_STABLE-ptrack-core.diff
new file mode 100644
index 0000000..04cf8a4
--- /dev/null
+++ b/patches/REL_16_STABLE-ptrack-core.diff
@@ -0,0 +1,261 @@
+diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
+index 45be21131c5..134e677f9d1 100644
+--- a/src/backend/backup/basebackup.c
++++ b/src/backend/backup/basebackup.c
+@@ -199,6 +199,13 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ /*
++ * Skip all transient ptrack files, but do copy ptrack.map, since it may
++ * be successfully used immediately after backup. TODO: check, test?
++ */
++ {"ptrack.map.mmap", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+@@ -214,6 +221,11 @@ static const struct exclude_list_item noChecksumFiles[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
+index e04bc3941ae..996b5de6169 100644
+--- a/src/backend/storage/file/copydir.c
++++ b/src/backend/storage/file/copydir.c
+@@ -27,6 +27,8 @@
+ #include "storage/copydir.h"
+ #include "storage/fd.h"
+
++copydir_hook_type copydir_hook = NULL;
++
+ /*
+ * copydir: copy a directory
+ *
+@@ -75,6 +77,9 @@ copydir(const char *fromdir, const char *todir, bool recurse)
+ }
+ FreeDir(xldir);
+
++ if (copydir_hook)
++ copydir_hook(todir);
++
+ /*
+ * Be paranoid here and fsync all files to ensure the copy is really done.
+ * But if fsync is disabled, we're done.
+diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
+index fdecbad1709..f849d00161e 100644
+--- a/src/backend/storage/smgr/md.c
++++ b/src/backend/storage/smgr/md.c
+@@ -87,6 +87,8 @@ typedef struct _MdfdVec
+
+ static MemoryContext MdCxt; /* context for all MdfdVec objects */
+
++mdextend_hook_type mdextend_hook = NULL;
++mdwrite_hook_type mdwrite_hook = NULL;
+
+ /* Populate a file tag describing an md.c segment file. */
+ #define INIT_MD_FILETAG(a,xx_rlocator,xx_forknum,xx_segno) \
+@@ -515,6 +517,9 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ register_dirty_segment(reln, forknum, v);
+
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
++
++ if (mdextend_hook)
++ mdextend_hook(reln->smgr_rlocator, forknum, blocknum);
+ }
+
+ /*
+@@ -622,6 +627,12 @@ mdzeroextend(SMgrRelation reln, ForkNumber forknum,
+
+ remblocks -= numblocks;
+ curblocknum += numblocks;
++
++ if (mdextend_hook)
++ {
++ for (; blocknum < curblocknum; blocknum++)
++ mdextend_hook(reln->smgr_rlocator, forknum, blocknum);
++ }
+ }
+ }
+
+@@ -867,6 +878,9 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+
+ if (!skipFsync && !SmgrIsTemp(reln))
+ register_dirty_segment(reln, forknum, v);
++
++ if (mdwrite_hook)
++ mdwrite_hook(reln->smgr_rlocator, forknum, blocknum);
+ }
+
+ /*
+diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
+index 04fcb06056d..22bf179f560 100644
+--- a/src/backend/storage/sync/sync.c
++++ b/src/backend/storage/sync/sync.c
+@@ -79,6 +79,8 @@ static MemoryContext pendingOpsCxt; /* context for the above */
+ static CycleCtr sync_cycle_ctr = 0;
+ static CycleCtr checkpoint_cycle_ctr = 0;
+
++ProcessSyncRequests_hook_type ProcessSyncRequests_hook = NULL;
++
+ /* Intervals for calling AbsorbSyncRequests */
+ #define FSYNCS_PER_ABSORB 10
+ #define UNLINKS_PER_ABSORB 10
+@@ -475,6 +477,9 @@ ProcessSyncRequests(void)
+ CheckpointStats.ckpt_longest_sync = longest;
+ CheckpointStats.ckpt_agg_sync_time = total_elapsed;
+
++ if (ProcessSyncRequests_hook)
++ ProcessSyncRequests_hook();
++
+ /* Flag successful completion of ProcessSyncRequests */
+ sync_in_progress = false;
+ }
+diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
+index 19eb67e4854..008a7acc9f0 100644
+--- a/src/bin/pg_checksums/pg_checksums.c
++++ b/src/bin/pg_checksums/pg_checksums.c
+@@ -118,6 +118,11 @@ static const struct exclude_list_item skip[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
+index e7ef2b8bd0c..ca7f8cdbc2f 100644
+--- a/src/bin/pg_resetwal/pg_resetwal.c
++++ b/src/bin/pg_resetwal/pg_resetwal.c
+@@ -85,6 +85,7 @@ static void RewriteControlFile(void);
+ static void FindEndOfXLOG(void);
+ static void KillExistingXLOG(void);
+ static void KillExistingArchiveStatus(void);
++static void KillExistingPtrack(void);
+ static void WriteEmptyXLOG(void);
+ static void usage(void);
+
+@@ -488,6 +489,7 @@ main(int argc, char *argv[])
+ RewriteControlFile();
+ KillExistingXLOG();
+ KillExistingArchiveStatus();
++ KillExistingPtrack();
+ WriteEmptyXLOG();
+
+ printf(_("Write-ahead log reset\n"));
+@@ -1029,6 +1031,41 @@ KillExistingArchiveStatus(void)
+ pg_fatal("could not close directory \"%s\": %m", ARCHSTATDIR);
+ }
+
++/*
++ * Remove existing ptrack files
++ */
++static void
++KillExistingPtrack(void)
++{
++#define PTRACKDIR "global"
++
++ DIR *xldir;
++ struct dirent *xlde;
++ char path[MAXPGPATH + sizeof(PTRACKDIR)];
++
++ xldir = opendir(PTRACKDIR);
++ if (xldir == NULL)
++ pg_fatal("could not open directory \"%s\": %m", PTRACKDIR);
++
++ while (errno = 0, (xlde = readdir(xldir)) != NULL)
++ {
++ if (strcmp(xlde->d_name, "ptrack.map.mmap") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map.tmp") == 0)
++ {
++ snprintf(path, sizeof(path), "%s/%s", PTRACKDIR, xlde->d_name);
++ if (unlink(path) < 0)
++ pg_fatal("could not delete file \"%s\": %m", path);
++ }
++ }
++
++ if (errno)
++ pg_fatal("could not read directory \"%s\": %m", PTRACKDIR);
++
++ if (closedir(xldir))
++ pg_fatal("could not close directory \"%s\": %m", PTRACKDIR);
++}
++
+
+ /*
+ * Write an empty XLOG file, containing only the checkpoint record
+diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
+index bd5c598e200..a568156c5fb 100644
+--- a/src/bin/pg_rewind/filemap.c
++++ b/src/bin/pg_rewind/filemap.c
+@@ -157,6 +157,10 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
+index a8be5b21e0b..020874f96cd 100644
+--- a/src/include/storage/copydir.h
++++ b/src/include/storage/copydir.h
+@@ -13,6 +13,9 @@
+ #ifndef COPYDIR_H
+ #define COPYDIR_H
+
++typedef void (*copydir_hook_type) (const char *path);
++extern PGDLLIMPORT copydir_hook_type copydir_hook;
++
+ extern void copydir(const char *fromdir, const char *todir, bool recurse);
+ extern void copy_file(const char *fromfile, const char *tofile);
+
+diff --git a/src/include/storage/md.h b/src/include/storage/md.h
+index 941879ee6a8..24738aeecd0 100644
+--- a/src/include/storage/md.h
++++ b/src/include/storage/md.h
+@@ -19,6 +19,13 @@
+ #include "storage/smgr.h"
+ #include "storage/sync.h"
+
++typedef void (*mdextend_hook_type) (RelFileLocatorBackend smgr_rlocator,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdextend_hook_type mdextend_hook;
++typedef void (*mdwrite_hook_type) (RelFileLocatorBackend smgr_rlocator,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdwrite_hook_type mdwrite_hook;
++
+ /* md storage manager functionality */
+ extern void mdinit(void);
+ extern void mdopen(SMgrRelation reln);
+diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h
+index cfbcfa6797d..2a432440db9 100644
+--- a/src/include/storage/sync.h
++++ b/src/include/storage/sync.h
+@@ -55,6 +55,9 @@ typedef struct FileTag
+ uint32 segno;
+ } FileTag;
+
++typedef void (*ProcessSyncRequests_hook_type) (void);
++extern PGDLLIMPORT ProcessSyncRequests_hook_type ProcessSyncRequests_hook;
++
+ extern void InitSync(void);
+ extern void SyncPreCheckpoint(void);
+ extern void SyncPostCheckpoint(void);
diff --git a/patches/master-ptrack-core.diff b/patches/master-ptrack-core.diff
new file mode 100644
index 0000000..3357a2b
--- /dev/null
+++ b/patches/master-ptrack-core.diff
@@ -0,0 +1,294 @@
+diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
+index 34a2c71812..2d73d8023e 100644
+--- a/src/backend/access/transam/xlog.c
++++ b/src/backend/access/transam/xlog.c
+@@ -135,6 +135,7 @@ int wal_retrieve_retry_interval = 5000;
+ int max_slot_wal_keep_size_mb = -1;
+ int wal_decode_buffer_size = 512 * 1024;
+ bool track_wal_io_timing = false;
++backup_checkpoint_request_hook_type backup_checkpoint_request_hook = NULL;
+
+ #ifdef WAL_DEBUG
+ bool XLOG_DEBUG = false;
+@@ -8801,6 +8802,12 @@ do_pg_backup_start(const char *backupidstr, bool fast, List **tablespaces,
+ {
+ bool checkpointfpw;
+
++ /*
++ * Before we call RequestCheckpoint() we need to set
++ * init_lsn for ptrack map
++ */
++ if (backup_checkpoint_request_hook)
++ backup_checkpoint_request_hook();
+ /*
+ * Force a CHECKPOINT. Aside from being necessary to prevent torn
+ * page problems, this guarantees that two successive backup runs
+diff --git a/src/backend/backup/basebackup.c b/src/backend/backup/basebackup.c
+index 9a2bf59e84..ade9115651 100644
+--- a/src/backend/backup/basebackup.c
++++ b/src/backend/backup/basebackup.c
+@@ -220,6 +220,13 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ /*
++ * Skip all transient ptrack files, but do copy ptrack.map, since it may
++ * be successfully used immediately after backup. TODO: check, test?
++ */
++ {"ptrack.map.mmap", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
+index d4fbe54207..b108416c70 100644
+--- a/src/backend/storage/file/copydir.c
++++ b/src/backend/storage/file/copydir.c
+@@ -27,6 +27,8 @@
+ #include "storage/copydir.h"
+ #include "storage/fd.h"
+
++copydir_hook_type copydir_hook = NULL;
++
+ /*
+ * copydir: copy a directory
+ *
+@@ -75,6 +77,9 @@ copydir(const char *fromdir, const char *todir, bool recurse)
+ }
+ FreeDir(xldir);
+
++ if (copydir_hook)
++ copydir_hook(todir);
++
+ /*
+ * Be paranoid here and fsync all files to ensure the copy is really done.
+ * But if fsync is disabled, we're done.
+diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
+index bf0f3ca76d..7d9833a360 100644
+--- a/src/backend/storage/smgr/md.c
++++ b/src/backend/storage/smgr/md.c
+@@ -85,6 +85,8 @@ typedef struct _MdfdVec
+
+ static MemoryContext MdCxt; /* context for all MdfdVec objects */
+
++mdextend_hook_type mdextend_hook = NULL;
++mdwrite_hook_type mdwrite_hook = NULL;
+
+ /* Populate a file tag describing an md.c segment file. */
+ #define INIT_MD_FILETAG(a,xx_rlocator,xx_forknum,xx_segno) \
+@@ -513,6 +515,9 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+ register_dirty_segment(reln, forknum, v);
+
+ Assert(_mdnblocks(reln, forknum, v) <= ((BlockNumber) RELSEG_SIZE));
++
++ if (mdextend_hook)
++ mdextend_hook(reln->smgr_rlocator, forknum, blocknum);
+ }
+
+ /*
+@@ -620,6 +625,12 @@ mdzeroextend(SMgrRelation reln, ForkNumber forknum,
+
+ remblocks -= numblocks;
+ curblocknum += numblocks;
++
++ if (mdextend_hook)
++ {
++ for (; blocknum < curblocknum; blocknum++)
++ mdextend_hook(reln->smgr_rlocator, forknum, blocknum);
++ }
+ }
+ }
+
+@@ -1015,7 +1026,14 @@ mdwritev(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
+
+ nblocks -= nblocks_this_segment;
+ buffers += nblocks_this_segment;
+- blocknum += nblocks_this_segment;
++
++ if (mdwrite_hook)
++ {
++ for (; nblocks_this_segment--; blocknum++)
++ mdwrite_hook(reln->smgr_rlocator, forknum, blocknum);
++ }
++ else
++ blocknum += nblocks_this_segment;
+ }
+ }
+
+diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
+index ab7137d0ff..bc40a763c0 100644
+--- a/src/backend/storage/sync/sync.c
++++ b/src/backend/storage/sync/sync.c
+@@ -74,6 +74,8 @@ static MemoryContext pendingOpsCxt; /* context for the above */
+ static CycleCtr sync_cycle_ctr = 0;
+ static CycleCtr checkpoint_cycle_ctr = 0;
+
++ProcessSyncRequests_hook_type ProcessSyncRequests_hook = NULL;
++
+ /* Intervals for calling AbsorbSyncRequests */
+ #define FSYNCS_PER_ABSORB 10
+ #define UNLINKS_PER_ABSORB 10
+@@ -470,6 +472,9 @@ ProcessSyncRequests(void)
+ CheckpointStats.ckpt_longest_sync = longest;
+ CheckpointStats.ckpt_agg_sync_time = total_elapsed;
+
++ if (ProcessSyncRequests_hook)
++ ProcessSyncRequests_hook();
++
+ /* Flag successful completion of ProcessSyncRequests */
+ sync_in_progress = false;
+ }
+diff --git a/src/bin/pg_checksums/pg_checksums.c b/src/bin/pg_checksums/pg_checksums.c
+index 9e6fd435f6..f2180b9f6d 100644
+--- a/src/bin/pg_checksums/pg_checksums.c
++++ b/src/bin/pg_checksums/pg_checksums.c
+@@ -110,6 +110,11 @@ static const struct exclude_list_item skip[] = {
+ {"pg_filenode.map", false},
+ {"pg_internal.init", true},
+ {"PG_VERSION", false},
++
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ #ifdef EXEC_BACKEND
+ {"config_exec_params", true},
+ #endif
+diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
+index e9dcb5a6d8..844b04d5e1 100644
+--- a/src/bin/pg_resetwal/pg_resetwal.c
++++ b/src/bin/pg_resetwal/pg_resetwal.c
+@@ -86,6 +86,7 @@ static void FindEndOfXLOG(void);
+ static void KillExistingXLOG(void);
+ static void KillExistingArchiveStatus(void);
+ static void KillExistingWALSummaries(void);
++static void KillExistingPtrack(void);
+ static void WriteEmptyXLOG(void);
+ static void usage(void);
+
+@@ -495,6 +496,7 @@ main(int argc, char *argv[])
+ KillExistingXLOG();
+ KillExistingArchiveStatus();
+ KillExistingWALSummaries();
++ KillExistingPtrack();
+ WriteEmptyXLOG();
+
+ printf(_("Write-ahead log reset\n"));
+@@ -998,6 +1000,41 @@ KillExistingXLOG(void)
+ pg_fatal("could not close directory \"%s\": %m", XLOGDIR);
+ }
+
++/*
++ * Remove existing ptrack files
++ */
++static void
++KillExistingPtrack(void)
++{
++#define PTRACKDIR "global"
++
++ DIR *xldir;
++ struct dirent *xlde;
++ char path[MAXPGPATH + sizeof(PTRACKDIR)];
++
++ xldir = opendir(PTRACKDIR);
++ if (xldir == NULL)
++ pg_fatal("could not open directory \"%s\": %m", PTRACKDIR);
++
++ while (errno = 0, (xlde = readdir(xldir)) != NULL)
++ {
++ if (strcmp(xlde->d_name, "ptrack.map.mmap") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map") == 0 ||
++ strcmp(xlde->d_name, "ptrack.map.tmp") == 0)
++ {
++ snprintf(path, sizeof(path), "%s/%s", PTRACKDIR, xlde->d_name);
++ if (unlink(path) < 0)
++ pg_fatal("could not delete file \"%s\": %m", path);
++ }
++ }
++
++ if (errno)
++ pg_fatal("could not read directory \"%s\": %m", PTRACKDIR);
++
++ if (closedir(xldir))
++ pg_fatal("could not close directory \"%s\": %m", PTRACKDIR);
++}
++
+
+ /*
+ * Remove existing archive status files
+diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
+index 4458324c9d..7d857467f7 100644
+--- a/src/bin/pg_rewind/filemap.c
++++ b/src/bin/pg_rewind/filemap.c
+@@ -156,6 +156,10 @@ static const struct exclude_list_item excludeFiles[] =
+ {"postmaster.pid", false},
+ {"postmaster.opts", false},
+
++ {"ptrack.map.mmap", false},
++ {"ptrack.map", false},
++ {"ptrack.map.tmp", false},
++
+ /* end of list */
+ {NULL, false}
+ };
+diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
+index 76787a8267..2c662f4022 100644
+--- a/src/include/access/xlog.h
++++ b/src/include/access/xlog.h
+@@ -57,6 +57,9 @@ extern PGDLLIMPORT int wal_decode_buffer_size;
+
+ extern PGDLLIMPORT int CheckPointSegments;
+
++typedef void (*backup_checkpoint_request_hook_type) (void);
++extern PGDLLIMPORT backup_checkpoint_request_hook_type backup_checkpoint_request_hook;
++
+ /* Archive modes */
+ typedef enum ArchiveMode
+ {
+diff --git a/src/include/storage/copydir.h b/src/include/storage/copydir.h
+index a25e258f47..b20b9c76e8 100644
+--- a/src/include/storage/copydir.h
++++ b/src/include/storage/copydir.h
+@@ -13,6 +13,9 @@
+ #ifndef COPYDIR_H
+ #define COPYDIR_H
+
++typedef void (*copydir_hook_type) (const char *path);
++extern PGDLLIMPORT copydir_hook_type copydir_hook;
++
+ extern void copydir(const char *fromdir, const char *todir, bool recurse);
+ extern void copy_file(const char *fromfile, const char *tofile);
+
+diff --git a/src/include/storage/md.h b/src/include/storage/md.h
+index 620f10abde..b36936871b 100644
+--- a/src/include/storage/md.h
++++ b/src/include/storage/md.h
+@@ -19,6 +19,13 @@
+ #include "storage/smgr.h"
+ #include "storage/sync.h"
+
++typedef void (*mdextend_hook_type) (RelFileLocatorBackend smgr_rlocator,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdextend_hook_type mdextend_hook;
++typedef void (*mdwrite_hook_type) (RelFileLocatorBackend smgr_rlocator,
++ ForkNumber forknum, BlockNumber blocknum);
++extern PGDLLIMPORT mdwrite_hook_type mdwrite_hook;
++
+ /* md storage manager functionality */
+ extern void mdinit(void);
+ extern void mdopen(SMgrRelation reln);
+diff --git a/src/include/storage/sync.h b/src/include/storage/sync.h
+index 9dee8fa6e5..348ed53e4e 100644
+--- a/src/include/storage/sync.h
++++ b/src/include/storage/sync.h
+@@ -55,6 +55,9 @@ typedef struct FileTag
+ uint64 segno;
+ } FileTag;
+
++typedef void (*ProcessSyncRequests_hook_type) (void);
++extern PGDLLIMPORT ProcessSyncRequests_hook_type ProcessSyncRequests_hook;
++
+ extern void InitSync(void);
+ extern void SyncPreCheckpoint(void);
+ extern void SyncPostCheckpoint(void);
diff --git a/ptrack--2.1--2.2.sql b/ptrack--2.1--2.2.sql
index b09c15e..da897b6 100644
--- a/ptrack--2.1--2.2.sql
+++ b/ptrack--2.1--2.2.sql
@@ -1,7 +1,7 @@
/* ptrack/ptrack--2.1--2.2.sql */
-- Complain if script is sourced in psql, rather than via ALTER EXTENSION
-\echo Use "ALTER EXTENSION ptrack UPDATE;" to load this file.\ quit
+\echo Use "ALTER EXTENSION ptrack UPDATE;" to load this file. \quit
DROP FUNCTION ptrack_get_pagemapset(start_lsn pg_lsn);
CREATE FUNCTION ptrack_get_pagemapset(start_lsn pg_lsn)
diff --git a/ptrack--2.2--2.3.sql b/ptrack--2.2--2.3.sql
new file mode 100644
index 0000000..6c5f574
--- /dev/null
+++ b/ptrack--2.2--2.3.sql
@@ -0,0 +1,5 @@
+/* ptrack/ptrack--2.2--2.3.sql */
+
+-- Complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION ptrack UPDATE;" to load this file. \quit
+
diff --git a/ptrack--2.3--2.4.sql b/ptrack--2.3--2.4.sql
new file mode 100644
index 0000000..780bba5
--- /dev/null
+++ b/ptrack--2.3--2.4.sql
@@ -0,0 +1,5 @@
+/* ptrack/ptrack--2.3--2.4.sql */
+
+-- Complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION ptrack UPDATE;" to load this file. \quit
+
diff --git a/ptrack.c b/ptrack.c
index 66f5676..e2f3627 100644
--- a/ptrack.c
+++ b/ptrack.c
@@ -2,14 +2,13 @@
* ptrack.c
* Block level incremental backup engine
*
- * Copyright (c) 2019-2020, Postgres Professional
+ * Copyright (c) 2019-2022, Postgres Professional
*
* IDENTIFICATION
* ptrack/ptrack.c
*
* INTERFACE ROUTINES (PostgreSQL side)
* ptrackMapInit() --- allocate new shared ptrack_map
- * ptrackMapAttach() --- attach to the existing ptrack_map
* assign_ptrack_map_size() --- ptrack_map_size GUC assign callback
* ptrack_walkdir() --- walk directory and mark all blocks of all
* data files in ptrack_map
@@ -17,7 +16,7 @@
*
* Currently ptrack has following public API methods:
*
- * # ptrack_version --- returns ptrack version string (2.0 currently).
+ * # ptrack_version --- returns ptrack version string (2.4 currently).
* # ptrack_get_pagemapset('LSN') --- returns a set of changed data files with
* bitmaps of changed blocks since specified LSN.
* # ptrack_init_lsn --- returns LSN of the last ptrack map initialization.
@@ -37,11 +36,9 @@
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
-#ifdef PGPRO_EE
-/* For file_is_in_cfs_tablespace() only. */
-#include "replication/basebackup.h"
-#endif
+#include "port/pg_crc32c.h"
#include "storage/copydir.h"
+#include "storage/ipc.h"
#include "storage/lmgr.h"
#if PG_VERSION_NUM >= 120000
#include "storage/md.h"
@@ -53,32 +50,43 @@
#include "utils/pg_lsn.h"
#include "datapagemap.h"
-#include "engine.h"
#include "ptrack.h"
+#include "engine.h"
PG_MODULE_MAGIC;
PtrackMap ptrack_map = NULL;
-uint64 ptrack_map_size;
+uint64 ptrack_map_size = 0;
int ptrack_map_size_tmp;
+static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
static copydir_hook_type prev_copydir_hook = NULL;
static mdwrite_hook_type prev_mdwrite_hook = NULL;
static mdextend_hook_type prev_mdextend_hook = NULL;
static ProcessSyncRequests_hook_type prev_ProcessSyncRequests_hook = NULL;
+#if PG_VERSION_NUM >= 170000
+static backup_checkpoint_request_hook_type prev_backup_checkpoint_request_hook = NULL;
+#endif
void _PG_init(void);
-void _PG_fini(void);
+static void ptrack_shmem_startup_hook(void);
static void ptrack_copydir_hook(const char *path);
static void ptrack_mdwrite_hook(RelFileNodeBackend smgr_rnode,
ForkNumber forkno, BlockNumber blkno);
static void ptrack_mdextend_hook(RelFileNodeBackend smgr_rnode,
ForkNumber forkno, BlockNumber blkno);
static void ptrack_ProcessSyncRequests_hook(void);
+#if PG_VERSION_NUM >= 170000
+static void ptrack_backup_checkpoint_request_hook(void);
+#endif
static void ptrack_gather_filelist(List **filelist, char *path, Oid spcOid, Oid dbOid);
static int ptrack_filelist_getnext(PtScanCtx * ctx);
+#if PG_VERSION_NUM >= 150000
+static shmem_request_hook_type prev_shmem_request_hook = NULL;
+static void ptrack_shmem_request(void);
+#endif
/*
* Module load callback
@@ -103,15 +111,34 @@ _PG_init(void)
"Sets the size of ptrack map in MB used for incremental backup (0 disabled).",
NULL,
&ptrack_map_size_tmp,
- -1,
- -1, 32 * 1024, /* limit to 32 GB */
- PGC_POSTMASTER,
0,
+#if SIZEOF_SIZE_T == 8
+ 0, 32 * 1024, /* limit to 32 GB */
+#else
+ 0, 256, /* limit to 256 MB */
+#endif
+ PGC_POSTMASTER,
+ GUC_UNIT_MB,
NULL,
assign_ptrack_map_size,
NULL);
+ /* Request server shared memory */
+ if (ptrack_map_size != 0)
+ {
+#if PG_VERSION_NUM >= 150000
+ prev_shmem_request_hook = shmem_request_hook;
+ shmem_request_hook = ptrack_shmem_request;
+#else
+ RequestAddinShmemSpace(PtrackActualSize);
+#endif
+ }
+ else
+ ptrackCleanFiles();
+
/* Install hooks */
+ prev_shmem_startup_hook = shmem_startup_hook;
+ shmem_startup_hook = ptrack_shmem_startup_hook;
prev_copydir_hook = copydir_hook;
copydir_hook = ptrack_copydir_hook;
prev_mdwrite_hook = mdwrite_hook;
@@ -120,19 +147,56 @@ _PG_init(void)
mdextend_hook = ptrack_mdextend_hook;
prev_ProcessSyncRequests_hook = ProcessSyncRequests_hook;
ProcessSyncRequests_hook = ptrack_ProcessSyncRequests_hook;
+#if PG_VERSION_NUM >= 170000
+ prev_backup_checkpoint_request_hook = backup_checkpoint_request_hook;
+ backup_checkpoint_request_hook = ptrack_backup_checkpoint_request_hook;
+#endif
}
+#if PG_VERSION_NUM >= 150000
+static void
+ptrack_shmem_request(void)
+{
+ if (prev_shmem_request_hook)
+ prev_shmem_request_hook();
+
+ RequestAddinShmemSpace(PtrackActualSize);
+}
+#endif
+
/*
- * Module unload callback
+ * ptrack_shmem_startup hook: allocate or attach to shared memory.
*/
-void
-_PG_fini(void)
+static void
+ptrack_shmem_startup_hook(void)
{
- /* Uninstall hooks */
- copydir_hook = prev_copydir_hook;
- mdwrite_hook = prev_mdwrite_hook;
- mdextend_hook = prev_mdextend_hook;
- ProcessSyncRequests_hook = prev_ProcessSyncRequests_hook;
+ bool map_found;
+
+ if (prev_shmem_startup_hook)
+ prev_shmem_startup_hook();
+
+ /*
+ * Create or attach to the shared memory state
+ */
+ LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
+
+ if (ptrack_map_size != 0)
+ {
+ ptrack_map = ShmemInitStruct("ptrack map",
+ PtrackActualSize,
+ &map_found);
+ if (!map_found)
+ {
+ ptrackMapInit();
+ elog(DEBUG1, "Shared memory for ptrack is ready");
+ }
+ }
+ else
+ {
+ ptrack_map = NULL;
+ }
+
+ LWLockRelease(AddinShmemInitLock);
}
/*
@@ -178,14 +242,6 @@ ptrack_copydir_hook(const char *path)
elog(DEBUG1, "ptrack_copydir_hook: spcOid %u, dbOid %u", spcOid, dbOid);
-#ifdef PGPRO_EE
- /*
- * Currently, we do not track files from compressed tablespaces in ptrack.
- */
- if (file_is_in_cfs_tablespace(path))
- elog(DEBUG1, "ptrack_copydir_hook: skipping changes tracking in the CFS tablespace %u", spcOid);
- else
-#endif
ptrack_walkdir(path, spcOid, dbOid);
if (prev_copydir_hook)
@@ -221,6 +277,16 @@ ptrack_ProcessSyncRequests_hook()
prev_ProcessSyncRequests_hook();
}
+#if PG_VERSION_NUM >= 170000
+static void
+ptrack_backup_checkpoint_request_hook(void)
+{
+ ptrack_set_init_lsn();
+
+ if (prev_backup_checkpoint_request_hook)
+ prev_backup_checkpoint_request_hook();
+}
+#endif
/*
* Recursively walk through the path and add all data files to filelist.
*/
@@ -229,7 +295,6 @@ ptrack_gather_filelist(List **filelist, char *path, Oid spcOid, Oid dbOid)
{
DIR *dir;
struct dirent *de;
-
dir = AllocateDir(path);
while ((de = ReadDirExtended(dir, path, LOG)) != NULL)
@@ -251,7 +316,7 @@ ptrack_gather_filelist(List **filelist, char *path, Oid spcOid, Oid dbOid)
if (sret < 0)
{
- ereport(LOG,
+ ereport(WARNING,
(errcode_for_file_access(),
errmsg("ptrack: could not stat file \"%s\": %m", subpath)));
continue;
@@ -259,41 +324,58 @@ ptrack_gather_filelist(List **filelist, char *path, Oid spcOid, Oid dbOid)
if (S_ISREG(fst.st_mode))
{
+ if (fst.st_size == 0)
+ {
+ elog(DEBUG3, "ptrack: skip empty file %s", subpath);
+
+ /* But try the next one */
+ continue;
+ }
+
/* Regular file inside database directory, otherwise skip it */
if (dbOid != InvalidOid || spcOid == GLOBALTABLESPACE_OID)
{
+#if PG_VERSION_NUM >= 170000
+ RelFileNumber relNumber;
+ unsigned segno;
+#else
int oidchars;
char oidbuf[OIDCHARS + 1];
+#endif
char *segpath;
PtrackFileList_i *pfl = palloc0(sizeof(PtrackFileList_i));
/*
* Check that filename seems to be a regular relation file.
*/
+#if PG_VERSION_NUM >= 170000
+ if (!parse_filename_for_nontemp_relation(de->d_name, &relNumber, &pfl->forknum, &segno))
+ continue;
+#else
if (!parse_filename_for_nontemp_relation(de->d_name, &oidchars, &pfl->forknum))
continue;
+#endif
+ /* Parse segno */
+ segpath = strstr(de->d_name, ".");
+ pfl->segno = segpath != NULL ? atoi(segpath + 1) : 0;
- /* Parse segno for main fork */
- if (pfl->forknum == MAIN_FORKNUM)
- {
- segpath = strstr(de->d_name, ".");
- pfl->segno = segpath != NULL ? atoi(segpath + 1) : 0;
- }
- else
- pfl->segno = 0;
-
+ /* Fill the pfl in */
+#if PG_VERSION_NUM >= 170000
+ nodeRel(pfl->relnode) = relNumber;
+#else
memcpy(oidbuf, de->d_name, oidchars);
oidbuf[oidchars] = '\0';
- pfl->relnode.relNode = atooid(oidbuf);
- pfl->relnode.dbNode = dbOid;
- pfl->relnode.spcNode = spcOid == InvalidOid ? DEFAULTTABLESPACE_OID : spcOid;
- pfl->path = GetRelationPath(dbOid, pfl->relnode.spcNode,
- pfl->relnode.relNode, InvalidBackendId, pfl->forknum);
+ nodeRel(pfl->relnode) = atooid(oidbuf);
+#endif
+ nodeDb(pfl->relnode) = dbOid;
+ nodeSpc(pfl->relnode) = spcOid == InvalidOid ? DEFAULTTABLESPACE_OID : spcOid;
+ pfl->path = GetRelationPath(dbOid, nodeSpc(pfl->relnode),
+ nodeRel(pfl->relnode), InvalidBackendId, pfl->forknum);
*filelist = lappend(*filelist, pfl);
elog(DEBUG3, "ptrack: added file %s of rel %u to file list",
- pfl->path, pfl->relnode.relNode);
+ pfl->path, nodeRel(pfl->relnode));
}
}
else if (S_ISDIR(fst.st_mode))
@@ -305,7 +387,7 @@ ptrack_gather_filelist(List **filelist, char *path, Oid spcOid, Oid dbOid)
ptrack_gather_filelist(filelist, subpath, spcOid, InvalidOid);
}
/* TODO: is it enough to properly check symlink support? */
-#ifndef WIN32
+#if !defined(WIN32) || (PG_VERSION_NUM >= 160000)
else if (S_ISLNK(fst.st_mode))
#else
else if (pgwin32_is_junction(subpath))
@@ -330,17 +412,29 @@ ptrack_filelist_getnext(PtScanCtx * ctx)
ListCell *cell;
char *fullpath;
struct stat fst;
+ uint32 rel_st_size = 0;
+
+get_next:
/* No more file in the list */
if (list_length(ctx->filelist) == 0)
return -1;
+#ifdef foreach_current_index
+ /* Get first file from the head */
+ cell = list_tail(ctx->filelist);
+ pfl = (PtrackFileList_i *) lfirst(cell);
+
+ /* Remove this file from the list */
+ ctx->filelist = list_delete_last(ctx->filelist);
+#else
/* Get first file from the head */
cell = list_head(ctx->filelist);
pfl = (PtrackFileList_i *) lfirst(cell);
/* Remove this file from the list */
ctx->filelist = list_delete_first(ctx->filelist);
+#endif
if (pfl->segno > 0)
{
@@ -354,9 +448,9 @@ ptrack_filelist_getnext(PtScanCtx * ctx)
ctx->relpath = pfl->path;
}
- ctx->bid.relnode.spcNode = pfl->relnode.spcNode;
- ctx->bid.relnode.dbNode = pfl->relnode.dbNode;
- ctx->bid.relnode.relNode = pfl->relnode.relNode;
+ nodeSpc(ctx->bid.relnode) = nodeSpc(pfl->relnode);
+ nodeDb(ctx->bid.relnode) = nodeDb(pfl->relnode);
+ nodeRel(ctx->bid.relnode) = nodeRel(pfl->relnode);
ctx->bid.forknum = pfl->forknum;
ctx->bid.blocknum = 0;
@@ -365,17 +459,27 @@ ptrack_filelist_getnext(PtScanCtx * ctx)
elog(WARNING, "ptrack: cannot stat file %s", fullpath);
/* But try the next one */
- return ptrack_filelist_getnext(ctx);
+ goto get_next;
+ }
+
+ rel_st_size = fst.st_size;
+
+ if (rel_st_size == 0)
+ {
+ elog(DEBUG3, "ptrack: skip empty file %s", fullpath);
+
+ /* But try the next one */
+ goto get_next;
}
if (pfl->segno > 0)
{
- ctx->relsize = pfl->segno * RELSEG_SIZE + fst.st_size / BLCKSZ;
+ ctx->relsize = pfl->segno * RELSEG_SIZE + rel_st_size / BLCKSZ;
ctx->bid.blocknum = pfl->segno * RELSEG_SIZE;
}
else
/* Estimate relsize as size of first segment in blocks */
- ctx->relsize = fst.st_size / BLCKSZ;
+ ctx->relsize = rel_st_size / BLCKSZ;
elog(DEBUG3, "ptrack: got file %s with size %u from the file list", pfl->path, ctx->relsize);
@@ -494,7 +598,7 @@ ptrack_get_pagemapset(PG_FUNCTION_ARGS)
XLogRecPtr update_lsn2;
/* Stop traversal if there are no more segments */
- if (ctx->bid.blocknum > ctx->relsize)
+ if (ctx->bid.blocknum >= ctx->relsize)
{
/* We completed a segment and there is a bitmap to return */
if (pagemap.bitmap != NULL)
@@ -526,12 +630,9 @@ ptrack_get_pagemapset(PG_FUNCTION_ARGS)
if (htup)
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(htup));
}
- else
- {
- /* We have just processed unchanged file, let's pick next */
- if (ptrack_filelist_getnext(ctx) < 0)
- SRF_RETURN_DONE(funcctx);
- }
+
+ if (ptrack_filelist_getnext(ctx) < 0)
+ SRF_RETURN_DONE(funcctx);
}
hash = BID_HASH_FUNC(ctx->bid);
@@ -539,10 +640,12 @@ ptrack_get_pagemapset(PG_FUNCTION_ARGS)
update_lsn1 = pg_atomic_read_u64(&ptrack_map->entries[slot1]);
+#if USE_ASSERT_CHECKING
if (update_lsn1 != InvalidXLogRecPtr)
elog(DEBUG3, "ptrack: update_lsn1 %X/%X of blckno %u of file %s",
(uint32) (update_lsn1 >> 32), (uint32) update_lsn1,
ctx->bid.blocknum, ctx->relpath);
+#endif
/* Only probe the second slot if the first one is marked */
if (update_lsn1 >= ctx->lsn)
@@ -550,10 +653,12 @@ ptrack_get_pagemapset(PG_FUNCTION_ARGS)
slot2 = (size_t)(((hash << 32) | (hash >> 32)) % PtrackContentNblocks);
update_lsn2 = pg_atomic_read_u64(&ptrack_map->entries[slot2]);
+#if USE_ASSERT_CHECKING
if (update_lsn2 != InvalidXLogRecPtr)
elog(DEBUG3, "ptrack: update_lsn2 %X/%X of blckno %u of file %s",
(uint32) (update_lsn1 >> 32), (uint32) update_lsn2,
ctx->bid.blocknum, ctx->relpath);
+#endif
/* Block has been changed since specified LSN. Mark it in the bitmap */
if (update_lsn2 >= ctx->lsn)
diff --git a/ptrack.control b/ptrack.control
index ec0af9d..7e3a2b7 100644
--- a/ptrack.control
+++ b/ptrack.control
@@ -1,5 +1,5 @@
# ptrack extension
comment = 'block-level incremental backup engine'
-default_version = '2.2'
+default_version = '2.4'
module_pathname = '$libdir/ptrack'
relocatable = true
diff --git a/ptrack.h b/ptrack.h
index d205115..abeffb3 100644
--- a/ptrack.h
+++ b/ptrack.h
@@ -4,6 +4,7 @@
* header for ptrack map for tracking updates of relation's pages
*
*
+ * Copyright (c) 2019-2022, Postgres Professional
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
@@ -17,14 +18,38 @@
#include "access/xlogdefs.h"
#include "storage/block.h"
#include "storage/buf.h"
+#if PG_VERSION_NUM >= 160000
+#include "storage/relfilelocator.h"
+#else
#include "storage/relfilenode.h"
+#endif
#include "storage/smgr.h"
#include "utils/relcache.h"
/* Ptrack version as a string */
-#define PTRACK_VERSION "2.2"
+#define PTRACK_VERSION "2.4"
/* Ptrack version as a number */
-#define PTRACK_VERSION_NUM 220
+#define PTRACK_VERSION_NUM 240
+/* Last ptrack version that changed map file format */
+#define PTRACK_MAP_FILE_VERSION_NUM 220
+
+#if PG_VERSION_NUM >= 160000
+#define RelFileNode RelFileLocator
+#define RelFileNodeBackend RelFileLocatorBackend
+#define nodeDb(node) (node).dbOid
+#define nodeSpc(node) (node).spcOid
+#define nodeRel(node) (node).relNumber
+#define nodeOf(ndbck) (ndbck).locator
+#else
+#define nodeDb(node) (node).dbNode
+#define nodeSpc(node) (node).spcNode
+#define nodeRel(node) (node).relNode
+#define nodeOf(ndbck) (ndbck).node
+#endif
+
+#if PG_VERSION_NUM >= 170000
+#define InvalidBackendId INVALID_PROC_NUMBER
+#endif
/*
* Structure identifying block on the disk.
@@ -57,6 +82,7 @@ typedef struct PtrackFileList_i
ForkNumber forknum;
int segno;
char *path;
+
} PtrackFileList_i;
#endif /* PTRACK_H */
diff --git a/run_tests.sh b/run_tests.sh
deleted file mode 100755
index 90654cc..0000000
--- a/run_tests.sh
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/env bash
-
-#
-# Copyright (c) 2019-2020, Postgres Professional
-#
-
-PG_SRC=$PWD/postgres
-status=0
-
-# curl "https://ftp.postgresql.org/pub/source/v$PG_VERSION/postgresql-$PG_VERSION.tar.bz2" -o postgresql.tar.bz2
-# echo "$PG_SHA256 *postgresql.tar.bz2" | sha256sum -c -
-
-# mkdir $PG_SRC
-
-# tar \
-# --extract \
-# --file postgresql.tar.bz2 \
-# --directory $PG_SRC \
-# --strip-components 1
-
-# Clone Postgres
-echo "############### Getting Postgres sources"
-git clone https://github.com/postgres/postgres.git -b $PG_BRANCH --depth=1
-
-# Clone pg_probackup
-echo "############### Getting pg_probackup sources"
-git clone https://github.com/postgrespro/pg_probackup.git --depth=1 -b master
-# git clone https://github.com/ololobus/pg_probackup.git --depth=1 -b ptrack-tests
-
-# Compile and install Postgres
-cd postgres # Go to postgres dir
-
-echo "############### Applying ptrack patch"
-git apply -v -3 ../patches/$PG_BRANCH-ptrack-core.diff
-
-if [ "$MODE" = "paranoia" ]; then
- echo "############### Paranoia mode: applying turn-off-hint-bits.diff"
- git apply -v -3 ../patches/turn-off-hint-bits.diff
-fi
-
-echo "############### Compiling Postgres"
-if [ "$TEST_CASE" = "tap" ] && [ "$MODE" = "legacy" ]; then
- ./configure CFLAGS='-DEXEC_BACKEND' --disable-atomics --prefix=$PGHOME --enable-debug --enable-cassert --enable-depend --enable-tap-tests
-else
- ./configure --prefix=$PGHOME --enable-debug --enable-cassert --enable-depend --enable-tap-tests
-fi
-make -s -j$(nproc) install
-make -s -j$(nproc) -C contrib/ install
-
-# Override default Postgres instance
-export PATH=$PGHOME/bin:$PATH
-export LD_LIBRARY_PATH=$PGHOME/lib
-export PG_CONFIG=$(which pg_config)
-
-# Show pg_config path (just in case)
-echo "############### pg_config path"
-which pg_config
-
-# Show pg_config just in case
-echo "############### pg_config"
-pg_config
-
-# Get amcheck if missing
-if [ ! -d "contrib/amcheck" ]; then
- echo "############### Getting missing amcheck"
- git clone https://github.com/petergeoghegan/amcheck.git --depth=1 contrib/amcheck
- make USE_PGXS=1 -C contrib/amcheck install
-fi
-
-# Get back to testdir
-cd ..
-
-# Build and install ptrack extension
-echo "############### Compiling and installing ptrack extension"
-
-# XXX: Hackish way to make possible to run tap tests
-mkdir $PG_SRC/contrib/ptrack
-cp * $PG_SRC/contrib/ptrack/
-cp -R t $PG_SRC/contrib/ptrack/
-
-make USE_PGXS=1 PG_CPPFLAGS="-coverage" SHLIB_LINK="-coverage" -C $PG_SRC/contrib/ptrack/ install
-
-if [ "$TEST_CASE" = "tap" ]; then
-
- # Run tap tests
- echo "############### Running tap tests"
- if [ "$MODE" = "legacy" ]; then
- # There is a known issue with attaching shared memory segment using the same
- # address each time, when EXEC_BACKEND mechanism is turned on. It happens due
- # to the ASLR address space randomization, so we are trying to attach a segment
- # to the already occupied location. That way we simply turning off ASLR here.
- #
- # Postgres comment: https://github.com/postgres/postgres/blob/5cbfce562f7cd2aab0cdc4694ce298ec3567930e/src/backend/postmaster/postmaster.c#L4929
- setarch x86_64 --addr-no-randomize make -C postgres/contrib/ptrack check || status=$?
- else
- make -C postgres/contrib/ptrack check || status=$?
- fi
-
-else
-
- # Build and install pg_probackup
- echo "############### Compiling and installing pg_probackup"
- cd pg_probackup # Go to pg_probackup dir
- make USE_PGXS=1 top_srcdir=$PG_SRC install
-
- # Setup python environment
- echo "############### Setting up python env"
- virtualenv pyenv
- source pyenv/bin/activate
- pip install testgres==1.8.2
-
- echo "############### Testing"
- if [ "$MODE" = "basic" ]; then
- export PG_PROBACKUP_TEST_BASIC=ON
- elif [ "$MODE" = "paranoia" ]; then
- export PG_PROBACKUP_PARANOIA=ON
- fi
-
- if [ "$TEST_CASE" = "all" ]; then
- # Run all pg_probackup ptrack tests
- python -m unittest -v tests.ptrack || status=$?
- else
- for i in `seq $TEST_REPEATS`; do
- python -m unittest -v tests.ptrack.PtrackTest.$TEST_CASE || status=$?
- done
- fi
-
- # Exit virtualenv
- deactivate
-
- # Get back to testdir
- cd ..
-
-fi
-
-# Generate *.gcov files
-gcov $PG_SRC/contrib/ptrack/*.c $PG_SRC/contrib/ptrack/*.h
-
-# Send coverage stats to Codecov
-bash <(curl -s https://codecov.io/bash)
-
-# Something went wrong, exit with code 1
-if [ $status -ne 0 ]; then exit 1; fi
diff --git a/t/001_basic.pl b/t/001_basic.pl
index bac81f2..bdb1eca 100644
--- a/t/001_basic.pl
+++ b/t/001_basic.pl
@@ -6,19 +6,52 @@
use strict;
use warnings;
-use PostgresNode;
-use TestLib;
use Test::More;
-plan tests => 24;
+my $pg_15_modules;
+
+BEGIN
+{
+ $pg_15_modules = eval
+ {
+ require PostgreSQL::Test::Cluster;
+ require PostgreSQL::Test::Utils;
+ return 1;
+ };
+
+ unless (defined $pg_15_modules)
+ {
+ $pg_15_modules = 0;
+
+ require PostgresNode;
+ require TestLib;
+ }
+}
+
+plan tests => 23;
+
+note('PostgreSQL 15 modules are used: ' . ($pg_15_modules ? 'yes' : 'no'));
my $node;
my $res;
my $res_stdout;
my $res_stderr;
-# Initialize node
-$node = get_new_node('node');
+# Create node.
+# Older versions of PostgreSQL modules use get_new_node function.
+# Newer use standard perl object constructor syntax.
+eval
+{
+ if ($pg_15_modules)
+ {
+ $node = PostgreSQL::Test::Cluster->new("node");
+ }
+ else
+ {
+ $node = PostgresNode::get_new_node("node");
+ }
+};
+
$node->init;
$node->start;
@@ -149,7 +182,6 @@
# Check that we have lost everything
ok(! -f $node->data_dir . "/global/ptrack.map", "ptrack.map should be cleaned up");
ok(! -f $node->data_dir . "/global/ptrack.map.tmp", "ptrack.map.tmp should be cleaned up");
-ok(! -f $node->data_dir . "/global/ptrack.map.mmap", "ptrack.map.mmap should be cleaned up");
($res, $res_stdout, $res_stderr) = $node->psql("postgres", "SELECT ptrack_get_pagemapset('0/0')");
is($res, 3, 'errors out if ptrack is disabled');
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy