diff -r 486b8a383100 -r 0705afae6253 mercurial/dirstate.py --- a/mercurial/dirstate.py Wed Aug 31 05:48:32 2022 +0200 +++ b/mercurial/dirstate.py Wed Aug 31 06:37:42 2022 +0200 @@ -31,6 +31,7 @@ ) from .dirstateutils import ( + docket as docketmod, timestamp, ) @@ -1433,6 +1434,27 @@ else: return self._filename + def data_backup_filename(self, backupname): + if not self._use_dirstate_v2: + return None + return backupname + b'.v2-data' + + def _new_backup_data_filename(self, backupname): + """return a filename to backup a data-file or None""" + if not self._use_dirstate_v2: + return None + data_filename = self._map.docket.data_filename() + return data_filename, self.data_backup_filename(backupname) + + def backup_data_file(self, backupname): + if not self._use_dirstate_v2: + return None + docket = docketmod.DirstateDocket.parse( + self._opener.read(backupname), + self._nodeconstants, + ) + return self.data_backup_filename(backupname), docket.data_filename() + def savebackup(self, tr, backupname): '''Save current dirstate into backup file''' filename = self._actualfilename(tr) @@ -1472,6 +1494,19 @@ self._opener.join(backupname), hardlink=True, ) + data_pair = self._new_backup_data_filename(backupname) + if data_pair is not None: + data_filename, bck_data_filename = data_pair + util.copyfile( + self._opener.join(data_filename), + self._opener.join(bck_data_filename), + hardlink=True, + ) + if tr is not None: + # ensure that pending file written above is unlinked at + # failure, even if tr.writepending isn't invoked until the + # end of this transaction + tr.registertmp(bck_data_filename, location=b'plain') def restorebackup(self, tr, backupname): '''Restore dirstate by backup file''' @@ -1480,14 +1515,29 @@ self.invalidate() filename = self._actualfilename(tr) o = self._opener + data_pair = self.backup_data_file(backupname) if util.samefile(o.join(backupname), o.join(filename)): o.unlink(backupname) else: o.rename(backupname, filename, checkambig=True) + if data_pair is not None: + data_backup, target = data_pair + if o.exists(target) and util.samefile( + o.join(data_backup), o.join(target) + ): + o.unlink(data_backup) + else: + o.rename(data_backup, target, checkambig=True) + def clearbackup(self, tr, backupname): '''Clear backup file''' - self._opener.unlink(backupname) + o = self._opener + data_backup = self.backup_data_file(backupname) + o.unlink(backupname) + + if data_backup is not None: + o.unlink(data_backup[0]) def verify(self, m1, m2): """check the dirstate content again the parent manifest and yield errors"""