simplestorerepo: minimal changes required to get this mostly working again
authorAugie Fackler <augie@google.com>
Mon, 07 Jan 2019 18:22:20 -0500
changeset 41157 c4639fdae1b9
parent 41156 f36fd52dae8f
child 41158 ad51e6117095
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
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)