Mercurial > public > mercurial-scm > hg
comparison mercurial/revlog.py @ 51179:a93e52f0b6ff
changelog: disallow delayed write on inline changesets
Since this will never happens, we can make the situation invalid and to stop to
handling the associated the case.
This simplify the random access file reading too.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Thu, 07 Dec 2023 02:07:16 +0100 |
parents | dcaa2df1f688 |
children | 6ec8387eb0be |
comparison
equal
deleted
inserted
replaced
51178:dcaa2df1f688 | 51179:a93e52f0b6ff |
---|---|
365 default_compression_header, | 365 default_compression_header, |
366 ): | 366 ): |
367 self.opener = opener | 367 self.opener = opener |
368 self.index = index | 368 self.index = index |
369 | 369 |
370 self.__index_file = index_file | 370 self.index_file = index_file |
371 self.data_file = data_file | 371 self.data_file = data_file |
372 self.sidedata_file = sidedata_file | 372 self.sidedata_file = sidedata_file |
373 self.inline = inline | 373 self.inline = inline |
374 self.data_config = data_config | 374 self.data_config = data_config |
375 self.delta_config = delta_config | 375 self.delta_config = delta_config |
413 self.data_config.uncompressed_cache_count, | 413 self.data_config.uncompressed_cache_count, |
414 maxcost=65536, # some arbitrary initial value | 414 maxcost=65536, # some arbitrary initial value |
415 ) | 415 ) |
416 | 416 |
417 self._delay_buffer = None | 417 self._delay_buffer = None |
418 | |
419 @property | |
420 def index_file(self): | |
421 return self.__index_file | |
422 | |
423 @index_file.setter | |
424 def index_file(self, new_index_file): | |
425 self.__index_file = new_index_file | |
426 if self.inline: | |
427 self._segmentfile.filename = new_index_file | |
428 | 418 |
429 def __len__(self): | 419 def __len__(self): |
430 return len(self.index) | 420 return len(self.index) |
431 | 421 |
432 def clear_cache(self): | 422 def clear_cache(self): |
650 @contextlib.contextmanager | 640 @contextlib.contextmanager |
651 def reading(self): | 641 def reading(self): |
652 """Context manager that keeps data and sidedata files open for reading""" | 642 """Context manager that keeps data and sidedata files open for reading""" |
653 if len(self.index) == 0: | 643 if len(self.index) == 0: |
654 yield # nothing to be read | 644 yield # nothing to be read |
645 elif self._delay_buffer is not None and self.inline: | |
646 msg = "revlog with delayed write should not be inline" | |
647 raise error.ProgrammingError(msg) | |
655 else: | 648 else: |
656 with self._segmentfile.reading(): | 649 with self._segmentfile.reading(): |
657 with self._segmentfile_sidedata.reading(): | 650 with self._segmentfile_sidedata.reading(): |
658 yield | 651 yield |
659 | 652 |
1135 sdfh.write(sidedata) | 1128 sdfh.write(sidedata) |
1136 if self._delay_buffer is None: | 1129 if self._delay_buffer is None: |
1137 ifh.write(entry) | 1130 ifh.write(entry) |
1138 else: | 1131 else: |
1139 self._delay_buffer.append(entry) | 1132 self._delay_buffer.append(entry) |
1133 elif self._delay_buffer is not None: | |
1134 msg = b'invalid delayed write on inline revlog' | |
1135 raise error.ProgrammingError(msg) | |
1140 else: | 1136 else: |
1141 offset += curr * self.index.entry_size | 1137 offset += curr * self.index.entry_size |
1142 transaction.add(self.canonical_index_file, offset) | 1138 transaction.add(self.canonical_index_file, offset) |
1143 assert not sidedata | 1139 assert not sidedata |
1144 if self._delay_buffer is None: | 1140 ifh.write(entry) |
1145 ifh.write(entry) | 1141 ifh.write(data[0]) |
1146 ifh.write(data[0]) | 1142 ifh.write(data[1]) |
1147 ifh.write(data[1]) | |
1148 else: | |
1149 self._delay_buffer.append(entry) | |
1150 self._delay_buffer.append(data[0]) | |
1151 self._delay_buffer.append(data[1]) | |
1152 return ( | 1143 return ( |
1153 ifh.tell(), | 1144 ifh.tell(), |
1154 dfh.tell() if dfh else None, | 1145 dfh.tell() if dfh else None, |
1155 sdfh.tell() if sdfh else None, | 1146 sdfh.tell() if sdfh else None, |
1156 ) | 1147 ) |
1158 def _divert_index(self): | 1149 def _divert_index(self): |
1159 return self.index_file + b'.a' | 1150 return self.index_file + b'.a' |
1160 | 1151 |
1161 def delay(self): | 1152 def delay(self): |
1162 assert not self.is_open | 1153 assert not self.is_open |
1154 if self.inline: | |
1155 msg = "revlog with delayed write should not be inline" | |
1156 raise error.ProgrammingError(msg) | |
1163 if self._delay_buffer is not None or self._orig_index_file is not None: | 1157 if self._delay_buffer is not None or self._orig_index_file is not None: |
1164 # delay or divert already in place | 1158 # delay or divert already in place |
1165 return None | 1159 return None |
1166 elif len(self.index) == 0: | 1160 elif len(self.index) == 0: |
1167 self._orig_index_file = self.index_file | 1161 self._orig_index_file = self.index_file |
1171 if self.opener.exists(self.index_file): | 1165 if self.opener.exists(self.index_file): |
1172 self.opener.unlink(self.index_file) | 1166 self.opener.unlink(self.index_file) |
1173 return self.index_file | 1167 return self.index_file |
1174 else: | 1168 else: |
1175 self._delay_buffer = [] | 1169 self._delay_buffer = [] |
1176 if self.inline: | |
1177 self._segmentfile._delay_buffer = self._delay_buffer | |
1178 return None | 1170 return None |
1179 | 1171 |
1180 def write_pending(self): | 1172 def write_pending(self): |
1181 assert not self.is_open | 1173 assert not self.is_open |
1174 if self.inline: | |
1175 msg = "revlog with delayed write should not be inline" | |
1176 raise error.ProgrammingError(msg) | |
1182 if self._orig_index_file is not None: | 1177 if self._orig_index_file is not None: |
1183 return None, True | 1178 return None, True |
1184 any_pending = False | 1179 any_pending = False |
1185 pending_index_file = self._divert_index() | 1180 pending_index_file = self._divert_index() |
1186 if self.opener.exists(pending_index_file): | 1181 if self.opener.exists(pending_index_file): |
1193 with self.opener(pending_index_file, b'r+') as ifh: | 1188 with self.opener(pending_index_file, b'r+') as ifh: |
1194 ifh.seek(0, os.SEEK_END) | 1189 ifh.seek(0, os.SEEK_END) |
1195 ifh.write(b"".join(self._delay_buffer)) | 1190 ifh.write(b"".join(self._delay_buffer)) |
1196 any_pending = True | 1191 any_pending = True |
1197 self._delay_buffer = None | 1192 self._delay_buffer = None |
1198 if self.inline: | |
1199 self._segmentfile._delay_buffer = self._delay_buffer | |
1200 else: | |
1201 assert self._segmentfile._delay_buffer is None | |
1202 self._orig_index_file = self.index_file | 1193 self._orig_index_file = self.index_file |
1203 self.index_file = pending_index_file | 1194 self.index_file = pending_index_file |
1204 return self.index_file, any_pending | 1195 return self.index_file, any_pending |
1205 | 1196 |
1206 def finalize_pending(self): | 1197 def finalize_pending(self): |
1207 assert not self.is_open | 1198 assert not self.is_open |
1199 if self.inline: | |
1200 msg = "revlog with delayed write should not be inline" | |
1201 raise error.ProgrammingError(msg) | |
1208 | 1202 |
1209 delay = self._delay_buffer is not None | 1203 delay = self._delay_buffer is not None |
1210 divert = self._orig_index_file is not None | 1204 divert = self._orig_index_file is not None |
1211 | 1205 |
1212 if delay and divert: | 1206 if delay and divert: |
1214 elif delay: | 1208 elif delay: |
1215 if self._delay_buffer: | 1209 if self._delay_buffer: |
1216 with self.opener(self.index_file, b'r+') as ifh: | 1210 with self.opener(self.index_file, b'r+') as ifh: |
1217 ifh.seek(0, os.SEEK_END) | 1211 ifh.seek(0, os.SEEK_END) |
1218 ifh.write(b"".join(self._delay_buffer)) | 1212 ifh.write(b"".join(self._delay_buffer)) |
1219 self._segmentfile._delay_buffer = self._delay_buffer = None | 1213 self._delay_buffer = None |
1220 elif divert: | 1214 elif divert: |
1221 if self.opener.exists(self.index_file): | 1215 if self.opener.exists(self.index_file): |
1222 self.opener.rename( | 1216 self.opener.rename( |
1223 self.index_file, | 1217 self.index_file, |
1224 self._orig_index_file, | 1218 self._orig_index_file, |
2829 revlog has grown too large to be an inline revlog, it will convert it | 2823 revlog has grown too large to be an inline revlog, it will convert it |
2830 to use multiple index and data files. | 2824 to use multiple index and data files. |
2831 """ | 2825 """ |
2832 tiprev = len(self) - 1 | 2826 tiprev = len(self) - 1 |
2833 total_size = self.start(tiprev) + self.length(tiprev) | 2827 total_size = self.start(tiprev) + self.length(tiprev) |
2834 if not self._inline or total_size < _maxinline: | 2828 if not self._inline or (self._may_inline and total_size < _maxinline): |
2835 return | 2829 return |
2836 | 2830 |
2837 if self._docket is not None: | 2831 if self._docket is not None: |
2838 msg = b"inline revlog should not have a docket" | 2832 msg = b"inline revlog should not have a docket" |
2839 raise error.ProgrammingError(msg) | 2833 raise error.ProgrammingError(msg) |