comparison mercurial/changegroup.py @ 27867:7ced54ebf972

with: use context manager for transaction in changegroup apply (This needs some line wrapping due to the additional indent level. -mpm)
author Bryan O'Sullivan <bryano@fb.com>
date Fri, 15 Jan 2016 13:14:50 -0800
parents a09f143daaf4
children da5f23362517
comparison
equal deleted inserted replaced
27866:f54bf1f41566 27867:7ced54ebf972
321 def revmap(x): 321 def revmap(x):
322 return cl.rev(x) 322 return cl.rev(x)
323 323
324 changesets = files = revisions = 0 324 changesets = files = revisions = 0
325 325
326 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
327 try: 326 try:
328 # The transaction could have been created before and already 327 with repo.transaction("\n".join([srctype,
329 # carries source information. In this case we use the top 328 util.hidepassword(url)])) as tr:
330 # level data. We overwrite the argument because we need to use 329 # The transaction could have been created before and already
331 # the top level value (if they exist) in this function. 330 # carries source information. In this case we use the top
332 srctype = tr.hookargs.setdefault('source', srctype) 331 # level data. We overwrite the argument because we need to use
333 url = tr.hookargs.setdefault('url', url) 332 # the top level value (if they exist) in this function.
334 repo.hook('prechangegroup', throw=True, **tr.hookargs) 333 srctype = tr.hookargs.setdefault('source', srctype)
335 334 url = tr.hookargs.setdefault('url', url)
336 # write changelog data to temp files so concurrent readers 335 repo.hook('prechangegroup', throw=True, **tr.hookargs)
337 # will not see an inconsistent view 336
338 cl = repo.changelog 337 # write changelog data to temp files so concurrent readers
339 cl.delayupdate(tr) 338 # will not see an inconsistent view
340 oldheads = cl.heads() 339 cl = repo.changelog
341 340 cl.delayupdate(tr)
342 trp = weakref.proxy(tr) 341 oldheads = cl.heads()
343 # pull off the changeset group 342
344 repo.ui.status(_("adding changesets\n")) 343 trp = weakref.proxy(tr)
345 clstart = len(cl) 344 # pull off the changeset group
346 class prog(object): 345 repo.ui.status(_("adding changesets\n"))
347 def __init__(self, step, total): 346 clstart = len(cl)
348 self._step = step 347 class prog(object):
349 self._total = total 348 def __init__(self, step, total):
350 self._count = 1 349 self._step = step
351 def __call__(self): 350 self._total = total
352 repo.ui.progress(self._step, self._count, unit=_('chunks'), 351 self._count = 1
353 total=self._total) 352 def __call__(self):
354 self._count += 1 353 repo.ui.progress(self._step, self._count,
355 self.callback = prog(_('changesets'), expectedtotal) 354 unit=_('chunks'), total=self._total)
356 355 self._count += 1
357 efiles = set() 356 self.callback = prog(_('changesets'), expectedtotal)
358 def onchangelog(cl, node): 357
359 efiles.update(cl.read(node)[3]) 358 efiles = set()
360 359 def onchangelog(cl, node):
361 self.changelogheader() 360 efiles.update(cl.read(node)[3])
362 srccontent = cl.addgroup(self, csmap, trp, 361
363 addrevisioncb=onchangelog) 362 self.changelogheader()
364 efiles = len(efiles) 363 srccontent = cl.addgroup(self, csmap, trp,
365 364 addrevisioncb=onchangelog)
366 if not (srccontent or emptyok): 365 efiles = len(efiles)
367 raise error.Abort(_("received changelog group is empty")) 366
368 clend = len(cl) 367 if not (srccontent or emptyok):
369 changesets = clend - clstart 368 raise error.Abort(_("received changelog group is empty"))
370 repo.ui.progress(_('changesets'), None) 369 clend = len(cl)
371 370 changesets = clend - clstart
372 # pull off the manifest group 371 repo.ui.progress(_('changesets'), None)
373 repo.ui.status(_("adding manifests\n")) 372
374 self._unpackmanifests(repo, revmap, trp, prog, changesets) 373 # pull off the manifest group
375 374 repo.ui.status(_("adding manifests\n"))
376 needfiles = {} 375 self._unpackmanifests(repo, revmap, trp, prog, changesets)
377 if repo.ui.configbool('server', 'validate', default=False): 376
378 # validate incoming csets have their manifests 377 needfiles = {}
379 for cset in xrange(clstart, clend): 378 if repo.ui.configbool('server', 'validate', default=False):
380 mfnode = repo.changelog.read(repo.changelog.node(cset))[0] 379 # validate incoming csets have their manifests
381 mfest = repo.manifest.readdelta(mfnode) 380 for cset in xrange(clstart, clend):
382 # store file nodes we must see 381 mfnode = repo.changelog.read(
383 for f, n in mfest.iteritems(): 382 repo.changelog.node(cset))[0]
384 needfiles.setdefault(f, set()).add(n) 383 mfest = repo.manifest.readdelta(mfnode)
385 384 # store file nodes we must see
386 # process the files 385 for f, n in mfest.iteritems():
387 repo.ui.status(_("adding file changes\n")) 386 needfiles.setdefault(f, set()).add(n)
388 self.callback = None 387
389 pr = prog(_('files'), efiles) 388 # process the files
390 newrevs, newfiles = _addchangegroupfiles( 389 repo.ui.status(_("adding file changes\n"))
391 repo, self, revmap, trp, pr, needfiles) 390 self.callback = None
392 revisions += newrevs 391 pr = prog(_('files'), efiles)
393 files += newfiles 392 newrevs, newfiles = _addchangegroupfiles(
394 393 repo, self, revmap, trp, pr, needfiles)
395 dh = 0 394 revisions += newrevs
396 if oldheads: 395 files += newfiles
397 heads = cl.heads() 396
398 dh = len(heads) - len(oldheads) 397 dh = 0
399 for h in heads: 398 if oldheads:
400 if h not in oldheads and repo[h].closesbranch(): 399 heads = cl.heads()
401 dh -= 1 400 dh = len(heads) - len(oldheads)
402 htext = "" 401 for h in heads:
403 if dh: 402 if h not in oldheads and repo[h].closesbranch():
404 htext = _(" (%+d heads)") % dh 403 dh -= 1
405 404 htext = ""
406 repo.ui.status(_("added %d changesets" 405 if dh:
407 " with %d changes to %d files%s\n") 406 htext = _(" (%+d heads)") % dh
408 % (changesets, revisions, files, htext)) 407
409 repo.invalidatevolatilesets() 408 repo.ui.status(_("added %d changesets"
410 409 " with %d changes to %d files%s\n")
411 if changesets > 0: 410 % (changesets, revisions, files, htext))
412 if 'node' not in tr.hookargs: 411 repo.invalidatevolatilesets()
413 tr.hookargs['node'] = hex(cl.node(clstart)) 412
414 tr.hookargs['node_last'] = hex(cl.node(clend - 1)) 413 if changesets > 0:
415 hookargs = dict(tr.hookargs) 414 if 'node' not in tr.hookargs:
416 else: 415 tr.hookargs['node'] = hex(cl.node(clstart))
417 hookargs = dict(tr.hookargs) 416 tr.hookargs['node_last'] = hex(cl.node(clend - 1))
418 hookargs['node'] = hex(cl.node(clstart)) 417 hookargs = dict(tr.hookargs)
419 hookargs['node_last'] = hex(cl.node(clend - 1)) 418 else:
420 repo.hook('pretxnchangegroup', throw=True, **hookargs) 419 hookargs = dict(tr.hookargs)
421 420 hookargs['node'] = hex(cl.node(clstart))
422 added = [cl.node(r) for r in xrange(clstart, clend)] 421 hookargs['node_last'] = hex(cl.node(clend - 1))
423 publishing = repo.publishing() 422 repo.hook('pretxnchangegroup', throw=True, **hookargs)
424 if srctype in ('push', 'serve'): 423
425 # Old servers can not push the boundary themselves. 424 added = [cl.node(r) for r in xrange(clstart, clend)]
426 # New servers won't push the boundary if changeset already 425 publishing = repo.publishing()
427 # exists locally as secret 426 if srctype in ('push', 'serve'):
428 # 427 # Old servers can not push the boundary themselves.
429 # We should not use added here but the list of all change in 428 # New servers won't push the boundary if changeset already
430 # the bundle 429 # exists locally as secret
431 if publishing: 430 #
432 phases.advanceboundary(repo, tr, phases.public, srccontent) 431 # We should not use added here but the list of all change in
433 else: 432 # the bundle
434 # Those changesets have been pushed from the outside, their 433 if publishing:
435 # phases are going to be pushed alongside. Therefor 434 phases.advanceboundary(repo, tr, phases.public,
436 # `targetphase` is ignored. 435 srccontent)
437 phases.advanceboundary(repo, tr, phases.draft, srccontent) 436 else:
438 phases.retractboundary(repo, tr, phases.draft, added) 437 # Those changesets have been pushed from the
439 elif srctype != 'strip': 438 # outside, their phases are going to be pushed
440 # publishing only alter behavior during push 439 # alongside. Therefor `targetphase` is
441 # 440 # ignored.
442 # strip should not touch boundary at all 441 phases.advanceboundary(repo, tr, phases.draft,
443 phases.retractboundary(repo, tr, targetphase, added) 442 srccontent)
444 443 phases.retractboundary(repo, tr, phases.draft, added)
445 if changesets > 0: 444 elif srctype != 'strip':
446 if srctype != 'strip': 445 # publishing only alter behavior during push
447 # During strip, branchcache is invalid but coming call to 446 #
448 # `destroyed` will repair it. 447 # strip should not touch boundary at all
449 # In other case we can safely update cache on disk. 448 phases.retractboundary(repo, tr, targetphase, added)
450 branchmap.updatecache(repo.filtered('served')) 449
451 450 if changesets > 0:
452 def runhooks(): 451 if srctype != 'strip':
453 # These hooks run when the lock releases, not when the 452 # During strip, branchcache is invalid but
454 # transaction closes. So it's possible for the changelog 453 # coming call to `destroyed` will repair it.
455 # to have changed since we last saw it. 454 # In other case we can safely update cache on
456 if clstart >= len(repo): 455 # disk.
457 return 456 branchmap.updatecache(repo.filtered('served'))
458 457
459 # forcefully update the on-disk branch cache 458 def runhooks():
460 repo.ui.debug("updating the branch cache\n") 459 # These hooks run when the lock releases, not when the
461 repo.hook("changegroup", **hookargs) 460 # transaction closes. So it's possible for the changelog
462 461 # to have changed since we last saw it.
463 for n in added: 462 if clstart >= len(repo):
464 args = hookargs.copy() 463 return
465 args['node'] = hex(n) 464
466 del args['node_last'] 465 # forcefully update the on-disk branch cache
467 repo.hook("incoming", **args) 466 repo.ui.debug("updating the branch cache\n")
468 467 repo.hook("changegroup", **hookargs)
469 newheads = [h for h in repo.heads() if h not in oldheads] 468
470 repo.ui.log("incoming", 469 for n in added:
471 "%s incoming changes - new heads: %s\n", 470 args = hookargs.copy()
472 len(added), 471 args['node'] = hex(n)
473 ', '.join([hex(c[:6]) for c in newheads])) 472 del args['node_last']
474 473 repo.hook("incoming", **args)
475 tr.addpostclose('changegroup-runhooks-%020i' % clstart, 474
476 lambda tr: repo._afterlock(runhooks)) 475 newheads = [h for h in repo.heads()
477 476 if h not in oldheads]
478 tr.close() 477 repo.ui.log("incoming",
479 478 "%s incoming changes - new heads: %s\n",
479 len(added),
480 ', '.join([hex(c[:6]) for c in newheads]))
481
482 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
483 lambda tr: repo._afterlock(runhooks))
480 finally: 484 finally:
481 tr.release()
482 repo.ui.flush() 485 repo.ui.flush()
483 # never return 0 here: 486 # never return 0 here:
484 if dh < 0: 487 if dh < 0:
485 return dh - 1 488 return dh - 1
486 else: 489 else: