comparison mercurial/dirstate.py @ 50086:76d44983a398

dirstate: remove the dedicated backup logic When alone, the dirstate can now take care of its commit/rollback pattern itself. When in a transaction, the transaction deal with commit/rollback pattern quite fine. Why did you have a dedicated backup logic?
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Thu, 16 Feb 2023 04:49:35 +0100
parents 5b9c3ae807c8
children 0f0880c8a7e5
comparison
equal deleted inserted replaced
50085:ff12f42415f5 50086:76d44983a398
29 scmutil, 29 scmutil,
30 util, 30 util,
31 ) 31 )
32 32
33 from .dirstateutils import ( 33 from .dirstateutils import (
34 docket as docketmod,
35 timestamp, 34 timestamp,
36 ) 35 )
37 36
38 from .interfaces import ( 37 from .interfaces import (
39 dirstate as intdirstate, 38 dirstate as intdirstate,
1629 self._map.docket.data_filename(), 1628 self._map.docket.data_filename(),
1630 ) 1629 )
1631 else: 1630 else:
1632 return (self._filename,) 1631 return (self._filename,)
1633 1632
1634 def data_backup_filename(self, backupname):
1635 if not self._use_dirstate_v2:
1636 return None
1637 return backupname + b'.v2-data'
1638
1639 def _new_backup_data_filename(self, backupname):
1640 """return a filename to backup a data-file or None"""
1641 if not self._use_dirstate_v2:
1642 return None
1643 if self._map.docket.uuid is None:
1644 # not created yet, nothing to backup
1645 return None
1646 data_filename = self._map.docket.data_filename()
1647 return data_filename, self.data_backup_filename(backupname)
1648
1649 def backup_data_file(self, backupname):
1650 if not self._use_dirstate_v2:
1651 return None
1652 docket = docketmod.DirstateDocket.parse(
1653 self._opener.read(backupname),
1654 self._nodeconstants,
1655 )
1656 return self.data_backup_filename(backupname), docket.data_filename()
1657
1658 def savebackup(self, tr, backupname):
1659 '''Save current dirstate into backup file'''
1660 filename = self._actualfilename(tr)
1661 assert backupname != filename
1662
1663 # use '_writedirstate' instead of 'write' to write changes certainly,
1664 # because the latter omits writing out if transaction is running.
1665 # output file will be used to create backup of dirstate at this point.
1666 if self._dirty:
1667 self._writedirstate(
1668 tr,
1669 self._opener(filename, b"w", atomictemp=True, checkambig=True),
1670 )
1671
1672 if tr:
1673 # ensure that subsequent tr.writepending returns True for
1674 # changes written out above, even if dirstate is never
1675 # changed after this
1676 tr.addfilegenerator(
1677 b'dirstate-1-main',
1678 (self._filename,),
1679 lambda f: self._writedirstate(tr, f),
1680 location=b'plain',
1681 post_finalize=True,
1682 )
1683
1684 self._opener.tryunlink(backupname)
1685 if self._opener.exists(filename):
1686 # hardlink backup is okay because _writedirstate is always called
1687 # with an "atomictemp=True" file.
1688 util.copyfile(
1689 self._opener.join(filename),
1690 self._opener.join(backupname),
1691 hardlink=True,
1692 )
1693 data_pair = self._new_backup_data_filename(backupname)
1694 if data_pair is not None:
1695 data_filename, bck_data_filename = data_pair
1696 util.copyfile(
1697 self._opener.join(data_filename),
1698 self._opener.join(bck_data_filename),
1699 hardlink=True,
1700 )
1701 if tr is not None:
1702 # ensure that pending file written above is unlinked at
1703 # failure, even if tr.writepending isn't invoked until the
1704 # end of this transaction
1705 tr.registertmp(bck_data_filename, location=b'plain')
1706
1707 def restorebackup(self, tr, backupname):
1708 '''Restore dirstate by backup file'''
1709 # this "invalidate()" prevents "wlock.release()" from writing
1710 # changes of dirstate out after restoring from backup file
1711 self.invalidate()
1712 o = self._opener
1713 if not o.exists(backupname):
1714 # there was no file backup, delete existing files
1715 filename = self._actualfilename(tr)
1716 data_file = None
1717 if self._use_dirstate_v2 and self._map.docket.uuid is not None:
1718 data_file = self._map.docket.data_filename()
1719 if o.exists(filename):
1720 o.unlink(filename)
1721 if data_file is not None and o.exists(data_file):
1722 o.unlink(data_file)
1723 return
1724 filename = self._actualfilename(tr)
1725 data_pair = self.backup_data_file(backupname)
1726 if o.exists(filename) and util.samefile(
1727 o.join(backupname), o.join(filename)
1728 ):
1729 o.unlink(backupname)
1730 else:
1731 o.rename(backupname, filename, checkambig=True)
1732
1733 if data_pair is not None:
1734 data_backup, target = data_pair
1735 if o.exists(target) and util.samefile(
1736 o.join(data_backup), o.join(target)
1737 ):
1738 o.unlink(data_backup)
1739 else:
1740 o.rename(data_backup, target, checkambig=True)
1741
1742 def clearbackup(self, tr, backupname):
1743 '''Clear backup file'''
1744 o = self._opener
1745 if o.exists(backupname):
1746 data_backup = self.backup_data_file(backupname)
1747 o.unlink(backupname)
1748 if data_backup is not None:
1749 o.unlink(data_backup[0])
1750
1751 def verify(self, m1, m2, p1, narrow_matcher=None): 1633 def verify(self, m1, m2, p1, narrow_matcher=None):
1752 """ 1634 """
1753 check the dirstate contents against the parent manifest and yield errors 1635 check the dirstate contents against the parent manifest and yield errors
1754 """ 1636 """
1755 missing_from_p1 = _( 1637 missing_from_p1 = _(