diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -3076,7 +3076,7 @@ def debugobsolete(ui, repo, precursor=No 'of transaction.')) with repo.lock(): - n = repo.obsstore.delete(indices) + n = repair.deleteobsmarkers(repo.obsstore, indices) ui.write(_('deleted %i obsolescense markers\n') % n) return diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py --- a/mercurial/obsolete.py +++ b/mercurial/obsolete.py @@ -628,30 +628,6 @@ class obsstore(object): transaction.hookargs['new_obsmarkers'] = str(previous + len(new)) return len(new) - def delete(self, indices): - """Delete some obsmarkers from store and return how many were deleted - - Indices is a list of ints which are the indices - of the markers to be deleted.""" - if not indices: - # we don't want to rewrite the obsstore with the same content - return - - left = [] - current = self._all - n = 0 - for i, m in enumerate(current): - if i in indices: - n += 1 - continue - left.append(m) - - newobsstore = self.svfs('obsstore', 'w', atomictemp=True) - for bytes in encodemarkers(left, True, self._version): - newobsstore.write(bytes) - newobsstore.close() - return n - def mergemarkers(self, transaction, data): """merge a binary stream of markers inside the obsstore diff --git a/mercurial/repair.py b/mercurial/repair.py --- a/mercurial/repair.py +++ b/mercurial/repair.py @@ -17,6 +17,7 @@ from . import ( changegroup, error, exchange, + obsolete, util, ) @@ -313,3 +314,32 @@ def stripbmrevset(repo, mark): "ancestors(head() and not bookmark(%s)) - " "ancestors(bookmark() and not bookmark(%s))", mark, mark, mark) + +def deleteobsmarkers(obsstore, indices): + """Delete some obsmarkers from obsstore and return how many were deleted + + 'indices' is a list of ints which are the indices + of the markers to be deleted. + + Every invocation of this function completely rewrites the obsstore file, + skipping the markers we want to be removed. The new temporary file is + created, remaining markers are written there and on .close() this file + gets atomically renamed to obsstore, thus guaranteeing consistency.""" + if not indices: + # we don't want to rewrite the obsstore with the same content + return + + left = [] + current = obsstore._all + n = 0 + for i, m in enumerate(current): + if i in indices: + n += 1 + continue + left.append(m) + + newobsstorefile = obsstore.svfs('obsstore', 'w', atomictemp=True) + for bytes in obsolete.encodemarkers(left, True, obsstore._version): + newobsstorefile.write(bytes) + newobsstorefile.close() + return n