treemanifest: write trees during local commits

Summary:
This makes local commits get written to trees (as well as flat manifest) when a
commit happens where the parent commit has a tree manifest already. During a
transaction where multiple trees are written (like when rebasing multiple
nodes), we reuse the same pack file for all the trees produced by tieing into
the transaction abort and close hooks.

Test Plan:
Ran the tests. Ran hg commit with the extension enabled. A future
patch will add an integration test for the treemanifest extension.

Reviewers: #mercurial, quark

Reviewed By: quark

Subscribers: mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D4055851

Signature: t1:4055851:1477059659:91b1c2f93ef986e910cea752ebf2466cb20ac921
This commit is contained in:
Durham Goode 2016-10-21 11:02:26 -07:00
parent 8bc51e248b
commit e63b8ce924
2 changed files with 48 additions and 4 deletions

View File

@ -11,7 +11,7 @@ import os
import time
import heapq
from mercurial import manifest, mdiff, revlog, util
from mercurial import manifest, mdiff, revlog, scmutil, util
import cachemanager
import cfastmanifest
from metrics import metricscollector
@ -19,6 +19,8 @@ from constants import *
try:
import ctreemanifest
import treemanifest
from remotefilelog import datapack, shallowutil
supportsctree = True
except ImportError:
supportsctree = False
@ -812,10 +814,48 @@ class manifestfactory(object):
fastcache.put_inmemory(hexnode, cachedmf)
self.ui.debug("[FM] wrote manifest %s\n" % (hexnode,))
return node
else:
return orig(*args, **kwargs)
node = orig(*args, **kwargs)
if (supportsctree and
self.ui.configbool("fastmanifest", "usetree", False)):
tree = origself.read(p1)._treemanifest()
if tree:
newtree = tree.copy()
for filename in removed:
del newtree[filename]
for filename in added:
fnode = m[filename]
fflag = m.flags(filename)
newtree.set(filename, fnode, fflag)
if not util.safehasattr(transaction, 'treepack'):
packpath = shallowutil.getlocalpackpath(
origself.opener.vfs.base,
'manifests')
opener = scmutil.vfs(packpath)
transaction.treepack = datapack.mutabledatapack(
self.ui,
opener)
def postclose(tr):
tr.treepack.close()
treemanifestcache.getinstance(origself.opener,
self.ui).clear()
origself.opener.manifestdatastore.markforrefresh()
def abort(tr):
tr.treepack.abort()
transaction.addpostclose('treepack', postclose)
transaction.addabort('treepack', abort)
pack = treemanifest.InterceptedMutablePack(
transaction.treepack,
node)
newtree.write(pack, tree)
treemanifestcache.getinstance(opener, self.ui)[node] = newtree
return node
def _silent_debug(*args, **kwargs):
"""Replacement for ui.debug that silently swallows the arguments.

View File

@ -71,6 +71,10 @@ def _unpackmanifests(orig, self, repo, *args, **kwargs):
repo.svfs.manifestdatastore.markforrefresh()
class InterceptedMutablePack(object):
"""This classes intercepts pack writes and replaces the node for the root
with the provided node. This is useful for forcing a tree manifest to be
referencable via its flat hash.
"""
def __init__(self, pack, node):
self._pack = pack
self._node = node