Mercurial > hg
comparison tests/simplestorerepo.py @ 41157:c4639fdae1b9
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
author | Augie Fackler <augie@google.com> |
---|---|
date | Mon, 07 Jan 2019 18:22:20 -0500 |
parents | 1b183edbb68e |
children | ad51e6117095 |
comparison
equal
deleted
inserted
replaced
41156:f36fd52dae8f | 41157:c4639fdae1b9 |
---|---|
64 | 64 |
65 class simplestoreerror(error.StorageError): | 65 class simplestoreerror(error.StorageError): |
66 pass | 66 pass |
67 | 67 |
68 @interfaceutil.implementer(repository.irevisiondelta) | 68 @interfaceutil.implementer(repository.irevisiondelta) |
69 @attr.s(slots=True, frozen=True) | 69 @attr.s(slots=True) |
70 class simplestorerevisiondelta(object): | 70 class simplestorerevisiondelta(object): |
71 node = attr.ib() | 71 node = attr.ib() |
72 p1node = attr.ib() | 72 p1node = attr.ib() |
73 p2node = attr.ib() | 73 p2node = attr.ib() |
74 basenode = attr.ib() | 74 basenode = attr.ib() |
75 linknode = attr.ib() | |
76 flags = attr.ib() | 75 flags = attr.ib() |
77 baserevisionsize = attr.ib() | 76 baserevisionsize = attr.ib() |
78 revision = attr.ib() | 77 revision = attr.ib() |
79 delta = attr.ib() | 78 delta = attr.ib() |
79 linknode = attr.ib(default=None) | |
80 | |
81 @interfaceutil.implementer(repository.iverifyproblem) | |
82 @attr.s(frozen=True) | |
83 class simplefilestoreproblem(object): | |
84 warning = attr.ib(default=None) | |
85 error = attr.ib(default=None) | |
86 node = attr.ib(default=None) | |
80 | 87 |
81 @interfaceutil.implementer(repository.ifilestorage) | 88 @interfaceutil.implementer(repository.ifilestorage) |
82 class filestorage(object): | 89 class filestorage(object): |
83 """Implements storage for a tracked path. | 90 """Implements storage for a tracked path. |
84 | 91 |
190 def node(self, rev): | 197 def node(self, rev): |
191 validaterev(rev) | 198 validaterev(rev) |
192 | 199 |
193 return self._indexbyrev[rev][b'node'] | 200 return self._indexbyrev[rev][b'node'] |
194 | 201 |
202 def hasnode(self, node): | |
203 validatenode(node) | |
204 return node in self._indexbynode | |
205 | |
206 def censorrevision(self, tr, censornode, tombstone=b''): | |
207 raise NotImplementedError('TODO') | |
208 | |
195 def lookup(self, node): | 209 def lookup(self, node): |
196 if isinstance(node, int): | 210 if isinstance(node, int): |
197 return self.node(node) | 211 return self.node(node) |
198 | 212 |
199 if len(node) == 20: | 213 if len(node) == 20: |
288 p1, p2 = self.parents(node) | 302 p1, p2 = self.parents(node) |
289 if node != storageutil.hashrevisionsha1(text, p1, p2): | 303 if node != storageutil.hashrevisionsha1(text, p1, p2): |
290 raise simplestoreerror(_("integrity check failed on %s") % | 304 raise simplestoreerror(_("integrity check failed on %s") % |
291 self._path) | 305 self._path) |
292 | 306 |
293 def revision(self, node, raw=False): | 307 def revision(self, nodeorrev, raw=False): |
308 if isinstance(nodeorrev, int): | |
309 node = self.node(nodeorrev) | |
310 else: | |
311 node = nodeorrev | |
294 validatenode(node) | 312 validatenode(node) |
295 | 313 |
296 if node == nullid: | 314 if node == nullid: |
297 return b'' | 315 return b'' |
298 | 316 |
407 # recording. | 425 # recording. |
408 entries = [f for f in entries if not f.startswith('undo.backup.')] | 426 entries = [f for f in entries if not f.startswith('undo.backup.')] |
409 | 427 |
410 return [b'/'.join((self._storepath, f)) for f in entries] | 428 return [b'/'.join((self._storepath, f)) for f in entries] |
411 | 429 |
430 def storageinfo(self, exclusivefiles=False, sharedfiles=False, | |
431 revisionscount=False, trackedsize=False, | |
432 storedsize=False): | |
433 # TODO do a real implementation of this | |
434 return { | |
435 'exclusivefiles': [], | |
436 'sharedfiles': [], | |
437 'revisionscount': len(self), | |
438 'trackedsize': 0, | |
439 'storedsize': None, | |
440 } | |
441 | |
442 def verifyintegrity(self, state): | |
443 state['skipread'] = set() | |
444 for rev in self: | |
445 node = self.node(rev) | |
446 try: | |
447 self.revision(node) | |
448 except Exception as e: | |
449 yield simplefilestoreproblem( | |
450 error='unpacking %s: %s' % (node, e), | |
451 node=node) | |
452 state['skipread'].add(node) | |
453 | |
454 def emitrevisions(self, nodes, nodesorder=None, revisiondata=False, | |
455 assumehaveparentrevisions=False, | |
456 deltamode=repository.CG_DELTAMODE_STD): | |
457 # TODO this will probably break on some ordering options. | |
458 nodes = [n for n in nodes if n != nullid] | |
459 if not nodes: | |
460 return | |
461 for delta in storageutil.emitrevisions( | |
462 self, nodes, nodesorder, simplestorerevisiondelta, | |
463 revisiondata=revisiondata, | |
464 assumehaveparentrevisions=assumehaveparentrevisions, | |
465 deltamode=deltamode): | |
466 yield delta | |
467 | |
412 def add(self, text, meta, transaction, linkrev, p1, p2): | 468 def add(self, text, meta, transaction, linkrev, p1, p2): |
413 if meta or text.startswith(b'\1\n'): | 469 if meta or text.startswith(b'\1\n'): |
414 text = storageutil.packmeta(meta, text) | 470 text = storageutil.packmeta(meta, text) |
415 | 471 |
416 return self.addrevision(text, transaction, linkrev, p1, p2) | 472 return self.addrevision(text, transaction, linkrev, p1, p2) |
487 self._addrawrevision(node, text, transaction, linkrev, p1, p2, | 543 self._addrawrevision(node, text, transaction, linkrev, p1, p2, |
488 flags) | 544 flags) |
489 | 545 |
490 if addrevisioncb: | 546 if addrevisioncb: |
491 addrevisioncb(self, node) | 547 addrevisioncb(self, node) |
492 | |
493 return nodes | 548 return nodes |
549 | |
550 def _headrevs(self): | |
551 # Assume all revisions are heads by default. | |
552 revishead = {rev: True for rev in self._indexbyrev} | |
553 | |
554 for rev, entry in self._indexbyrev.items(): | |
555 # Unset head flag for all seen parents. | |
556 revishead[self.rev(entry[b'p1'])] = False | |
557 revishead[self.rev(entry[b'p2'])] = False | |
558 | |
559 return [rev for rev, ishead in sorted(revishead.items()) | |
560 if ishead] | |
494 | 561 |
495 def heads(self, start=None, stop=None): | 562 def heads(self, start=None, stop=None): |
496 # This is copied from revlog.py. | 563 # This is copied from revlog.py. |
497 if start is None and stop is None: | 564 if start is None and stop is None: |
498 if not len(self): | 565 if not len(self): |
499 return [nullid] | 566 return [nullid] |
500 return [self.node(r) for r in self.headrevs()] | 567 return [self.node(r) for r in self._headrevs()] |
501 | 568 |
502 if start is None: | 569 if start is None: |
503 start = nullid | 570 start = nullid |
504 if stop is None: | 571 if stop is None: |
505 stop = [] | 572 stop = [] |
535 elif p == nullrev: | 602 elif p == nullrev: |
536 c.append(self.node(r)) | 603 c.append(self.node(r)) |
537 return c | 604 return c |
538 | 605 |
539 def getstrippoint(self, minlink): | 606 def getstrippoint(self, minlink): |
540 | 607 return storageutil.resolvestripinfo( |
541 # This is largely a copy of revlog.getstrippoint(). | 608 minlink, len(self) - 1, self._headrevs(), self.linkrev, |
542 brokenrevs = set() | 609 self.parentrevs) |
543 strippoint = len(self) | |
544 | |
545 heads = {} | |
546 futurelargelinkrevs = set() | |
547 for head in self.heads(): | |
548 headlinkrev = self.linkrev(self.rev(head)) | |
549 heads[head] = headlinkrev | |
550 if headlinkrev >= minlink: | |
551 futurelargelinkrevs.add(headlinkrev) | |
552 | |
553 # This algorithm involves walking down the rev graph, starting at the | |
554 # heads. Since the revs are topologically sorted according to linkrev, | |
555 # once all head linkrevs are below the minlink, we know there are | |
556 # no more revs that could have a linkrev greater than minlink. | |
557 # So we can stop walking. | |
558 while futurelargelinkrevs: | |
559 strippoint -= 1 | |
560 linkrev = heads.pop(strippoint) | |
561 | |
562 if linkrev < minlink: | |
563 brokenrevs.add(strippoint) | |
564 else: | |
565 futurelargelinkrevs.remove(linkrev) | |
566 | |
567 for p in self.parentrevs(strippoint): | |
568 if p != nullrev: | |
569 plinkrev = self.linkrev(p) | |
570 heads[p] = plinkrev | |
571 if plinkrev >= minlink: | |
572 futurelargelinkrevs.add(plinkrev) | |
573 | |
574 return strippoint, brokenrevs | |
575 | 610 |
576 def strip(self, minlink, transaction): | 611 def strip(self, minlink, transaction): |
577 if not len(self): | 612 if not len(self): |
578 return | 613 return |
579 | 614 |
629 repo.__class__ = simplestorerepo | 664 repo.__class__ = simplestorerepo |
630 | 665 |
631 def featuresetup(ui, supported): | 666 def featuresetup(ui, supported): |
632 supported.add(REQUIREMENT) | 667 supported.add(REQUIREMENT) |
633 | 668 |
634 def newreporequirements(orig, ui): | 669 def newreporequirements(orig, ui, createopts): |
635 """Modifies default requirements for new repos to use the simple store.""" | 670 """Modifies default requirements for new repos to use the simple store.""" |
636 requirements = orig(ui) | 671 requirements = orig(ui, createopts) |
637 | 672 |
638 # These requirements are only used to affect creation of the store | 673 # These requirements are only used to affect creation of the store |
639 # object. We have our own store. So we can remove them. | 674 # object. We have our own store. So we can remove them. |
640 # TODO do this once we feel like taking the test hit. | 675 # TODO do this once we feel like taking the test hit. |
641 #if 'fncache' in requirements: | 676 #if 'fncache' in requirements: |
663 def extsetup(ui): | 698 def extsetup(ui): |
664 localrepo.featuresetupfuncs.add(featuresetup) | 699 localrepo.featuresetupfuncs.add(featuresetup) |
665 | 700 |
666 extensions.wrapfunction(localrepo, 'newreporequirements', | 701 extensions.wrapfunction(localrepo, 'newreporequirements', |
667 newreporequirements) | 702 newreporequirements) |
668 extensions.wrapfunction(store, 'store', makestore) | 703 extensions.wrapfunction(localrepo, 'makestore', makestore) |
669 extensions.wrapfunction(verify.verifier, '__init__', verifierinit) | 704 extensions.wrapfunction(verify.verifier, '__init__', verifierinit) |