comparison mercurial/revlog.py @ 46718: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
comparison
equal deleted inserted replaced
46717:502e795b55ac 46718:ba8e508a8e69
3203 d[b'storedsize'] = sum( 3203 d[b'storedsize'] = sum(
3204 self.opener.stat(path).st_size for path in self.files() 3204 self.opener.stat(path).st_size for path in self.files()
3205 ) 3205 )
3206 3206
3207 return d 3207 return d
3208
3209 def rewrite_sidedata(self, helpers, startrev, endrev):
3210 if self.version & 0xFFFF != REVLOGV2:
3211 return
3212 # inline are not yet supported because they suffer from an issue when
3213 # rewriting them (since it's not an append-only operation).
3214 # See issue6485.
3215 assert not self._inline
3216 if not helpers[1] and not helpers[2]:
3217 # Nothing to generate or remove
3218 return
3219
3220 new_entries = []
3221 # append the new sidedata
3222 with self._datafp(b'a+') as fp:
3223 # Maybe this bug still exists, see revlog._writeentry
3224 fp.seek(0, os.SEEK_END)
3225 current_offset = fp.tell()
3226 for rev in range(startrev, endrev + 1):
3227 entry = self.index[rev]
3228 new_sidedata = storageutil.run_sidedata_helpers(
3229 store=self,
3230 sidedata_helpers=helpers,
3231 sidedata={},
3232 rev=rev,
3233 )
3234
3235 serialized_sidedata = sidedatautil.serialize_sidedata(
3236 new_sidedata
3237 )
3238 if entry[8] != 0 or entry[9] != 0:
3239 # rewriting entries that already have sidedata is not
3240 # supported yet, because it introduces garbage data in the
3241 # revlog.
3242 msg = "Rewriting existing sidedata is not supported yet"
3243 raise error.Abort(msg)
3244 entry = entry[:8]
3245 entry += (current_offset, len(serialized_sidedata))
3246
3247 fp.write(serialized_sidedata)
3248 new_entries.append(entry)
3249 current_offset += len(serialized_sidedata)
3250
3251 # rewrite the new index entries
3252 with self._indexfp(b'w+') as fp:
3253 fp.seek(startrev * self._io.size)
3254 for i, entry in enumerate(new_entries):
3255 rev = startrev + i
3256 self.index.replace_sidedata_info(rev, entry[8], entry[9])
3257 packed = self._io.packentry(entry, self.node, self.version, rev)
3258 fp.write(packed)