comparison mercurial/transaction.py @ 39686:3d22aef3ecd5

transaction: make entries a private attribute (API) This attribute is tracking changes to append-only files. It is an implementation detail and should not be exposed as part of the public interface. But code in repair was accessing it, so it seemingly does belong as part of the public API. But that code in repair is making assumptions about how storage works and is grossly wrong when alternate storage backends are in play. We'll need some kind of "strip" API at the storage layer that knows how to handle things in a storage-agnostic manner. I don't think accessing a private attribute on the transaction is any worse than what this code is already doing. So I'm fine with violating the abstraction for transactions. And with this change, all per-instance attributes on transaction have been made private except for "changes" and "hookargs." Both are used by multiple consumers and look like they need to be part of the public interface. .. api:: Various attributes of ``transaction.transaction`` are now ``_`` prefixed to indicate they shouldn't be used by external consumers. Differential Revision: https://phab.mercurial-scm.org/D4634
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 17 Sep 2018 16:29:12 -0700
parents 4024c363cd33
children aca09df32819
comparison
equal deleted inserted replaced
39685:4024c363cd33 39686:3d22aef3ecd5
127 # a map to access file in various {location -> vfs} 127 # a map to access file in various {location -> vfs}
128 vfsmap = vfsmap.copy() 128 vfsmap = vfsmap.copy()
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.
228 228
229 def _addentry(self, file, offset, data): 229 def _addentry(self, file, offset, data):
230 """add a append-only entry to memory and on-disk state""" 230 """add a append-only entry to memory and on-disk state"""
231 if file in self._map or file in self._backupmap: 231 if file in self._map or file in self._backupmap:
232 return 232 return
233 self.entries.append((file, offset, data)) 233 self._entries.append((file, offset, data))
234 self._map[file] = len(self.entries) - 1 234 self._map[file] = len(self._entries) - 1
235 # add enough data to the journal to do the truncate 235 # add enough data to the journal to do the truncate
236 self._file.write("%s\0%d\n" % (file, offset)) 236 self._file.write("%s\0%d\n" % (file, offset))
237 self._file.flush() 237 self._file.flush()
238 238
239 @active 239 @active
350 return any 350 return any
351 351
352 @active 352 @active
353 def find(self, file): 353 def find(self, file):
354 if file in self._map: 354 if file in self._map:
355 return self.entries[self._map[file]] 355 return self._entries[self._map[file]]
356 if file in self._backupmap: 356 if file in self._backupmap:
357 return self._backupentries[self._backupmap[file]] 357 return self._backupentries[self._backupmap[file]]
358 return None 358 return None
359 359
360 @active 360 @active
365 ''' 365 '''
366 366
367 if file not in self._map: 367 if file not in self._map:
368 raise KeyError(file) 368 raise KeyError(file)
369 index = self._map[file] 369 index = self._map[file]
370 self.entries[index] = (file, offset, data) 370 self._entries[index] = (file, offset, data)
371 self._file.write("%s\0%d\n" % (file, offset)) 371 self._file.write("%s\0%d\n" % (file, offset))
372 self._file.flush() 372 self._file.flush()
373 373
374 @active 374 @active
375 def nest(self, name=r'<unnamed>'): 375 def nest(self, name=r'<unnamed>'):
484 if not c: 484 if not c:
485 raise 485 raise
486 # Abort may be raise by read only opener 486 # Abort may be raise by read only opener
487 self._report("couldn't remove %s: %s\n" 487 self._report("couldn't remove %s: %s\n"
488 % (vfs.join(b), inst)) 488 % (vfs.join(b), inst))
489 self.entries = [] 489 self._entries = []
490 self._writeundo() 490 self._writeundo()
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):
562 self._usages = 0 562 self._usages = 0
563 self._file.close() 563 self._file.close()
564 self._backupsfile.close() 564 self._backupsfile.close()
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
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, 581 _playback(self._journal, self._report, self._opener,
582 self._vfsmap, self.entries, self._backupentries, 582 self._vfsmap, self._entries, self._backupentries,
583 False, checkambigfiles=self._checkambigfiles) 583 False, 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: