hgsubversion: use a single transaction for hgsubversion pull

Summary:
hgsubversion was doing one transaction per commit, which is both slow
and also causes a lot of packs to be created when operating on a remotefilelog
client.

Let's make it use a single transaction instead. Unfortunately the svn metadata
is not integrated with Mercurial transactions. If we're using a normal flat-text
revmap, if there is an exception when running pull, it will need to svn rebuild
the metadata to remove the bad data and continue.

If we're using a sqlite revmap, then we've integrated with the sqlite
transaction, so it should work as expected.

Reviewed By: quark-zju

Differential Revision: D13433557

fbshipit-source-id: 809abb57839213302eb856ec19a113097be624e8
This commit is contained in:
Durham Goode 2018-12-12 15:09:59 -08:00 committed by Facebook Github Bot
parent 656bf8e5fb
commit 02d3eea7c2
2 changed files with 26 additions and 14 deletions

View File

@ -608,6 +608,7 @@ class SqliteRevMap(collections.MutableMapping):
self._lastpulledpath = lastpulled_path
self._db = None
self._txndb = None
self._sqlitepragmas = sqlitepragmas
self.firstpulled = 0
self._updatefirstlastpulled()
@ -733,18 +734,23 @@ class SqliteRevMap(collections.MutableMapping):
@contextlib.contextmanager
def _transaction(self, mode="IMMEDIATE"):
if self._db is None:
self._opendb()
with self._db as db:
# wait indefinitely for database lock
while True:
try:
db.execute("BEGIN %s" % mode)
break
except sqlite3.OperationalError as ex:
if str(ex) != "database is locked":
raise
yield db
if self._txndb is not None:
yield self._txndb
else:
if self._db is None:
self._opendb()
with self._db as db:
# wait indefinitely for database lock
while True:
try:
db.execute("BEGIN %s" % mode)
break
except sqlite3.OperationalError as ex:
if str(ex) != "database is locked":
raise
self._txndb = db
yield db
self._txndb = None
def _query(self, sql, params=()):
with self._transaction() as db:

View File

@ -501,7 +501,13 @@ def pull(repo, source, heads=None, force=False, meta=None):
try:
# start converting revisions
firstrun = True
with progress.bar(ui, "pull", total=total) as prog:
with repo.wlock(), repo.lock(), repo.transaction(
"svn"
), meta.revmap._transaction() if hgutil.safehasattr(
meta.revmap, "_transaction"
) else hgutil.nullcontextmanager(), progress.bar(
ui, "pull", total=total
) as prog:
for r in svn.revisions(start=start, stop=stopat_rev):
if r.revnum in skiprevs or (
r.author is None
@ -536,7 +542,6 @@ def pull(repo, source, heads=None, force=False, meta=None):
continue
meta.delbranch(branch, parent, r)
meta.save()
converted = True
firstrun = False
@ -557,6 +562,7 @@ def pull(repo, source, heads=None, force=False, meta=None):
raise hgutil.Abort(*e.args)
lastpulled = r.revnum
meta.save()
except KeyboardInterrupt:
ui.traceback()