Mercurial > public > mercurial-scm > hg-stable
diff mercurial/revlog.py @ 46731:ba8e508a8e69
sidedata-exchange: rewrite sidedata on-the-fly whenever possible
When a A exchanges with B, the difference of their supported sidedata categories
is made, and the responsibility is always with the client to generated it:
- If A pushes to B and B requires category `foo` that A does not have, A
will need to generate it when sending it to B.
- If A pulls from B and A needs category `foo`, it will generate `foo`
before the end of the transaction.
- Any category that is not required is removed. If peers are not compatible,
abort.
It is forbidden to rewrite sidedata for a rev that already has sidedata, since
that would introduce unreachable (garbage) data in the data file, something
we're not prepared for yet.
Differential Revision: https://phab.mercurial-scm.org/D10032
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Fri, 19 Feb 2021 11:24:50 +0100 |
parents | c8bb7b89179e |
children | 49fd21f32695 |
line wrap: on
line diff
--- a/mercurial/revlog.py Mon Feb 15 11:08:28 2021 +0100 +++ b/mercurial/revlog.py Fri Feb 19 11:24:50 2021 +0100 @@ -3205,3 +3205,54 @@ ) return d + + def rewrite_sidedata(self, helpers, startrev, endrev): + if self.version & 0xFFFF != REVLOGV2: + return + # inline are not yet supported because they suffer from an issue when + # rewriting them (since it's not an append-only operation). + # See issue6485. + assert not self._inline + if not helpers[1] and not helpers[2]: + # Nothing to generate or remove + return + + new_entries = [] + # append the new sidedata + with self._datafp(b'a+') as fp: + # Maybe this bug still exists, see revlog._writeentry + fp.seek(0, os.SEEK_END) + current_offset = fp.tell() + for rev in range(startrev, endrev + 1): + entry = self.index[rev] + new_sidedata = storageutil.run_sidedata_helpers( + store=self, + sidedata_helpers=helpers, + sidedata={}, + rev=rev, + ) + + serialized_sidedata = sidedatautil.serialize_sidedata( + new_sidedata + ) + if entry[8] != 0 or entry[9] != 0: + # rewriting entries that already have sidedata is not + # supported yet, because it introduces garbage data in the + # revlog. + msg = "Rewriting existing sidedata is not supported yet" + raise error.Abort(msg) + entry = entry[:8] + entry += (current_offset, len(serialized_sidedata)) + + fp.write(serialized_sidedata) + new_entries.append(entry) + current_offset += len(serialized_sidedata) + + # rewrite the new index entries + with self._indexfp(b'w+') as fp: + fp.seek(startrev * self._io.size) + for i, entry in enumerate(new_entries): + rev = startrev + i + self.index.replace_sidedata_info(rev, entry[8], entry[9]) + packed = self._io.packentry(entry, self.node, self.version, rev) + fp.write(packed)