Show More
@@ -1111,6 +1111,28 b' default = "65K"' | |||||
1111 |
|
1111 | |||
1112 | [[items]] |
|
1112 | [[items]] | |
1113 | section = "experimental" |
|
1113 | section = "experimental" | |
|
1114 | name = "revlog.uncompressed-cache.enabled" | |||
|
1115 | default = true | |||
|
1116 | experimental = true | |||
|
1117 | documentation = """Enable some caching of uncompressed chunk, greatly boosting | |||
|
1118 | performance at the cost of memory usage.""" | |||
|
1119 | ||||
|
1120 | [[items]] | |||
|
1121 | section = "experimental" | |||
|
1122 | name = "revlog.uncompressed-cache.factor" | |||
|
1123 | default = 4 | |||
|
1124 | experimental = true | |||
|
1125 | documentation = """The size of the cache compared to the largest revision seen.""" | |||
|
1126 | ||||
|
1127 | [[items]] | |||
|
1128 | section = "experimental" | |||
|
1129 | name = "revlog.uncompressed-cache.count" | |||
|
1130 | default = 10000 | |||
|
1131 | experimental = true | |||
|
1132 | documentation = """The number of chunk cached.""" | |||
|
1133 | ||||
|
1134 | [[items]] | |||
|
1135 | section = "experimental" | |||
1114 | name = "stream-v3" |
|
1136 | name = "stream-v3" | |
1115 | default = false |
|
1137 | default = false | |
1116 |
|
1138 |
@@ -1089,6 +1089,16 b' def resolverevlogstorevfsoptions(ui, req' | |||||
1089 | if chunkcachesize is not None: |
|
1089 | if chunkcachesize is not None: | |
1090 | data_config.chunk_cache_size = chunkcachesize |
|
1090 | data_config.chunk_cache_size = chunkcachesize | |
1091 |
|
1091 | |||
|
1092 | if ui.configbool(b'experimental', b'revlog.uncompressed-cache.enabled'): | |||
|
1093 | factor = ui.configint( | |||
|
1094 | b'experimental', b'revlog.uncompressed-cache.factor' | |||
|
1095 | ) | |||
|
1096 | count = ui.configint( | |||
|
1097 | b'experimental', b'revlog.uncompressed-cache.count' | |||
|
1098 | ) | |||
|
1099 | data_config.uncompressed_cache_factor = factor | |||
|
1100 | data_config.uncompressed_cache_count = count | |||
|
1101 | ||||
1092 | delta_config.delta_both_parents = ui.configbool( |
|
1102 | delta_config.delta_both_parents = ui.configbool( | |
1093 | b'storage', b'revlog.optimize-delta-parent-choice' |
|
1103 | b'storage', b'revlog.optimize-delta-parent-choice' | |
1094 | ) |
|
1104 | ) |
@@ -295,6 +295,12 b' class DataConfig(_Config):' | |||||
295 | # How much data to read and cache into the raw revlog data cache. |
|
295 | # How much data to read and cache into the raw revlog data cache. | |
296 | chunk_cache_size = attr.ib(default=65536) |
|
296 | chunk_cache_size = attr.ib(default=65536) | |
297 |
|
297 | |||
|
298 | # The size of the uncompressed cache compared to the largest revision seen. | |||
|
299 | uncompressed_cache_factor = attr.ib(default=None) | |||
|
300 | ||||
|
301 | # The number of chunk cached | |||
|
302 | uncompressed_cache_count = attr.ib(default=None) | |||
|
303 | ||||
298 | # Allow sparse reading of the revlog data |
|
304 | # Allow sparse reading of the revlog data | |
299 | with_sparse_read = attr.ib(default=False) |
|
305 | with_sparse_read = attr.ib(default=False) | |
300 | # minimal density of a sparse read chunk |
|
306 | # minimal density of a sparse read chunk | |
@@ -396,6 +402,18 b' class _InnerRevlog:' | |||||
396 | # 3-tuple of (node, rev, text) for a raw revision. |
|
402 | # 3-tuple of (node, rev, text) for a raw revision. | |
397 | self._revisioncache = None |
|
403 | self._revisioncache = None | |
398 |
|
404 | |||
|
405 | # cache some uncompressed chunks | |||
|
406 | # rev β uncompressed_chunk | |||
|
407 | # | |||
|
408 | # the max cost is dynamically updated to be proportionnal to the | |||
|
409 | # size of revision we actually encounter. | |||
|
410 | self._uncompressed_chunk_cache = None | |||
|
411 | if self.data_config.uncompressed_cache_factor is not None: | |||
|
412 | self._uncompressed_chunk_cache = util.lrucachedict( | |||
|
413 | self.data_config.uncompressed_cache_count, | |||
|
414 | maxcost=65536, # some arbitrary initial value | |||
|
415 | ) | |||
|
416 | ||||
399 | self._delay_buffer = None |
|
417 | self._delay_buffer = None | |
400 |
|
418 | |||
401 | @property |
|
419 | @property | |
@@ -414,6 +432,8 b' class _InnerRevlog:' | |||||
414 | def clear_cache(self): |
|
432 | def clear_cache(self): | |
415 | assert not self.is_delaying |
|
433 | assert not self.is_delaying | |
416 | self._revisioncache = None |
|
434 | self._revisioncache = None | |
|
435 | if self._uncompressed_chunk_cache is not None: | |||
|
436 | self._uncompressed_chunk_cache.clear() | |||
417 | self._segmentfile.clear_cache() |
|
437 | self._segmentfile.clear_cache() | |
418 | self._segmentfile_sidedata.clear_cache() |
|
438 | self._segmentfile_sidedata.clear_cache() | |
419 |
|
439 | |||
@@ -865,18 +885,26 b' class _InnerRevlog:' | |||||
865 |
|
885 | |||
866 | Returns a str holding uncompressed data for the requested revision. |
|
886 | Returns a str holding uncompressed data for the requested revision. | |
867 | """ |
|
887 | """ | |
|
888 | if self._uncompressed_chunk_cache is not None: | |||
|
889 | uncomp = self._uncompressed_chunk_cache.get(rev) | |||
|
890 | if uncomp is not None: | |||
|
891 | return uncomp | |||
|
892 | ||||
868 | compression_mode = self.index[rev][10] |
|
893 | compression_mode = self.index[rev][10] | |
869 | data = self.get_segment_for_revs(rev, rev)[1] |
|
894 | data = self.get_segment_for_revs(rev, rev)[1] | |
870 | if compression_mode == COMP_MODE_PLAIN: |
|
895 | if compression_mode == COMP_MODE_PLAIN: | |
871 |
|
|
896 | uncomp = data | |
872 | elif compression_mode == COMP_MODE_DEFAULT: |
|
897 | elif compression_mode == COMP_MODE_DEFAULT: | |
873 |
|
|
898 | uncomp = self._decompressor(data) | |
874 | elif compression_mode == COMP_MODE_INLINE: |
|
899 | elif compression_mode == COMP_MODE_INLINE: | |
875 |
|
|
900 | uncomp = self.decompress(data) | |
876 | else: |
|
901 | else: | |
877 | msg = b'unknown compression mode %d' |
|
902 | msg = b'unknown compression mode %d' | |
878 | msg %= compression_mode |
|
903 | msg %= compression_mode | |
879 | raise error.RevlogError(msg) |
|
904 | raise error.RevlogError(msg) | |
|
905 | if self._uncompressed_chunk_cache is not None: | |||
|
906 | self._uncompressed_chunk_cache.insert(rev, uncomp, cost=len(uncomp)) | |||
|
907 | return uncomp | |||
880 |
|
908 | |||
881 | def _chunks(self, revs, targetsize=None): |
|
909 | def _chunks(self, revs, targetsize=None): | |
882 | """Obtain decompressed chunks for the specified revisions. |
|
910 | """Obtain decompressed chunks for the specified revisions. | |
@@ -899,17 +927,30 b' class _InnerRevlog:' | |||||
899 | iosize = self.index.entry_size |
|
927 | iosize = self.index.entry_size | |
900 | buffer = util.buffer |
|
928 | buffer = util.buffer | |
901 |
|
929 | |||
902 |
|
|
930 | fetched_revs = [] | |
903 |
|
|
931 | fadd = fetched_revs.append | |
|
932 | ||||
904 | chunks = [] |
|
933 | chunks = [] | |
905 | ladd = chunks.append |
|
934 | ladd = chunks.append | |
906 |
|
935 | |||
907 | if not self.data_config.with_sparse_read: |
|
936 | if self._uncompressed_chunk_cache is None: | |
908 |
|
|
937 | fetched_revs = revs | |
|
938 | else: | |||
|
939 | for rev in revs: | |||
|
940 | cached_value = self._uncompressed_chunk_cache.get(rev) | |||
|
941 | if cached_value is None: | |||
|
942 | fadd(rev) | |||
|
943 | else: | |||
|
944 | ladd((rev, cached_value)) | |||
|
945 | ||||
|
946 | if not fetched_revs: | |||
|
947 | slicedchunks = () | |||
|
948 | elif not self.data_config.with_sparse_read: | |||
|
949 | slicedchunks = (fetched_revs,) | |||
909 | else: |
|
950 | else: | |
910 | slicedchunks = deltautil.slicechunk( |
|
951 | slicedchunks = deltautil.slicechunk( | |
911 | self, |
|
952 | self, | |
912 | revs, |
|
953 | fetched_revs, | |
913 | targetsize=targetsize, |
|
954 | targetsize=targetsize, | |
914 | ) |
|
955 | ) | |
915 |
|
956 | |||
@@ -949,7 +990,10 b' class _InnerRevlog:' | |||||
949 | msg %= comp_mode |
|
990 | msg %= comp_mode | |
950 | raise error.RevlogError(msg) |
|
991 | raise error.RevlogError(msg) | |
951 | ladd((rev, c)) |
|
992 | ladd((rev, c)) | |
952 |
|
993 | if self._uncompressed_chunk_cache is not None: | ||
|
994 | self._uncompressed_chunk_cache.insert(rev, c, len(c)) | |||
|
995 | ||||
|
996 | chunks.sort() | |||
953 | return [x[1] for x in chunks] |
|
997 | return [x[1] for x in chunks] | |
954 |
|
998 | |||
955 | def raw_text(self, node, rev): |
|
999 | def raw_text(self, node, rev): | |
@@ -981,6 +1025,14 b' class _InnerRevlog:' | |||||
981 | if 0 <= rawsize: |
|
1025 | if 0 <= rawsize: | |
982 | targetsize = 4 * rawsize |
|
1026 | targetsize = 4 * rawsize | |
983 |
|
1027 | |||
|
1028 | if self._uncompressed_chunk_cache is not None: | |||
|
1029 | # dynamically update the uncompressed_chunk_cache size to the | |||
|
1030 | # largest revision we saw in this revlog. | |||
|
1031 | factor = self.data_config.uncompressed_cache_factor | |||
|
1032 | candidate_size = rawsize * factor | |||
|
1033 | if candidate_size > self._uncompressed_chunk_cache.maxcost: | |||
|
1034 | self._uncompressed_chunk_cache.maxcost = candidate_size | |||
|
1035 | ||||
984 | bins = self._chunks(chain, targetsize=targetsize) |
|
1036 | bins = self._chunks(chain, targetsize=targetsize) | |
985 | if basetext is None: |
|
1037 | if basetext is None: | |
986 | basetext = bytes(bins[0]) |
|
1038 | basetext = bytes(bins[0]) |
General Comments 0
You need to be logged in to leave comments.
Login now