@@ -1723,7 +1723,8 @@ def pgdata_content(self, pgdata, ignore_ptrack=True, exclude_dirs=None):
17231723
17241724 file_fullpath = os .path .join (root , file )
17251725 file_relpath = os .path .relpath (file_fullpath , pgdata )
1726- directory_dict ['files' ][file_relpath ] = {'is_datafile' : False }
1726+ cfile = ContentFile (file .isdigit ())
1727+ directory_dict ['files' ][file_relpath ] = cfile
17271728 with open (file_fullpath , 'rb' ) as f :
17281729 # truncate cfm's content's zero tail
17291730 if file_relpath .endswith ('.cfm' ):
@@ -1743,49 +1744,31 @@ def pgdata_content(self, pgdata, ignore_ptrack=True, exclude_dirs=None):
17431744 b = f .read (64 * 1024 )
17441745 if not b : break
17451746 digest .update (b )
1746- directory_dict [ 'files' ][ file_relpath ][ ' md5' ] = digest .hexdigest ()
1747+ cfile . md5 = digest .hexdigest ()
17471748
17481749 # crappy algorithm
1749- if file .isdigit ():
1750- directory_dict ['files' ][file_relpath ]['is_datafile' ] = True
1750+ if cfile .is_datafile :
17511751 size_in_pages = os .path .getsize (file_fullpath )/ 8192
1752- directory_dict ['files' ][file_relpath ][
1753- 'md5_per_page' ] = self .get_md5_per_page_for_fork (
1752+ cfile .md5_per_page = self .get_md5_per_page_for_fork (
17541753 file_fullpath , size_in_pages
17551754 )
17561755
1757- for root , dirs , files in os .walk (pgdata , topdown = False , followlinks = True ):
1758- for directory in sorted (dirs ):
1756+ for directory in dirs :
17591757 directory_path = os .path .join (root , directory )
17601758 directory_relpath = os .path .relpath (directory_path , pgdata )
1761-
1762- found = False
1763- for d in dirs_to_ignore :
1764- if d in directory_relpath :
1765- found = True
1766- break
1767-
1768- # check if directory already here as part of larger directory
1769- if not found :
1770- for d in directory_dict ['dirs' ]:
1771- # print("OLD dir {0}".format(d))
1772- if directory_relpath in d :
1773- found = True
1774- break
1775-
1776- if not found :
1777- directory_dict ['dirs' ][directory_relpath ] = {}
1759+ parent = os .path .dirname (directory_relpath )
1760+ if parent in directory_dict ['dirs' ]:
1761+ del directory_dict ['dirs' ][parent ]
1762+ directory_dict ['dirs' ][directory_relpath ] = ContentDir ()
17781763
17791764 # get permissions for every file and directory
1780- for file in directory_dict ['dirs' ]:
1765+ for file , cfile in directory_dict ['dirs' ]. items () :
17811766 full_path = os .path .join (pgdata , file )
1782- directory_dict ['dirs' ][file ]['mode' ] = os .stat (
1783- full_path ).st_mode
1767+ cfile .mode = os .stat (full_path ).st_mode
17841768
1785- for file in directory_dict ['files' ]:
1769+ for file , cdir in directory_dict ['files' ]. items () :
17861770 full_path = os .path .join (pgdata , file )
1787- directory_dict ['files' ][file ]['mode' ] = os .stat (
1788- full_path ).st_mode
1771+ cdir .mode = os .stat (full_path ).st_mode
17891772
17901773 return directory_dict
17911774
@@ -1817,123 +1800,117 @@ def compare_pgdata(self, original_pgdata, restored_pgdata, exclusion_dict = dict
18171800 error_message = 'Restored PGDATA is not equal to original!\n '
18181801
18191802 # Compare directories
1820- for directory in restored_pgdata ['dirs' ]:
1821- if directory not in original_pgdata ['dirs' ]:
1822- fail = True
1823- error_message += '\n Directory was not present'
1824- error_message += ' in original PGDATA: {0}\n ' .format (
1825- os .path .join (restored_pgdata ['pgdata' ], directory ))
1826- else :
1827- if (
1828- restored_pgdata ['dirs' ][directory ]['mode' ] !=
1829- original_pgdata ['dirs' ][directory ]['mode' ]
1830- ):
1831- fail = True
1832- error_message += '\n Dir permissions mismatch:\n '
1833- error_message += ' Dir old: {0} Permissions: {1}\n ' .format (
1834- os .path .join (original_pgdata ['pgdata' ], directory ),
1835- original_pgdata ['dirs' ][directory ]['mode' ])
1836- error_message += ' Dir new: {0} Permissions: {1}\n ' .format (
1837- os .path .join (restored_pgdata ['pgdata' ], directory ),
1838- restored_pgdata ['dirs' ][directory ]['mode' ])
1839-
1840- for directory in original_pgdata ['dirs' ]:
1841- if directory not in restored_pgdata ['dirs' ]:
1803+ restored_dirs = set (restored_pgdata ['dirs' ])
1804+ original_dirs = set (restored_pgdata ['dirs' ])
1805+
1806+ for directory in sorted (restored_dirs - original_dirs ):
1807+ fail = True
1808+ error_message += '\n Directory was not present'
1809+ error_message += ' in original PGDATA: {0}\n ' .format (
1810+ os .path .join (restored_pgdata ['pgdata' ], directory ))
1811+
1812+ for directory in sorted (original_dirs - restored_dirs ):
1813+ fail = True
1814+ error_message += '\n Directory dissappeared'
1815+ error_message += ' in restored PGDATA: {0}\n ' .format (
1816+ os .path .join (restored_pgdata ['pgdata' ], directory ))
1817+
1818+ for directory in sorted (original_dirs & restored_dirs ):
1819+ original = original_pgdata ['dirs' ][directory ]
1820+ restored = restored_pgdata ['dirs' ][directory ]
1821+ if original .mode != restored .mode :
18421822 fail = True
1843- error_message += '\n Directory dissappeared'
1844- error_message += ' in restored PGDATA: {0}\n ' .format (
1845- os .path .join (restored_pgdata ['pgdata' ], directory ))
1846-
1847- for file in restored_pgdata ['files' ]:
1823+ error_message += '\n Dir permissions mismatch:\n '
1824+ error_message += ' Dir old: {0} Permissions: {1}\n ' .format (
1825+ os .path .join (original_pgdata ['pgdata' ], directory ),
1826+ original .mode )
1827+ error_message += ' Dir new: {0} Permissions: {1}\n ' .format (
1828+ os .path .join (restored_pgdata ['pgdata' ], directory ),
1829+ restored .mode )
1830+
1831+ restored_files = set (restored_pgdata ['files' ])
1832+ original_files = set (restored_pgdata ['files' ])
1833+
1834+ for file in sorted (restored_files - original_files ):
18481835 # File is present in RESTORED PGDATA
18491836 # but not present in ORIGINAL
18501837 # only backup_label is allowed
1851- if file not in original_pgdata ['files' ]:
1852- fail = True
1853- error_message += '\n File is not present'
1854- error_message += ' in original PGDATA: {0}\n ' .format (
1855- os .path .join (restored_pgdata ['pgdata' ], file ))
1856-
1857- for file in original_pgdata ['files' ]:
1858- if file in restored_pgdata ['files' ]:
1838+ fail = True
1839+ error_message += '\n File is not present'
1840+ error_message += ' in original PGDATA: {0}\n ' .format (
1841+ os .path .join (restored_pgdata ['pgdata' ], file ))
1842+
1843+ for file in sorted (original_files - restored_files ):
1844+ error_message += (
1845+ '\n File disappearance.\n '
1846+ 'File: {0}\n ' ).format (
1847+ os .path .join (restored_pgdata ['pgdata' ], file )
1848+ )
1849+ fail = True
18591850
1860- if (
1861- restored_pgdata ['files' ][file ]['mode' ] !=
1862- original_pgdata ['files' ][file ]['mode' ]
1863- ):
1851+ for file in sorted (original_files & restored_files ):
1852+ original = original_pgdata ['files' ][file ]
1853+ restored = restored_pgdata ['files' ][file ]
1854+ if restored .mode != original .mode :
1855+ fail = True
1856+ error_message += '\n File permissions mismatch:\n '
1857+ error_message += ' File_old: {0} Permissions: {1:o}\n ' .format (
1858+ os .path .join (original_pgdata ['pgdata' ], file ),
1859+ original .mode )
1860+ error_message += ' File_new: {0} Permissions: {1:o}\n ' .format (
1861+ os .path .join (restored_pgdata ['pgdata' ], file ),
1862+ restored .mode )
1863+
1864+ if original .md5 != restored .md5 :
1865+ if file not in exclusion_dict :
18641866 fail = True
1865- error_message += '\n File permissions mismatch:\n '
1866- error_message += ' File_old: {0} Permissions: {1:o}\n ' .format (
1867+ error_message += (
1868+ '\n File Checksum mismatch.\n '
1869+ 'File_old: {0}\n Checksum_old: {1}\n '
1870+ 'File_new: {2}\n Checksum_new: {3}\n ' ).format (
18671871 os .path .join (original_pgdata ['pgdata' ], file ),
1868- original_pgdata ['files' ][file ]['mode' ])
1869- error_message += ' File_new: {0} Permissions: {1:o}\n ' .format (
1872+ original .md5 ,
18701873 os .path .join (restored_pgdata ['pgdata' ], file ),
1871- restored_pgdata ['files' ][file ]['mode' ])
1874+ restored .md5
1875+ )
18721876
1873- if (
1874- original_pgdata ['files' ][file ]['md5' ] !=
1875- restored_pgdata ['files' ][file ]['md5' ]
1876- ):
1877- if file not in exclusion_dict :
1878- fail = True
1879- error_message += (
1880- '\n File Checksum mismatch.\n '
1881- 'File_old: {0}\n Checksum_old: {1}\n '
1882- 'File_new: {2}\n Checksum_new: {3}\n ' ).format (
1883- os .path .join (original_pgdata ['pgdata' ], file ),
1884- original_pgdata ['files' ][file ]['md5' ],
1885- os .path .join (restored_pgdata ['pgdata' ], file ),
1886- restored_pgdata ['files' ][file ]['md5' ]
1887- )
1877+ if not original .is_datafile :
1878+ continue
18881879
1889- if original_pgdata ['files' ][file ]['is_datafile' ]:
1890- for page in original_pgdata ['files' ][file ]['md5_per_page' ]:
1891- if page not in restored_pgdata ['files' ][file ]['md5_per_page' ]:
1892- error_message += (
1893- '\n Page {0} dissappeared.\n '
1894- 'File: {1}\n ' ).format (
1895- page ,
1896- os .path .join (
1897- restored_pgdata ['pgdata' ],
1898- file
1899- )
1900- )
1901- continue
1902-
1903- if not (file in exclusion_dict and page in exclusion_dict [file ]):
1904- if (
1905- original_pgdata ['files' ][file ]['md5_per_page' ][page ] !=
1906- restored_pgdata ['files' ][file ]['md5_per_page' ][page ]
1907- ):
1908- fail = True
1909- error_message += (
1910- '\n Page checksum mismatch: {0}\n '
1911- ' PAGE Checksum_old: {1}\n '
1912- ' PAGE Checksum_new: {2}\n '
1913- ' File: {3}\n '
1914- ).format (
1915- page ,
1916- original_pgdata ['files' ][file ][
1917- 'md5_per_page' ][page ],
1918- restored_pgdata ['files' ][file ][
1919- 'md5_per_page' ][page ],
1920- os .path .join (
1921- restored_pgdata ['pgdata' ], file )
1922- )
1923- for page in restored_pgdata ['files' ][file ]['md5_per_page' ]:
1924- if page not in original_pgdata ['files' ][file ]['md5_per_page' ]:
1925- error_message += '\n Extra page {0}\n File: {1}\n ' .format (
1926- page ,
1927- os .path .join (
1928- restored_pgdata ['pgdata' ], file ))
1880+ original_pages = set (original .md5_per_page )
1881+ restored_pages = set (restored .md5_per_page )
19291882
1930- else :
1931- error_message += (
1932- '\n File disappearance.\n '
1933- 'File: {0}\n ' ).format (
1934- os .path .join (restored_pgdata ['pgdata' ], file )
1883+ for page in sorted (original_pages - restored_pages ):
1884+ error_message += '\n Page {0} dissappeared.\n File: {1}\n ' .format (
1885+ page ,
1886+ os .path .join (restored_pgdata ['pgdata' ], file )
19351887 )
1936- fail = True
1888+
1889+
1890+ for page in sorted (restored_pages - original_pages ):
1891+ error_message += '\n Extra page {0}\n File: {1}\n ' .format (
1892+ page ,
1893+ os .path .join (restored_pgdata ['pgdata' ], file ))
1894+
1895+ for page in sorted (original_pages & restored_pages ):
1896+ if file in exclusion_dict and page in exclusion_dict [file ]:
1897+ continue
1898+
1899+ if original .md5_per_page [page ] != restored .md5_per_page [page ]:
1900+ fail = True
1901+ error_message += (
1902+ '\n Page checksum mismatch: {0}\n '
1903+ ' PAGE Checksum_old: {1}\n '
1904+ ' PAGE Checksum_new: {2}\n '
1905+ ' File: {3}\n '
1906+ ).format (
1907+ page ,
1908+ original .md5_per_page [page ],
1909+ restored .md5_per_page [page ],
1910+ os .path .join (
1911+ restored_pgdata ['pgdata' ], file )
1912+ )
1913+
19371914 self .assertFalse (fail , error_message )
19381915
19391916 def gdb_attach (self , pid ):
@@ -2186,3 +2163,10 @@ def _execute(self, cmd, running=True):
21862163# if running and line.startswith('*running'):
21872164 break
21882165 return output
2166+ class ContentFile (object ):
2167+ __slots__ = ('is_datafile' , 'mode' , 'md5' , 'md5_per_page' )
2168+ def __init__ (self , is_datafile : bool ):
2169+ self .is_datafile = is_datafile
2170+
2171+ class ContentDir (object ):
2172+ __slots__ = ('mode' )
0 commit comments