1818 */
1919
2020#include "postgres.h"
21-
2221#include <unistd.h>
2322#include <sys/stat.h>
2423
3635#include "catalog/pg_tablespace.h"
3736#include "miscadmin.h"
3837#include "port/pg_crc32c.h"
38+ #ifdef PGPRO_EE
39+ /* For file_is_in_cfs_tablespace() only. */
40+ #include "common/cfs_common.h"
41+ #endif
3942#include "storage/copydir.h"
4043#if PG_VERSION_NUM >=120000
4144#include "storage/md.h"
@@ -91,6 +94,68 @@ ptrack_write_chunk(int fd, pg_crc32c *crc, char *chunk, size_t size)
9194}
9295}
9396
97+ /*
98+ * Determines a file type which is one of the following:
99+ * * regular relation file
100+ * * regular relation file which is a part of a multifile relation
101+ * * everythong else
102+ */
103+ FileType
104+ file_type_from_path (const char * filename ) {
105+ ssize_t len = strlen (filename );
106+ bool met_dot ;
107+ met_dot = false;
108+
109+ // For this length checks we assume that the filename is at least
110+ // 1 character longer than the corresponding extension ".cfm":
111+ // strlen(".cfm") == 4 therefore we assume that the filename can't be
112+ // shorter than 5 bytes, for example: "5.cfm".
113+ if (len >=5 && strcmp (& filename [len - 4 ],".cfm" )== 0 )
114+ return FileTypeCFM ;
115+
116+ // we expect filename to be ****/12345 or ****/12345.12
117+ for (ssize_t i = len - 1 ;i >=0 && filename [i ]!= '/' ;i -- ) {
118+ if (isdigit (filename [i ])!= 0 )
119+ continue ;
120+
121+ // we expect the dot to appear only once
122+ if (filename [i ]== '.' ) {
123+ if (met_dot )
124+ return FileTypeUnknown ;
125+
126+ met_dot = true;
127+ }else
128+ // met anything except digit and dot => unknown file type
129+ return FileTypeUnknown ;
130+ }
131+
132+ return met_dot ?FileTypeMainMulti :FileTypeMain ;
133+ }
134+
135+ #ifdef PGPRO_EE
136+ /*
137+ * Determines the relation file size specified by fullpath as if it
138+ * was not compressed.
139+ */
140+ off_t
141+ get_cfs_relation_file_decompressed_size (RelFileNodeBackend rnode ,const char * fullpath ,ForkNumber forknum ) {
142+ File fd ;
143+ int compressor ;
144+ off_t size ;
145+
146+ compressor = md_get_compressor_internal (rnode .node ,rnode .backend ,forknum );
147+ fd = PathNameOpenFile (fullpath ,O_RDWR |PG_BINARY ,compressor );
148+
149+ if (fd < 0 )
150+ return (off_t )- 1 ;
151+
152+ size = FileSize (fd );
153+ FileClose (fd );
154+
155+ return size ;
156+ }
157+ #endif
158+
94159/*
95160 * Delete ptrack files when ptrack is disabled.
96161 *
@@ -498,8 +563,13 @@ assign_ptrack_map_size(int newval, void *extra)
498563 * For use in functions that copy directories bypassing buffer manager.
499564 */
500565static void
566+ #ifdef PGPRO_EE
567+ ptrack_mark_file (Oid dbOid ,Oid tablespaceOid ,
568+ const char * filepath ,const char * filename ,bool is_cfs )
569+ #else
501570ptrack_mark_file (Oid dbOid ,Oid tablespaceOid ,
502571const char * filepath ,const char * filename )
572+ #endif
503573{
504574RelFileNodeBackend rnode ;
505575ForkNumber forknum ;
@@ -508,6 +578,9 @@ ptrack_mark_file(Oid dbOid, Oid tablespaceOid,
508578struct stat stat_buf ;
509579int oidchars ;
510580char oidbuf [OIDCHARS + 1 ];
581+ #ifdef PGPRO_EE
582+ off_t rel_size ;
583+ #endif
511584
512585/* Do not track temporary relations */
513586if (looks_like_temp_rel_name (filename ))
@@ -526,6 +599,21 @@ ptrack_mark_file(Oid dbOid, Oid tablespaceOid,
526599oidbuf [oidchars ]= '\0' ;
527600nodeRel (nodeOf (rnode ))= atooid (oidbuf );
528601
602+ #ifdef PGPRO_EE
603+ // if current tablespace is cfs-compressed and md_get_compressor_internal
604+ // returns the type of the compressing algorithm for filepath, then it
605+ // needs to be de-compressed to obtain its size
606+ if (is_cfs && md_get_compressor_internal (rnode .node ,rnode .backend ,forknum )!= 0 ) {
607+ rel_size = get_cfs_relation_file_decompressed_size (rnode ,filepath ,forknum );
608+
609+ if (rel_size == (off_t )- 1 ) {
610+ elog (WARNING ,"ptrack: could not open cfs-compressed relation file: %s" ,filepath );
611+ return ;
612+ }
613+
614+ nblocks = rel_size /BLCKSZ ;
615+ }else
616+ #endif
529617/* Compute number of blocks based on file size */
530618if (stat (filepath ,& stat_buf )== 0 )
531619nblocks = stat_buf .st_size /BLCKSZ ;
@@ -546,6 +634,9 @@ ptrack_walkdir(const char *path, Oid tablespaceOid, Oid dbOid)
546634{
547635DIR * dir ;
548636struct dirent * de ;
637+ #ifdef PGPRO_EE
638+ bool is_cfs ;
639+ #endif
549640
550641/* Do not walk during bootstrap and if ptrack is disabled */
551642if (ptrack_map_size == 0
@@ -554,6 +645,10 @@ ptrack_walkdir(const char *path, Oid tablespaceOid, Oid dbOid)
554645|| InitializingParallelWorker )
555646return ;
556647
648+ #ifdef PGPRO_EE
649+ is_cfs = file_is_in_cfs_tablespace (path );
650+ #endif
651+
557652dir = AllocateDir (path );
558653
559654while ((de = ReadDirExtended (dir ,path ,LOG ))!= NULL )
@@ -581,7 +676,11 @@ ptrack_walkdir(const char *path, Oid tablespaceOid, Oid dbOid)
581676}
582677
583678if (S_ISREG (fst .st_mode ))
679+ #ifdef PGPRO_EE
680+ ptrack_mark_file (dbOid ,tablespaceOid ,subpath ,de -> d_name ,is_cfs );
681+ #else
584682ptrack_mark_file (dbOid ,tablespaceOid ,subpath ,de -> d_name );
683+ #endif
585684}
586685
587686FreeDir (dir );/* we ignore any error here */