make pushes faster in our reverse sync case

Summary:
Our reverse sync job is too slow when pushing to svn. It seems like the slowness comes
keep doing push-pull-rebase which doesn't seem necessary in our case.

From my understanding, we need to do push-pull-rebase because we have multiple writers.
In our sync job, we only have one writer and therefore can we skip the pulls and rebases?

Reviewed By: DurhamG

Differential Revision: D16442559

fbshipit-source-id: 926d1c516e8e6d59298d310fc67927ace37f72c9
This commit is contained in:
Shu-Ting Tseng 2019-07-26 07:17:55 -07:00 committed by Facebook Github Bot
parent 83b1186e2a
commit 86bdaeb464
3 changed files with 76 additions and 37 deletions

View File

@ -22,6 +22,9 @@ Config::
# Append 'REVERSE_SYNC_ONLY_HG_NODE: {hghash}' to the commit message when
# committing to SVN. The hghash here is the original hash, before any rebase.
rewritesvncommitwithhghash = False
# Skip the post-push pull and rebase. This only works in single-writer
# scenario and should only be used in HG -> SVN reverse sync.
skippostpushpulls = False
"""
from __future__ import absolute_import
@ -429,6 +432,10 @@ configitem("hgsubversion", "repouuid", default="")
# write the hg hash in the svn commit message when pushing to svn.
# only used for HG -> SVN reverse sync.
configitem("hgsubversion", "rewritesvncommitwithhghash", default=False)
# skip the pulls and potential rebases after pushing each commits.
# this significantly speed up the push but is not usable in multi-writer case.
# only used for HG -> SVN reverse sync.
configitem("hgsubversion", "skippostpushpulls", default=False)
@templatekeyword("svnrev")

View File

@ -253,6 +253,7 @@ def push(repo, dest, force, revs):
tip_ctx = repo[outgoing[-1]].p1()
svnbranch = tip_ctx.branch()
modified_files = {}
pushedrev = None
for i in range(len(outgoing) - 1, -1, -1):
# 2. Pick the oldest changeset that needs to be pushed
current_ctx = repo[outgoing[i]]
@ -266,46 +267,51 @@ def push(repo, dest, force, revs):
# results in nonzero exit status, see hg's commands.py
return 0
# 3. Move the changeset to the tip of the branch if necessary
conflicts = False
for file in current_ctx.files():
if file in modified_files:
conflicts = True
break
if conflicts or current_ctx.branch() != svnbranch:
util.swap_out_encoding(old_encoding)
try:
def extrafn(ctx, extra):
extra["branch"] = ctx.branch()
ui.note("rebasing %s onto %s \n" % (current_ctx, tip_ctx))
hgrebase.rebase(
ui,
repo,
dest=node.hex(tip_ctx.node()),
rev=[node.hex(current_ctx.node())],
extrafn=extrafn,
keep=True,
)
finally:
util.swap_out_encoding()
# Don't trust the pre-rebase repo and context.
repo = getlocalpeer(ui, {}, meta.path)
meta = repo.svnmeta(svn.uuid, svn.subdir)
hashes = meta.revmap.hashes()
tip_ctx = repo[tip_ctx.node()]
for c in tip_ctx.descendants():
rebasesrc = c.extra().get("rebase_source")
if rebasesrc and node.bin(rebasesrc) == current_ctx.node():
current_ctx = c
temporary_commits.append(c.node())
if ui.configbool("hgsubversion", "skippostpushpulls"):
# We use the revmap for the first commit.
# After that, we use what we received from svn.
tip_hash = pushedrev.revnum if pushedrev else hashes[tip_ctx.node()][0]
else:
# 3. Move the changeset to the tip of the branch if necessary
conflicts = False
for file in current_ctx.files():
if file in modified_files:
conflicts = True
break
if conflicts or current_ctx.branch() != svnbranch:
util.swap_out_encoding(old_encoding)
try:
def extrafn(ctx, extra):
extra["branch"] = ctx.branch()
ui.note("rebasing %s onto %s \n" % (current_ctx, tip_ctx))
hgrebase.rebase(
ui,
repo,
dest=node.hex(tip_ctx.node()),
rev=[node.hex(current_ctx.node())],
extrafn=extrafn,
keep=True,
)
finally:
util.swap_out_encoding()
# Don't trust the pre-rebase repo and context.
repo = getlocalpeer(ui, {}, meta.path)
meta = repo.svnmeta(svn.uuid, svn.subdir)
hashes = meta.revmap.hashes()
tip_ctx = repo[tip_ctx.node()]
for c in tip_ctx.descendants():
rebasesrc = c.extra().get("rebase_source")
if rebasesrc and node.bin(rebasesrc) == current_ctx.node():
current_ctx = c
temporary_commits.append(c.node())
break
tip_hash = hashes[tip_ctx.node()][0]
# 4. Push the changeset to subversion
tip_hash = hashes[tip_ctx.node()][0]
try:
ui.status("committing %s\n" % current_ctx)
pushedrev = pushmod.commit(
@ -325,6 +331,9 @@ def push(repo, dest, force, revs):
# push a revision and pull it back.
repo.hook("debug-hgsubversion-between-push-and-pull-for-tests")
if ui.configbool("hgsubversion", "skippostpushpulls"):
continue
# 5. Pull the latest changesets from subversion, which will
# include the one we just committed (and possibly others).
r = pull(repo, dest, force=force, meta=meta)

View File

@ -854,6 +854,29 @@ class PushTests(test_hgsubversion_util.TestBase):
"automated test\nREVERSE_SYNC_ONLY_HG_NODE: " + old_tip_hex,
)
def test_push_with_skip_postpush_pull_config(self):
"""
Push performs a pull after each push. With a config, that is disabled.
Lets ensure that code path works
"""
changes = [("gamma", "gamma", "sometext")]
self.commitchanges(changes)
changes = [("gamma", "gamma", "someothertext")]
newhash = self.commitchanges(changes)
repo = self.repo
old_tip = self.repo["tip"].hex()
hg.update(repo, newhash)
self.pushrevisionswithconfigs(
configs=[("hgsubversion", "skippostpushpulls", True)]
)
# verify that we didn't pull new commits
new_tip = self.repo["tip"].hex()
self.assertEqual(old_tip, new_tip)
if __name__ == "__main__":
import silenttestrunner