# HG changeset patch # User Pierre-Yves David # Date 1697685595 -7200 # Node ID eba138890c6403e4ec9b18ba81daddfb3d670f29 # Parent 49d75cc12b8fb64487376b465f6d7b18127d29eb revlog: move entry writing in the inner object This is the second big piece of API we want to live on the inner object. With this the inner object have freedom it needs to implement things internally. (except for the delayed write feature of the changelog, that will be migrated in coming changesets) diff -r 49d75cc12b8f -r eba138890c64 mercurial/revlog.py --- a/mercurial/revlog.py Thu Oct 19 04:11:39 2023 +0200 +++ b/mercurial/revlog.py Thu Oct 19 05:19:55 2023 +0200 @@ -976,6 +976,72 @@ sidedata = sidedatautil.deserialize_sidedata(segment) return sidedata + def write_entry( + self, + transaction, + entry, + data, + link, + offset, + sidedata, + sidedata_offset, + index_end, + data_end, + sidedata_end, + ): + # Files opened in a+ mode have inconsistent behavior on various + # platforms. Windows requires that a file positioning call be made + # when the file handle transitions between reads and writes. See + # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other + # platforms, Python or the platform itself can be buggy. Some versions + # of Solaris have been observed to not append at the end of the file + # if the file was seeked to before the end. See issue4943 for more. + # + # We work around this issue by inserting a seek() before writing. + # Note: This is likely not necessary on Python 3. However, because + # the file handle is reused for reads and may be seeked there, we need + # to be careful before changing this. + if self._writinghandles is None: + msg = b'adding revision outside `revlog._writing` context' + raise error.ProgrammingError(msg) + ifh, dfh, sdfh = self._writinghandles + if index_end is None: + ifh.seek(0, os.SEEK_END) + else: + ifh.seek(index_end, os.SEEK_SET) + if dfh: + if data_end is None: + dfh.seek(0, os.SEEK_END) + else: + dfh.seek(data_end, os.SEEK_SET) + if sdfh: + sdfh.seek(sidedata_end, os.SEEK_SET) + + curr = len(self.index) - 1 + if not self.inline: + transaction.add(self.data_file, offset) + if self.sidedata_file: + transaction.add(self.sidedata_file, sidedata_offset) + transaction.add(self.index_file, curr * len(entry)) + if data[0]: + dfh.write(data[0]) + dfh.write(data[1]) + if sidedata: + sdfh.write(sidedata) + ifh.write(entry) + else: + offset += curr * self.index.entry_size + transaction.add(self.index_file, offset) + ifh.write(entry) + ifh.write(data[0]) + ifh.write(data[1]) + assert not sidedata + return ( + ifh.tell(), + dfh.tell() if dfh else None, + sdfh.tell() if sdfh else None, + ) + class revlog: """ @@ -3189,7 +3255,14 @@ return self._docket.data_end def _writeentry( - self, transaction, entry, data, link, offset, sidedata, sidedata_offset + self, + transaction, + entry, + data, + link, + offset, + sidedata, + sidedata_offset, ): # Files opened in a+ mode have inconsistent behavior on various # platforms. Windows requires that a file positioning call be made @@ -3203,53 +3276,29 @@ # Note: This is likely not necessary on Python 3. However, because # the file handle is reused for reads and may be seeked there, we need # to be careful before changing this. - if self._inner._writinghandles is None: - msg = b'adding revision outside `revlog._writing` context' - raise error.ProgrammingError(msg) - ifh, dfh, sdfh = self._inner._writinghandles - if self._docket is None: - ifh.seek(0, os.SEEK_END) - else: - ifh.seek(self._docket.index_end, os.SEEK_SET) - if dfh: - if self._docket is None: - dfh.seek(0, os.SEEK_END) - else: - dfh.seek(self._docket.data_end, os.SEEK_SET) - if sdfh: - sdfh.seek(self._docket.sidedata_end, os.SEEK_SET) - - curr = len(self) - 1 - if not self._inline: - transaction.add(self._datafile, offset) - if self._sidedatafile: - transaction.add(self._sidedatafile, sidedata_offset) - transaction.add(self._indexfile, curr * len(entry)) - if data[0]: - dfh.write(data[0]) - dfh.write(data[1]) - if sidedata: - sdfh.write(sidedata) - ifh.write(entry) - else: - offset += curr * self.index.entry_size - transaction.add(self._indexfile, offset) - ifh.write(entry) - ifh.write(data[0]) - ifh.write(data[1]) - assert not sidedata - self._enforceinlinesize(transaction) + index_end = data_end = sidedata_end = None if self._docket is not None: - # revlog-v2 always has 3 writing handles, help Pytype - wh1 = self._inner._writinghandles[0] - wh2 = self._inner._writinghandles[1] - wh3 = self._inner._writinghandles[2] - assert wh1 is not None - assert wh2 is not None - assert wh3 is not None - self._docket.index_end = wh1.tell() - self._docket.data_end = wh2.tell() - self._docket.sidedata_end = wh3.tell() + index_end = self._docket.index_end + data_end = self._docket.data_end + sidedata_end = self._docket.sidedata_end + + files_end = self._inner.write_entry( + transaction, + entry, + data, + link, + offset, + sidedata, + sidedata_offset, + index_end, + data_end, + sidedata_end, + ) + self._enforceinlinesize(transaction) + if self._docket is not None: + self._docket.index_end = files_end[0] + self._docket.data_end = files_end[1] + self._docket.sidedata_end = files_end[2] nodemaputil.setup_persistent_nodemap(transaction, self)