Mercurial > hg > mercurial-source
comparison mercurial/transaction.py @ 40462:77c4e2ae9f07
transaction: make journal a private attribute
This attribute tracks the name of the journal file. It is an
implementation detail of the current transaction and therefore
shouldn't be exposed as part of the interface. Let's mark it as
private.
Differential Revision: https://phab.mercurial-scm.org/D4624
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 17 Sep 2018 15:55:57 -0700 |
parents | da9ce63bfa9b |
children | d27fde3e023e |
comparison
equal
deleted
inserted
replaced
40461:da9ce63bfa9b | 40462:77c4e2ae9f07 |
---|---|
129 vfsmap[''] = opener # set default value | 129 vfsmap[''] = opener # set default value |
130 self._vfsmap = vfsmap | 130 self._vfsmap = vfsmap |
131 self.after = after | 131 self.after = after |
132 self.entries = [] | 132 self.entries = [] |
133 self.map = {} | 133 self.map = {} |
134 self.journal = journalname | 134 self._journal = journalname |
135 self._undoname = undoname | 135 self._undoname = undoname |
136 self._queue = [] | 136 self._queue = [] |
137 # A callback to validate transaction content before closing it. | 137 # A callback to validate transaction content before closing it. |
138 # should raise exception is anything is wrong. | 138 # should raise exception is anything is wrong. |
139 # target user is repository hooks. | 139 # target user is repository hooks. |
155 # transaction. | 155 # transaction. |
156 self.changes = {} | 156 self.changes = {} |
157 | 157 |
158 # a dict of arguments to be passed to hooks | 158 # a dict of arguments to be passed to hooks |
159 self.hookargs = {} | 159 self.hookargs = {} |
160 self.file = opener.open(self.journal, "w") | 160 self.file = opener.open(self._journal, "w") |
161 | 161 |
162 # a list of ('location', 'path', 'backuppath', cache) entries. | 162 # a list of ('location', 'path', 'backuppath', cache) entries. |
163 # - if 'backuppath' is empty, no file existed at backup time | 163 # - if 'backuppath' is empty, no file existed at backup time |
164 # - if 'path' is empty, this is a temporary transaction file | 164 # - if 'path' is empty, this is a temporary transaction file |
165 # - if 'location' is not empty, the path is outside main opener reach. | 165 # - if 'location' is not empty, the path is outside main opener reach. |
166 # use 'location' value as a key in a vfsmap to find the right 'vfs' | 166 # use 'location' value as a key in a vfsmap to find the right 'vfs' |
167 # (cache is currently unused) | 167 # (cache is currently unused) |
168 self._backupentries = [] | 168 self._backupentries = [] |
169 self._backupmap = {} | 169 self._backupmap = {} |
170 self._backupjournal = "%s.backupfiles" % self.journal | 170 self._backupjournal = "%s.backupfiles" % self._journal |
171 self._backupsfile = opener.open(self._backupjournal, 'w') | 171 self._backupsfile = opener.open(self._backupjournal, 'w') |
172 self._backupsfile.write('%d\n' % version) | 172 self._backupsfile.write('%d\n' % version) |
173 | 173 |
174 if createmode is not None: | 174 if createmode is not None: |
175 opener.chmod(self.journal, createmode & 0o666) | 175 opener.chmod(self._journal, createmode & 0o666) |
176 opener.chmod(self._backupjournal, createmode & 0o666) | 176 opener.chmod(self._backupjournal, createmode & 0o666) |
177 | 177 |
178 # hold file generations to be performed on commit | 178 # hold file generations to be performed on commit |
179 self._filegenerators = {} | 179 self._filegenerators = {} |
180 # hold callback to write pending data for hooks | 180 # hold callback to write pending data for hooks |
192 name = r'/'.join(self.names) | 192 name = r'/'.join(self.names) |
193 return (r'<transaction name=%s, count=%d, usages=%d>' % | 193 return (r'<transaction name=%s, count=%d, usages=%d>' % |
194 (name, self._count, self._usages)) | 194 (name, self._count, self._usages)) |
195 | 195 |
196 def __del__(self): | 196 def __del__(self): |
197 if self.journal: | 197 if self._journal: |
198 self._abort() | 198 self._abort() |
199 | 199 |
200 @active | 200 @active |
201 def startgroup(self): | 201 def startgroup(self): |
202 """delay registration of file entry | 202 """delay registration of file entry |
253 | 253 |
254 if file in self.map or file in self._backupmap: | 254 if file in self.map or file in self._backupmap: |
255 return | 255 return |
256 vfs = self._vfsmap[location] | 256 vfs = self._vfsmap[location] |
257 dirname, filename = vfs.split(file) | 257 dirname, filename = vfs.split(file) |
258 backupfilename = "%s.backup.%s" % (self.journal, filename) | 258 backupfilename = "%s.backup.%s" % (self._journal, filename) |
259 backupfile = vfs.reljoin(dirname, backupfilename) | 259 backupfile = vfs.reljoin(dirname, backupfilename) |
260 if vfs.exists(file): | 260 if vfs.exists(file): |
261 filepath = vfs.join(file) | 261 filepath = vfs.join(file) |
262 backuppath = vfs.join(backupfile) | 262 backuppath = vfs.join(backupfile) |
263 util.copyfile(filepath, backuppath, hardlink=hardlink) | 263 util.copyfile(filepath, backuppath, hardlink=hardlink) |
491 if self.after: | 491 if self.after: |
492 self.after() | 492 self.after() |
493 self.after = None # Help prevent cycles. | 493 self.after = None # Help prevent cycles. |
494 if self.opener.isfile(self._backupjournal): | 494 if self.opener.isfile(self._backupjournal): |
495 self.opener.unlink(self._backupjournal) | 495 self.opener.unlink(self._backupjournal) |
496 if self.opener.isfile(self.journal): | 496 if self.opener.isfile(self._journal): |
497 self.opener.unlink(self.journal) | 497 self.opener.unlink(self._journal) |
498 for l, _f, b, c in self._backupentries: | 498 for l, _f, b, c in self._backupentries: |
499 if l not in self._vfsmap and c: | 499 if l not in self._vfsmap and c: |
500 self.report("couldn't remove %s: unknown cache location" | 500 self.report("couldn't remove %s: unknown cache location" |
501 "%s\n" % (b, l)) | 501 "%s\n" % (b, l)) |
502 continue | 502 continue |
509 raise | 509 raise |
510 # Abort may be raise by read only opener | 510 # Abort may be raise by read only opener |
511 self.report("couldn't remove %s: %s\n" | 511 self.report("couldn't remove %s: %s\n" |
512 % (vfs.join(b), inst)) | 512 % (vfs.join(b), inst)) |
513 self._backupentries = [] | 513 self._backupentries = [] |
514 self.journal = None | 514 self._journal = None |
515 | 515 |
516 self.releasefn(self, True) # notify success of closing transaction | 516 self.releasefn(self, True) # notify success of closing transaction |
517 self.releasefn = None # Help prevent cycles. | 517 self.releasefn = None # Help prevent cycles. |
518 | 518 |
519 # run post close action | 519 # run post close action |
547 self.report("couldn't remove %s: unknown cache location" | 547 self.report("couldn't remove %s: unknown cache location" |
548 "%s\n" % (b, l)) | 548 "%s\n" % (b, l)) |
549 continue | 549 continue |
550 vfs = self._vfsmap[l] | 550 vfs = self._vfsmap[l] |
551 base, name = vfs.split(b) | 551 base, name = vfs.split(b) |
552 assert name.startswith(self.journal), name | 552 assert name.startswith(self._journal), name |
553 uname = name.replace(self.journal, self._undoname, 1) | 553 uname = name.replace(self._journal, self._undoname, 1) |
554 u = vfs.reljoin(base, uname) | 554 u = vfs.reljoin(base, uname) |
555 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True) | 555 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True) |
556 undobackupfile.write("%s\0%s\0%s\0%d\n" % (l, f, u, c)) | 556 undobackupfile.write("%s\0%s\0%s\0%d\n" % (l, f, u, c)) |
557 undobackupfile.close() | 557 undobackupfile.close() |
558 | 558 |
565 | 565 |
566 try: | 566 try: |
567 if not self.entries and not self._backupentries: | 567 if not self.entries and not self._backupentries: |
568 if self._backupjournal: | 568 if self._backupjournal: |
569 self.opener.unlink(self._backupjournal) | 569 self.opener.unlink(self._backupjournal) |
570 if self.journal: | 570 if self._journal: |
571 self.opener.unlink(self.journal) | 571 self.opener.unlink(self._journal) |
572 return | 572 return |
573 | 573 |
574 self.report(_("transaction abort!\n")) | 574 self.report(_("transaction abort!\n")) |
575 | 575 |
576 try: | 576 try: |
577 for cat in sorted(self._abortcallback): | 577 for cat in sorted(self._abortcallback): |
578 self._abortcallback[cat](self) | 578 self._abortcallback[cat](self) |
579 # Prevent double usage and help clear cycles. | 579 # Prevent double usage and help clear cycles. |
580 self._abortcallback = None | 580 self._abortcallback = None |
581 _playback(self.journal, self.report, self.opener, self._vfsmap, | 581 _playback(self._journal, self.report, self.opener, self._vfsmap, |
582 self.entries, self._backupentries, False, | 582 self.entries, self._backupentries, False, |
583 checkambigfiles=self.checkambigfiles) | 583 checkambigfiles=self.checkambigfiles) |
584 self.report(_("rollback completed\n")) | 584 self.report(_("rollback completed\n")) |
585 except BaseException: | 585 except BaseException: |
586 self.report(_("rollback failed - please run hg recover\n")) | 586 self.report(_("rollback failed - please run hg recover\n")) |
587 finally: | 587 finally: |
588 self.journal = None | 588 self._journal = None |
589 self.releasefn(self, False) # notify failure of transaction | 589 self.releasefn(self, False) # notify failure of transaction |
590 self.releasefn = None # Help prevent cycles. | 590 self.releasefn = None # Help prevent cycles. |
591 | 591 |
592 def rollback(opener, vfsmap, file, report, checkambigfiles=None): | 592 def rollback(opener, vfsmap, file, report, checkambigfiles=None): |
593 """Rolls back the transaction contained in the given file | 593 """Rolls back the transaction contained in the given file |