comparison mercurial/revlog.py @ 9420:d0db168136dc

manifest/revlog: do not let the revlog cache mutable objects If a buffer of an mutable object is passed to revlog.addrevision(), the revlog will happily store it in its cache. Later when the revlog reuses the cached entry, if the manifest modified the object in-between, all kind of bugs appears. We fix it by: - passing immutable objects to addrevision() if they are already available - only storing the text in the cache if it's of str type Then we can remove the conversion of the cache entry to str() during retrieval. That was probably just there hiding the bug for the common cases but not really fixing it.
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Fri, 04 Sep 2009 10:47:55 +0200
parents 0001e49f1c11
children 1c4e4004f3a6
comparison
equal deleted inserted replaced
9419:3516a4e877c1 9420:d0db168136dc
971 def revision(self, node): 971 def revision(self, node):
972 """return an uncompressed revision of a given node""" 972 """return an uncompressed revision of a given node"""
973 if node == nullid: 973 if node == nullid:
974 return "" 974 return ""
975 if self._cache and self._cache[0] == node: 975 if self._cache and self._cache[0] == node:
976 return str(self._cache[2]) 976 return self._cache[2]
977 977
978 # look up what we need to read 978 # look up what we need to read
979 text = None 979 text = None
980 rev = self.rev(node) 980 rev = self.rev(node)
981 base = self.base(rev) 981 base = self.base(rev)
986 (self.index[rev][0] & 0xFFFF)) 986 (self.index[rev][0] & 0xFFFF))
987 987
988 # do we have useful data cached? 988 # do we have useful data cached?
989 if self._cache and self._cache[1] >= base and self._cache[1] < rev: 989 if self._cache and self._cache[1] >= base and self._cache[1] < rev:
990 base = self._cache[1] 990 base = self._cache[1]
991 text = str(self._cache[2]) 991 text = self._cache[2]
992 992
993 self._loadindex(base, rev + 1) 993 self._loadindex(base, rev + 1)
994 self._chunkraw(base, rev) 994 self._chunkraw(base, rev)
995 if text is None: 995 if text is None:
996 text = self._chunk(base) 996 text = self._chunk(base)
1109 ifh.write(entry) 1109 ifh.write(entry)
1110 ifh.write(data[0]) 1110 ifh.write(data[0])
1111 ifh.write(data[1]) 1111 ifh.write(data[1])
1112 self.checkinlinesize(transaction, ifh) 1112 self.checkinlinesize(transaction, ifh)
1113 1113
1114 self._cache = (node, curr, text) 1114 if type(text) == str: # only accept immutable objects
1115 self._cache = (node, curr, text)
1115 return node 1116 return node
1116 1117
1117 def ancestor(self, a, b): 1118 def ancestor(self, a, b):
1118 """calculate the least common ancestor of nodes a and b""" 1119 """calculate the least common ancestor of nodes a and b"""
1119 1120