Mercurial > hg
view tests/test-show-work.t @ 32558:aa91085cadf3
transaction: delete callbacks after use
Before this change, localrepository instances that performed multiple
transactions would leak transaction objects. This could occur when
running `hg convert`. When running `hg convert`, the leak would be
~90 MB per 10,000 changesets as measured with the Mercurial repo itself.
The leak I tracked down involved the "validate" closure from
localrepository.transaction(). It appeared to be keeping a
reference to the original transaction via __closure__. __del__
semantics and a circular reference involving the repo object
may have also come into play.
Attempting to refactor the "validate" closure proved to be
difficult because the "tr" reference in that closure may
reference an object that isn't created until transaction.__init__
is called. And the "validate" closure is passed as an argument to
transaction.__init__. Plus there is a giant warning comment in
"validate" about how hacky it is. I did not want to venture into
the dragon den.
Anyway, we've had problems with transactions causing leaks before.
The solution then (14e683d6b273) is the same as the solution in this
patch: drop references to callbacks after they are called. This
not only breaks cycles in core Mercurial but can help break cycles
in extensions that accidentally introduce them.
While I only tracked down a leak due to self.validator, since this is
the 2nd time I've tracked down leaks due to transaction callbacks I
figure enough is enough and we should prevent the class of leak from
occurring regardless of the variable. That's why all callback variables
are now nuked.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 26 May 2017 13:27:21 -0700 |
parents | 0bb157bebb43 |
children | 0b42c7ba46a6 |
line wrap: on
line source
$ cat >> $HGRCPATH << EOF > [extensions] > show = > EOF $ hg init repo0 $ cd repo0 Command works on an empty repo $ hg show work Single draft changeset shown $ echo 0 > foo $ hg -q commit -A -m 'commit 0' $ hg show work @ 9f171 commit 0 Even when it isn't the wdir $ hg -q up null $ hg show work o 9f171 commit 0 Single changeset is still there when public because it is a head $ hg phase --public -r 0 $ hg show work o 9f171 commit 0 A draft child will show both it and public parent $ hg -q up 0 $ echo 1 > foo $ hg commit -m 'commit 1' $ hg show work @ 181cc commit 1 o 9f171 commit 0 Multiple draft children will be shown $ echo 2 > foo $ hg commit -m 'commit 2' $ hg show work @ 128c8 commit 2 o 181cc commit 1 o 9f171 commit 0 Bumping first draft changeset to public will hide its parent $ hg phase --public -r 1 $ hg show work @ 128c8 commit 2 o 181cc commit 1 | ~ Multiple DAG heads will be shown $ hg -q up -r 1 $ echo 3 > foo $ hg commit -m 'commit 3' created new head $ hg show work @ f0abc commit 3 | o 128c8 commit 2 |/ o 181cc commit 1 | ~ Even when wdir is something else $ hg -q up null $ hg show work o f0abc commit 3 | o 128c8 commit 2 |/ o 181cc commit 1 | ~ Draft child shows public head (multiple heads) $ hg -q up 0 $ echo 4 > foo $ hg commit -m 'commit 4' created new head $ hg show work @ 668ca commit 4 | o f0abc commit 3 | | o 128c8 commit 2 | |/ | o 181cc commit 1 |/ o 9f171 commit 0 $ cd .. Branch name appears in output $ hg init branches $ cd branches $ echo 0 > foo $ hg -q commit -A -m 'commit 0' $ echo 1 > foo $ hg commit -m 'commit 1' $ echo 2 > foo $ hg commit -m 'commit 2' $ hg phase --public -r . $ hg -q up -r 1 $ hg branch mybranch marked working directory as branch mybranch (branches are permanent and global, did you want a bookmark?) $ echo 3 > foo $ hg commit -m 'commit 3' $ echo 4 > foo $ hg commit -m 'commit 4' $ hg show work @ f8dd3 (mybranch) commit 4 o 90cfc (mybranch) commit 3 | o 128c8 commit 2 |/ o 181cc commit 1 | ~ $ cd .. Bookmark name appears in output $ hg init bookmarks $ cd bookmarks $ echo 0 > foo $ hg -q commit -A -m 'commit 0' $ echo 1 > foo $ hg commit -m 'commit 1' $ echo 2 > foo $ hg commit -m 'commit 2' $ hg phase --public -r . $ hg bookmark @ $ hg -q up -r 1 $ echo 3 > foo $ hg commit -m 'commit 3' created new head $ echo 4 > foo $ hg commit -m 'commit 4' $ hg bookmark mybook $ hg show work @ cac82 (mybook) commit 4 o f0abc commit 3 | o 128c8 (@) commit 2 |/ o 181cc commit 1 | ~ $ cd ..