# HG changeset patch # User Augie Fackler # Date 1546903340 18000 # Node ID c4639fdae1b9ff6230b479ee73def2cb27fcd1c1 # Parent f36fd52dae8f6b291c26b2591fd538a91c842cc5 simplestorerepo: minimal changes required to get this mostly working again I was going to change this code's use of CBOR to use our in-house CBOR code, but discovered it's been broken for a while. This messy change gets it back to a point where it mostly works, I think roughly as well as it ever did. Should we keep this and fix it up the rest of the way, or dump it in favor of the sqlite store? Would this be a good jumping-off point for some sort of union store that could facilitate a cleanup in remotefilelog? Differential Revision: https://phab.mercurial-scm.org/D5519 diff -r f36fd52dae8f -r c4639fdae1b9 tests/simplestorerepo.py --- a/tests/simplestorerepo.py Tue Dec 04 11:22:31 2018 -0800 +++ b/tests/simplestorerepo.py Mon Jan 07 18:22:20 2019 -0500 @@ -66,17 +66,24 @@ pass @interfaceutil.implementer(repository.irevisiondelta) -@attr.s(slots=True, frozen=True) +@attr.s(slots=True) class simplestorerevisiondelta(object): node = attr.ib() p1node = attr.ib() p2node = attr.ib() basenode = attr.ib() - linknode = attr.ib() flags = attr.ib() baserevisionsize = attr.ib() revision = attr.ib() delta = attr.ib() + linknode = attr.ib(default=None) + +@interfaceutil.implementer(repository.iverifyproblem) +@attr.s(frozen=True) +class simplefilestoreproblem(object): + warning = attr.ib(default=None) + error = attr.ib(default=None) + node = attr.ib(default=None) @interfaceutil.implementer(repository.ifilestorage) class filestorage(object): @@ -192,6 +199,13 @@ return self._indexbyrev[rev][b'node'] + def hasnode(self, node): + validatenode(node) + return node in self._indexbynode + + def censorrevision(self, tr, censornode, tombstone=b''): + raise NotImplementedError('TODO') + def lookup(self, node): if isinstance(node, int): return self.node(node) @@ -290,7 +304,11 @@ raise simplestoreerror(_("integrity check failed on %s") % self._path) - def revision(self, node, raw=False): + def revision(self, nodeorrev, raw=False): + if isinstance(nodeorrev, int): + node = self.node(nodeorrev) + else: + node = nodeorrev validatenode(node) if node == nullid: @@ -409,6 +427,44 @@ return [b'/'.join((self._storepath, f)) for f in entries] + def storageinfo(self, exclusivefiles=False, sharedfiles=False, + revisionscount=False, trackedsize=False, + storedsize=False): + # TODO do a real implementation of this + return { + 'exclusivefiles': [], + 'sharedfiles': [], + 'revisionscount': len(self), + 'trackedsize': 0, + 'storedsize': None, + } + + def verifyintegrity(self, state): + state['skipread'] = set() + for rev in self: + node = self.node(rev) + try: + self.revision(node) + except Exception as e: + yield simplefilestoreproblem( + error='unpacking %s: %s' % (node, e), + node=node) + state['skipread'].add(node) + + def emitrevisions(self, nodes, nodesorder=None, revisiondata=False, + assumehaveparentrevisions=False, + deltamode=repository.CG_DELTAMODE_STD): + # TODO this will probably break on some ordering options. + nodes = [n for n in nodes if n != nullid] + if not nodes: + return + for delta in storageutil.emitrevisions( + self, nodes, nodesorder, simplestorerevisiondelta, + revisiondata=revisiondata, + assumehaveparentrevisions=assumehaveparentrevisions, + deltamode=deltamode): + yield delta + def add(self, text, meta, transaction, linkrev, p1, p2): if meta or text.startswith(b'\1\n'): text = storageutil.packmeta(meta, text) @@ -489,15 +545,26 @@ if addrevisioncb: addrevisioncb(self, node) + return nodes - return nodes + def _headrevs(self): + # Assume all revisions are heads by default. + revishead = {rev: True for rev in self._indexbyrev} + + for rev, entry in self._indexbyrev.items(): + # Unset head flag for all seen parents. + revishead[self.rev(entry[b'p1'])] = False + revishead[self.rev(entry[b'p2'])] = False + + return [rev for rev, ishead in sorted(revishead.items()) + if ishead] def heads(self, start=None, stop=None): # This is copied from revlog.py. if start is None and stop is None: if not len(self): return [nullid] - return [self.node(r) for r in self.headrevs()] + return [self.node(r) for r in self._headrevs()] if start is None: start = nullid @@ -537,41 +604,9 @@ return c def getstrippoint(self, minlink): - - # This is largely a copy of revlog.getstrippoint(). - brokenrevs = set() - strippoint = len(self) - - heads = {} - futurelargelinkrevs = set() - for head in self.heads(): - headlinkrev = self.linkrev(self.rev(head)) - heads[head] = headlinkrev - if headlinkrev >= minlink: - futurelargelinkrevs.add(headlinkrev) - - # This algorithm involves walking down the rev graph, starting at the - # heads. Since the revs are topologically sorted according to linkrev, - # once all head linkrevs are below the minlink, we know there are - # no more revs that could have a linkrev greater than minlink. - # So we can stop walking. - while futurelargelinkrevs: - strippoint -= 1 - linkrev = heads.pop(strippoint) - - if linkrev < minlink: - brokenrevs.add(strippoint) - else: - futurelargelinkrevs.remove(linkrev) - - for p in self.parentrevs(strippoint): - if p != nullrev: - plinkrev = self.linkrev(p) - heads[p] = plinkrev - if plinkrev >= minlink: - futurelargelinkrevs.add(plinkrev) - - return strippoint, brokenrevs + return storageutil.resolvestripinfo( + minlink, len(self) - 1, self._headrevs(), self.linkrev, + self.parentrevs) def strip(self, minlink, transaction): if not len(self): @@ -631,9 +666,9 @@ def featuresetup(ui, supported): supported.add(REQUIREMENT) -def newreporequirements(orig, ui): +def newreporequirements(orig, ui, createopts): """Modifies default requirements for new repos to use the simple store.""" - requirements = orig(ui) + requirements = orig(ui, createopts) # These requirements are only used to affect creation of the store # object. We have our own store. So we can remove them. @@ -665,5 +700,5 @@ extensions.wrapfunction(localrepo, 'newreporequirements', newreporequirements) - extensions.wrapfunction(store, 'store', makestore) + extensions.wrapfunction(localrepo, 'makestore', makestore) extensions.wrapfunction(verify.verifier, '__init__', verifierinit)