214 phase, node = _fphasesentry.unpack(entry) |
214 phase, node = _fphasesentry.unpack(entry) |
215 headsbyphase[phase].append(node) |
215 headsbyphase[phase].append(node) |
216 return headsbyphase |
216 return headsbyphase |
217 |
217 |
218 |
218 |
|
219 def _sortedrange_insert(data, idx, rev, t): |
|
220 merge_before = False |
|
221 if idx: |
|
222 r1, t1 = data[idx - 1] |
|
223 merge_before = r1[-1] + 1 == rev and t1 == t |
|
224 merge_after = False |
|
225 if idx < len(data): |
|
226 r2, t2 = data[idx] |
|
227 merge_after = r2[0] == rev + 1 and t2 == t |
|
228 |
|
229 if merge_before and merge_after: |
|
230 data[idx - 1] = (pycompat.xrange(r1[0], r2[-1] + 1), t) |
|
231 data.pop(idx) |
|
232 elif merge_before: |
|
233 data[idx - 1] = (pycompat.xrange(r1[0], rev + 1), t) |
|
234 elif merge_after: |
|
235 data[idx] = (pycompat.xrange(rev, r2[-1] + 1), t) |
|
236 else: |
|
237 data.insert(idx, (pycompat.xrange(rev, rev + 1), t)) |
|
238 |
|
239 |
|
240 def _sortedrange_split(data, idx, rev, t): |
|
241 r1, t1 = data[idx] |
|
242 if t == t1: |
|
243 return |
|
244 t = (t1[0], t[1]) |
|
245 if len(r1) == 1: |
|
246 data.pop(idx) |
|
247 _sortedrange_insert(data, idx, rev, t) |
|
248 elif r1[0] == rev: |
|
249 data[idx] = (pycompat.xrange(rev + 1, r1[-1] + 1), t1) |
|
250 _sortedrange_insert(data, idx, rev, t) |
|
251 elif r1[-1] == rev: |
|
252 data[idx] = (pycompat.xrange(r1[0], rev), t1) |
|
253 _sortedrange_insert(data, idx + 1, rev, t) |
|
254 else: |
|
255 data[idx : idx + 1] = [ |
|
256 (pycompat.xrange(r1[0], rev), t1), |
|
257 (pycompat.xrange(rev, rev + 1), t), |
|
258 (pycompat.xrange(rev + 1, r1[-1] + 1), t1), |
|
259 ] |
|
260 |
|
261 |
219 def _trackphasechange(data, rev, old, new): |
262 def _trackphasechange(data, rev, old, new): |
220 """add a phase move the <data> dictionnary |
263 """add a phase move to the <data> list of ranges |
221 |
264 |
222 If data is None, nothing happens. |
265 If data is None, nothing happens. |
223 """ |
266 """ |
224 if data is None: |
267 if data is None: |
225 return |
268 return |
226 existing = data.get(rev) |
269 |
227 if existing is not None: |
270 # If data is empty, create a one-revision range and done |
228 old = existing[0] |
271 if not data: |
229 data[rev] = (old, new) |
272 data.insert(0, (pycompat.xrange(rev, rev + 1), (old, new))) |
|
273 return |
|
274 |
|
275 low = 0 |
|
276 high = len(data) |
|
277 t = (old, new) |
|
278 while low < high: |
|
279 mid = (low + high) // 2 |
|
280 revs = data[mid][0] |
|
281 |
|
282 if rev in revs: |
|
283 _sortedrange_split(data, mid, rev, t) |
|
284 return |
|
285 |
|
286 if revs[0] == rev + 1: |
|
287 if mid and data[mid - 1][0][-1] == rev: |
|
288 _sortedrange_split(data, mid - 1, rev, t) |
|
289 else: |
|
290 _sortedrange_insert(data, mid, rev, t) |
|
291 return |
|
292 |
|
293 if revs[-1] == rev - 1: |
|
294 if mid + 1 < len(data) and data[mid + 1][0][0] == rev: |
|
295 _sortedrange_split(data, mid + 1, rev, t) |
|
296 else: |
|
297 _sortedrange_insert(data, mid + 1, rev, t) |
|
298 return |
|
299 |
|
300 if revs[0] > rev: |
|
301 high = mid |
|
302 else: |
|
303 low = mid + 1 |
|
304 |
|
305 if low == len(data): |
|
306 data.append((pycompat.xrange(rev, rev + 1), t)) |
|
307 return |
|
308 |
|
309 r1, t1 = data[low] |
|
310 if r1[0] > rev: |
|
311 data.insert(low, (pycompat.xrange(rev, rev + 1), t)) |
|
312 else: |
|
313 data.insert(low + 1, (pycompat.xrange(rev, rev + 1), t)) |
230 |
314 |
231 |
315 |
232 class phasecache(object): |
316 class phasecache(object): |
233 def __init__(self, repo, phasedefaults, _load=True): |
317 def __init__(self, repo, phasedefaults, _load=True): |
234 if _load: |
318 if _load: |
398 self._retractboundary(repo, tr, targetphase, nodes) |
482 self._retractboundary(repo, tr, targetphase, nodes) |
399 if tr is not None and b'phases' in tr.changes: |
483 if tr is not None and b'phases' in tr.changes: |
400 phasetracking = tr.changes[b'phases'] |
484 phasetracking = tr.changes[b'phases'] |
401 torev = repo.changelog.rev |
485 torev = repo.changelog.rev |
402 phase = self.phase |
486 phase = self.phase |
403 for n in nodes: |
487 revs = [torev(node) for node in nodes] |
404 rev = torev(n) |
488 revs.sort() |
|
489 for rev in revs: |
405 revphase = phase(repo, rev) |
490 revphase = phase(repo, rev) |
406 _trackphasechange(phasetracking, rev, None, revphase) |
491 _trackphasechange(phasetracking, rev, None, revphase) |
407 repo.invalidatevolatilesets() |
492 repo.invalidatevolatilesets() |
408 |
493 |
409 def advanceboundary(self, repo, tr, targetphase, nodes, dryrun=None): |
494 def advanceboundary(self, repo, tr, targetphase, nodes, dryrun=None): |
483 roots = oldroots[phase] |
568 roots = oldroots[phase] |
484 revs = set(repo.revs(b'%ln::%ld', roots, affected)) |
569 revs = set(repo.revs(b'%ln::%ld', roots, affected)) |
485 affected -= revs |
570 affected -= revs |
486 else: # public phase |
571 else: # public phase |
487 revs = affected |
572 revs = affected |
488 for r in revs: |
573 for r in sorted(revs): |
489 _trackphasechange(phasetracking, r, phase, targetphase) |
574 _trackphasechange(phasetracking, r, phase, targetphase) |
490 repo.invalidatevolatilesets() |
575 repo.invalidatevolatilesets() |
491 |
576 |
492 def _retractboundary(self, repo, tr, targetphase, nodes): |
577 def _retractboundary(self, repo, tr, targetphase, nodes): |
493 # Be careful to preserve shallow-copied values: do not update |
578 # Be careful to preserve shallow-copied values: do not update |