##// END OF EJS Templates
revlog: add a small cache of unfiltered chunk...
marmoute -
r52001:0250e450 default
parent child Browse files
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 return data
896 uncomp = data
872 elif compression_mode == COMP_MODE_DEFAULT:
897 elif compression_mode == COMP_MODE_DEFAULT:
873 return self._decompressor(data)
898 uncomp = self._decompressor(data)
874 elif compression_mode == COMP_MODE_INLINE:
899 elif compression_mode == COMP_MODE_INLINE:
875 return self.decompress(data)
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 l = []
930 fetched_revs = []
903 ladd = l.append
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 slicedchunks = (revs,)
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