diff --git a/remotefilelog/__init__.py b/remotefilelog/__init__.py --- a/remotefilelog/__init__.py +++ b/remotefilelog/__init__.py @@ -933,6 +933,10 @@ def debughistorypack(ui, path, **opts): return debugcommands.debughistorypack(ui, path) +@command('debugpackstatus', [], 'hg debugpackstatus') +def debugpackstatus(repo, ui, **opts): + return debugcommands.debugpackstatus(repo, ui) + @command('debugkeepset', [ ], _('hg debugkeepset')) def debugkeepset(ui, repo, **opts): diff --git a/remotefilelog/basepack.py b/remotefilelog/basepack.py --- a/remotefilelog/basepack.py +++ b/remotefilelog/basepack.py @@ -191,7 +191,7 @@ count += 1 return totalsize, count - def getmetrics(self): + def getmetrics(self, verbose=False): """Returns metrics on the state of this store.""" size, count = self.gettotalsizeandcount() return { diff --git a/remotefilelog/basestore.py b/remotefilelog/basestore.py --- a/remotefilelog/basestore.py +++ b/remotefilelog/basestore.py @@ -41,6 +41,41 @@ if shared: shallowutil.mkstickygroupdir(self.ui, path) + def getnumfiles(self): + count = 0 + try: + for __, __ in self._listkeys(): + count += 1 + except Exception: + pass + return count + + def gettotalsize(self): + totalsize = 0 + try: + for fnhash, node in self._listkeys(): + fnhashhex = hex(fnhash) + path = self._getrootpath() + '/' + path += (fnhashhex[0:2] + '/' + fnhashhex[2:] + if self._shared else fnhashhex) + path += '/' + hex(node) + totalsize += os.stat(path).st_size + except Exception: + pass + + return totalsize + + def getmetrics(self, verbose=False): + if verbose: + # Calculating the two is very, very slow, so we only do so when + # requested (e.g. in `hg debugpackstatus`), and not on every comand. + return { + 'numloosefiles': self.getnumfiles(), + 'totalloosesize': self.gettotalsize(), + } + else: + return {} + def getmissing(self, keys): missing = [] for name, node in keys: @@ -155,16 +190,18 @@ return filenames + def _getrootpath(self): + if self._shared: + return os.path.join(self._path, self._reponame) + else: + return self._path + def _listkeys(self): """List all the remotefilelog keys that exist in the store. Returns a iterator of (filename hash, filecontent hash) tuples. """ - if self._shared: - path = os.path.join(self._path, self._reponame) - else: - path = self._path - + path = self._getrootpath() for root, dirs, files in os.walk(path): for filename in files: if len(filename) != 40: diff --git a/remotefilelog/contentstore.py b/remotefilelog/contentstore.py --- a/remotefilelog/contentstore.py +++ b/remotefilelog/contentstore.py @@ -93,8 +93,8 @@ pass raise KeyError((name, hex(node))) - def getmetrics(self): - metrics = [s.getmetrics() for s in self.stores] + def getmetrics(self, verbose=False): + metrics = [s.getmetrics(verbose=verbose) for s in self.stores] return shallowutil.sumdicts(*metrics) def _getpartialchain(self, name, node): @@ -222,6 +222,9 @@ def markledger(self, ledger, options=None): pass + def getmetrics(self, verbose=False): + return {} + class manifestrevlogstore(object): def __init__(self, repo): self._store = repo.store diff --git a/remotefilelog/debugcommands.py b/remotefilelog/debugcommands.py --- a/remotefilelog/debugcommands.py +++ b/remotefilelog/debugcommands.py @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from __future__ import absolute_import -from mercurial import error, filelog, revlog +from mercurial import error, filelog, revlog, util from mercurial.node import bin, hex, nullid, short from mercurial.i18n import _ from . import ( @@ -357,6 +357,37 @@ ui.write("%s %s %s %s %s\n" % (short(node), short(p1node), short(p2node), short(linknode), copyfrom)) +def debugpackstatus(ui, repo): + def format(metrics, paths=None): + parts = [] + if 'numpacks' in metrics: + parts.append("%d packs consuming %s" % (metrics['numpacks'], + util.bytecount(metrics['totalpacksize']))) + if 'numloosefiles' in metrics: + parts.append("%d loose files consuming %s" % ( + metrics['numloosefiles'], + util.bytecount(metrics['totalloosesize']))) + + if paths: + parts.append("in %s" % ",".join(paths)) + return ", ".join(parts) + + mfl = repo.manifestlog + ui.write(("Local Tree Store: %s\n" % format( + shallowutil.sumdicts(*[s.getmetrics(verbose=True) for s in + mfl.localdatastores]), + [s.path for p in mfl.localdatastores] + ))) + ui.write(("Shared Tree Store: %s\n" % format( + shallowutil.sumdicts(*[s.getmetrics(verbose=True) for s in + mfl.shareddatastores]), + [s.path for p in mfl.localdatastores] + ))) + ui.write(("File Content Store: %s\n" % + format(repo.contentstore.getmetrics(verbose=True)))) + ui.write(("File Data Store: %s\n" % + format(repo.metadatastore.getmetrics(verbose=True)))) + def debugwaitonrepack(repo): with repo._lock(repo.svfs, "repacklock", True, None, None, _('repacking %s') % repo.origroot): diff --git a/remotefilelog/metadatastore.py b/remotefilelog/metadatastore.py --- a/remotefilelog/metadatastore.py +++ b/remotefilelog/metadatastore.py @@ -100,7 +100,7 @@ for store in self.stores: store.markledger(ledger, options) - def getmetrics(self): + def getmetrics(self, verbose=False): metrics = [s.getmetrics() for s in self.stores] return shallowutil.sumdicts(*metrics) @@ -145,3 +145,6 @@ def markledger(self, ledger, options=None): pass + + def getmetrics(self, verbose=False): + return {} diff --git a/treemanifest/__init__.py b/treemanifest/__init__.py --- a/treemanifest/__init__.py +++ b/treemanifest/__init__.py @@ -1492,7 +1492,7 @@ def markledger(self, ledger, options=None): pass - def getmetrics(self): + def getmetrics(self, verbose=False): return {} def serverrepack(repo, incremental=False, options=None):