Mercurial > public > mercurial-scm > hg
comparison mercurial/branchmap.py @ 41565:bf7fb97aecf1
branchmap: make branchcache responsible for reading
Encapsulate reading in a classmethod, to make it clear what kind of object is
being handled.
This is part of a stack of refactoring changes to help performance improvements
down the line.
Differential Revision: https://phab.mercurial-scm.org/D5635
author | Martijn Pieters <mj@octobus.net> |
---|---|
date | Mon, 21 Jan 2019 16:04:48 +0000 |
parents | 3461814417f3 |
children | eb7ce452e0fb |
comparison
equal
deleted
inserted
replaced
41564:a5493a251ad3 | 41565:bf7fb97aecf1 |
---|---|
28 | 28 |
29 calcsize = struct.calcsize | 29 calcsize = struct.calcsize |
30 pack_into = struct.pack_into | 30 pack_into = struct.pack_into |
31 unpack_from = struct.unpack_from | 31 unpack_from = struct.unpack_from |
32 | 32 |
33 def _filename(repo): | |
34 """name of a branchcache file for a given repo or repoview""" | |
35 filename = "branch2" | |
36 if repo.filtername: | |
37 filename = '%s-%s' % (filename, repo.filtername) | |
38 return filename | |
39 | |
40 def read(repo): | |
41 f = None | |
42 try: | |
43 f = repo.cachevfs(_filename(repo)) | |
44 lineiter = iter(f) | |
45 cachekey = next(lineiter).rstrip('\n').split(" ", 2) | |
46 last, lrev = cachekey[:2] | |
47 last, lrev = bin(last), int(lrev) | |
48 filteredhash = None | |
49 if len(cachekey) > 2: | |
50 filteredhash = bin(cachekey[2]) | |
51 bcache = branchcache(tipnode=last, tiprev=lrev, | |
52 filteredhash=filteredhash) | |
53 if not bcache.validfor(repo): | |
54 # invalidate the cache | |
55 raise ValueError(r'tip differs') | |
56 cl = repo.changelog | |
57 for l in lineiter: | |
58 l = l.rstrip('\n') | |
59 if not l: | |
60 continue | |
61 node, state, label = l.split(" ", 2) | |
62 if state not in 'oc': | |
63 raise ValueError(r'invalid branch state') | |
64 label = encoding.tolocal(label.strip()) | |
65 node = bin(node) | |
66 if not cl.hasnode(node): | |
67 raise ValueError( | |
68 r'node %s does not exist' % pycompat.sysstr(hex(node))) | |
69 bcache.setdefault(label, []).append(node) | |
70 if state == 'c': | |
71 bcache._closednodes.add(node) | |
72 | |
73 except (IOError, OSError): | |
74 return None | |
75 | |
76 except Exception as inst: | |
77 if repo.ui.debugflag: | |
78 msg = 'invalid branchheads cache' | |
79 if repo.filtername is not None: | |
80 msg += ' (%s)' % repo.filtername | |
81 msg += ': %s\n' | |
82 repo.ui.debug(msg % pycompat.bytestr(inst)) | |
83 bcache = None | |
84 | |
85 finally: | |
86 if f: | |
87 f.close() | |
88 | |
89 return bcache | |
90 | 33 |
91 ### Nearest subset relation | 34 ### Nearest subset relation |
92 # Nearest subset of filter X is a filter Y so that: | 35 # Nearest subset of filter X is a filter Y so that: |
93 # * Y is included in X, | 36 # * Y is included in X, |
94 # * X - Y is as small as possible. | 37 # * X - Y is as small as possible. |
105 filtername = repo.filtername | 48 filtername = repo.filtername |
106 bcache = repo._branchcaches.get(filtername) | 49 bcache = repo._branchcaches.get(filtername) |
107 | 50 |
108 revs = [] | 51 revs = [] |
109 if bcache is None or not bcache.validfor(repo): | 52 if bcache is None or not bcache.validfor(repo): |
110 bcache = read(repo) | 53 bcache = branchcache.fromfile(repo) |
111 if bcache is None: | 54 if bcache is None: |
112 subsetname = subsettable.get(filtername) | 55 subsetname = subsettable.get(filtername) |
113 if subsetname is None: | 56 if subsetname is None: |
114 bcache = branchcache() | 57 bcache = branchcache() |
115 else: | 58 else: |
179 | 122 |
180 The open/closed state is represented by a single letter 'o' or 'c'. | 123 The open/closed state is represented by a single letter 'o' or 'c'. |
181 This field can be used to avoid changelog reads when determining if a | 124 This field can be used to avoid changelog reads when determining if a |
182 branch head closes a branch or not. | 125 branch head closes a branch or not. |
183 """ | 126 """ |
127 @classmethod | |
128 def fromfile(cls, repo): | |
129 f = None | |
130 try: | |
131 f = repo.cachevfs(cls._filename(repo)) | |
132 lineiter = iter(f) | |
133 cachekey = next(lineiter).rstrip('\n').split(" ", 2) | |
134 last, lrev = cachekey[:2] | |
135 last, lrev = bin(last), int(lrev) | |
136 filteredhash = None | |
137 if len(cachekey) > 2: | |
138 filteredhash = bin(cachekey[2]) | |
139 bcache = cls(tipnode=last, tiprev=lrev, filteredhash=filteredhash) | |
140 if not bcache.validfor(repo): | |
141 # invalidate the cache | |
142 raise ValueError(r'tip differs') | |
143 cl = repo.changelog | |
144 for line in lineiter: | |
145 line = line.rstrip('\n') | |
146 if not line: | |
147 continue | |
148 node, state, label = line.split(" ", 2) | |
149 if state not in 'oc': | |
150 raise ValueError(r'invalid branch state') | |
151 label = encoding.tolocal(label.strip()) | |
152 node = bin(node) | |
153 if not cl.hasnode(node): | |
154 raise ValueError( | |
155 r'node %s does not exist' % pycompat.sysstr(hex(node))) | |
156 bcache.setdefault(label, []).append(node) | |
157 if state == 'c': | |
158 bcache._closednodes.add(node) | |
159 | |
160 except (IOError, OSError): | |
161 return None | |
162 | |
163 except Exception as inst: | |
164 if repo.ui.debugflag: | |
165 msg = 'invalid branchheads cache' | |
166 if repo.filtername is not None: | |
167 msg += ' (%s)' % repo.filtername | |
168 msg += ': %s\n' | |
169 repo.ui.debug(msg % pycompat.bytestr(inst)) | |
170 bcache = None | |
171 | |
172 finally: | |
173 if f: | |
174 f.close() | |
175 | |
176 return bcache | |
177 | |
178 @staticmethod | |
179 def _filename(repo): | |
180 """name of a branchcache file for a given repo or repoview""" | |
181 filename = "branch2" | |
182 if repo.filtername: | |
183 filename = '%s-%s' % (filename, repo.filtername) | |
184 return filename | |
184 | 185 |
185 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev, | 186 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev, |
186 filteredhash=None, closednodes=None): | 187 filteredhash=None, closednodes=None): |
187 super(branchcache, self).__init__(entries) | 188 super(branchcache, self).__init__(entries) |
188 self.tipnode = tipnode | 189 self.tipnode = tipnode |
244 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash, | 245 return branchcache(self, self.tipnode, self.tiprev, self.filteredhash, |
245 self._closednodes) | 246 self._closednodes) |
246 | 247 |
247 def write(self, repo): | 248 def write(self, repo): |
248 try: | 249 try: |
249 f = repo.cachevfs(_filename(repo), "w", atomictemp=True) | 250 f = repo.cachevfs(self._filename(repo), "w", atomictemp=True) |
250 cachekey = [hex(self.tipnode), '%d' % self.tiprev] | 251 cachekey = [hex(self.tipnode), '%d' % self.tiprev] |
251 if self.filteredhash is not None: | 252 if self.filteredhash is not None: |
252 cachekey.append(hex(self.filteredhash)) | 253 cachekey.append(hex(self.filteredhash)) |
253 f.write(" ".join(cachekey) + '\n') | 254 f.write(" ".join(cachekey) + '\n') |
254 nodecount = 0 | 255 nodecount = 0 |