[remotefilelog] don't crash on invalid pack files

Summary:
We have run into some cases where users ended up with empty pack file in their
packs directory.  Just log a warning in this case and skip this pack file,
rather than letting the exception propagate up and crashing the command.

Test Plan:
Created empty 0000000000000000000000000000000000000000.histpack and
0000000000000000000000000000000000000000.histidx files in my repository's
hgcache directory, and confirmed that "hg log" now simply warns about them
instead of crashing.

I didn't really test the perftest.py or treemanifest_correctness.py extensions
much.  They seem to throw exceptions, and look like they have maybe gotten a
bit stale.  I fixed one minor typo, but didn't dig into the other exceptions
too much.

Reviewers: durham

Reviewed By: durham

Subscribers: net-systems-diffs@, yogeshwer, mjpieters

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

Tasks: 15428659

Signature: t1:4402516:1484155254:96d2980efcec2d735257b08910e1ca437ef1dad6
This commit is contained in:
Adam Simpkins 2017-01-12 09:47:29 -08:00
parent 43d3e5f2fe
commit ab81106b08
6 changed files with 25 additions and 17 deletions

View File

@ -1,5 +1,6 @@
import errno, hashlib, mmap, os, struct, time import errno, hashlib, mmap, os, struct, time
from mercurial import osutil from mercurial import osutil
from mercurial.i18n import _
import shallowutil import shallowutil
@ -37,7 +38,7 @@ SMALLFANOUTCUTOFF = 2**16 / 8
REFRESHRATE = 0.1 REFRESHRATE = 0.1
class basepackstore(object): class basepackstore(object):
def __init__(self, path): def __init__(self, ui, path):
self.path = path self.path = path
self.packs = [] self.packs = []
# lastrefesh is 0 so we'll immediately check for new packs on the first # lastrefesh is 0 so we'll immediately check for new packs on the first
@ -47,12 +48,17 @@ class basepackstore(object):
for filepath in self._getavailablepackfiles(): for filepath in self._getavailablepackfiles():
try: try:
pack = self.getpack(filepath) pack = self.getpack(filepath)
except (OSError, IOError) as ex: except Exception as ex:
# someone could have removed the file since we retrieved the # An exception may be thrown if the pack file is corrupted
# list of paths. if that happens, just don't add the pack to # somehow. Log a warning but keep going in this case, just
# the list of available packs. # skipping this pack file.
if ex.errno != errno.ENOENT: #
raise # If this is an ENOENT error then don't even bother logging.
# Someone could have removed the file since we retrieved the
# list of paths.
if getattr(ex, 'errno', None) != errno.ENOENT:
ui.warn(_('unable to load pack %s: %s\n') % (filepath, ex))
pass
continue continue
self.packs.append(pack) self.packs.append(pack)

View File

@ -22,9 +22,9 @@ class datapackstore(basepack.basepackstore):
INDEXSUFFIX = INDEXSUFFIX INDEXSUFFIX = INDEXSUFFIX
PACKSUFFIX = PACKSUFFIX PACKSUFFIX = PACKSUFFIX
def __init__(self, path, usecdatapack=False): def __init__(self, ui, path, usecdatapack=False):
self.usecdatapack = usecdatapack self.usecdatapack = usecdatapack
super(datapackstore, self).__init__(path) super(datapackstore, self).__init__(ui, path)
def getpack(self, path): def getpack(self, path):
if self.usecdatapack: if self.usecdatapack:

View File

@ -184,9 +184,10 @@ def wraprepo(repo):
# Instantiate pack stores # Instantiate pack stores
packpath = shallowutil.getcachepackpath(repo, constants.FILEPACK_CATEGORY) packpath = shallowutil.getcachepackpath(repo, constants.FILEPACK_CATEGORY)
packcontentstore = datapackstore( packcontentstore = datapackstore(
repo.ui,
packpath, packpath,
usecdatapack=repo.ui.configbool('remotefilelog', 'fastdatapack')) usecdatapack=repo.ui.configbool('remotefilelog', 'fastdatapack'))
packmetadatastore = historypackstore(packpath) packmetadatastore = historypackstore(repo.ui, packpath)
# Instantiate union stores # Instantiate union stores
repo.contentstore = unioncontentstore(packcontentstore, cachecontent, repo.contentstore = unioncontentstore(packcontentstore, cachecontent,

View File

@ -39,7 +39,7 @@ def testpackedtrees(ui, repo, *args, **opts):
buildtreepack(repo, newpack, opts.get('build')) buildtreepack(repo, newpack, opts.get('build'))
newpack.close() newpack.close()
packstore = datapack.datapackstore(opener.base, packstore = datapack.datapackstore(ui, opener.base,
usecdatapack=ui.configbool('remotefilelog', 'fastdatapack')) usecdatapack=ui.configbool('remotefilelog', 'fastdatapack'))
unionstore = contentstore.unioncontentstore(packstore) unionstore = contentstore.unioncontentstore(packstore)
@ -63,7 +63,7 @@ class cachestore(object):
def buildtreepack(repo, pack, revs): def buildtreepack(repo, pack, revs):
mf = repo.manifest mf = repo.manifest
cache = cachestore() cache = cachestore()
packstore = datapack.datapackstore(pack.opener.base) packstore = datapack.datapackstore(repo.ui, pack.opener.base)
store = contentstore.unioncontentstore(cache, packstore) store = contentstore.unioncontentstore(cache, packstore)
ctxs = list(repo.set(revs)) ctxs = list(repo.set(revs))
for count, ctx in enumerate(ctxs): for count, ctx in enumerate(ctxs):

View File

@ -26,7 +26,7 @@ testedwith = 'ships-with-fb-hgext'
('', 'revs', 'master + master~5', ''), ('', 'revs', 'master + master~5', ''),
], '') ], '')
def testpackedtrees(ui, repo, *args, **opts): def testpackedtrees(ui, repo, *args, **opts):
packpath = shallowutil.getcacheackpath(repo, 'manifest') packpath = shallowutil.getcachepackpath(repo, 'manifest')
if not os.path.exists(packpath): if not os.path.exists(packpath):
os.mkdir(packpath) os.mkdir(packpath)
opener = scmutil.vfs(packpath) opener = scmutil.vfs(packpath)
@ -35,7 +35,7 @@ def testpackedtrees(ui, repo, *args, **opts):
buildtreepack(repo, newpack, opts.get('build')) buildtreepack(repo, newpack, opts.get('build'))
newpack.close() newpack.close()
packstore = datapack.datapackstore(opener.base, packstore = datapack.datapackstore(ui, opener.base,
usecdatapack=ui.configbool('remotefilelog', 'fastdatapack')) usecdatapack=ui.configbool('remotefilelog', 'fastdatapack'))
unionstore = contentstore.unioncontentstore(packstore) unionstore = contentstore.unioncontentstore(packstore)
@ -59,7 +59,7 @@ class cachestore(object):
def buildtreepack(repo, pack, revs): def buildtreepack(repo, pack, revs):
mf = repo.manifest mf = repo.manifest
cache = cachestore() cache = cachestore()
packstore = datapack.datapackstore(pack.opener.base) packstore = datapack.datapackstore(repo.ui, pack.opener.base)
store = contentstore.unioncontentstore(cache, packstore) store = contentstore.unioncontentstore(cache, packstore)
ctxs = list(repo.set(revs)) ctxs = list(repo.set(revs))
for count, ctx in enumerate(ctxs): for count, ctx in enumerate(ctxs):

View File

@ -57,11 +57,12 @@ def wraprepo(repo):
usecdatapack = repo.ui.configbool('remotefilelog', 'fastdatapack') usecdatapack = repo.ui.configbool('remotefilelog', 'fastdatapack')
packpath = shallowutil.getcachepackpath(repo, PACK_CATEGORY) packpath = shallowutil.getcachepackpath(repo, PACK_CATEGORY)
datastore = datapackstore(packpath, usecdatapack=usecdatapack) datastore = datapackstore(repo.ui, packpath, usecdatapack=usecdatapack)
localpackpath = shallowutil.getlocalpackpath(repo.svfs.vfs.base, localpackpath = shallowutil.getlocalpackpath(repo.svfs.vfs.base,
PACK_CATEGORY) PACK_CATEGORY)
localdatastore = datapackstore(localpackpath, usecdatapack=usecdatapack) localdatastore = datapackstore(repo.ui, localpackpath,
usecdatapack=usecdatapack)
repo.svfs.sharedmanifestdatastores = [datastore] repo.svfs.sharedmanifestdatastores = [datastore]
repo.svfs.localmanifestdatastores = [localdatastore] repo.svfs.localmanifestdatastores = [localdatastore]