revset: optimize "draft() & ::x" pattern
The `draft() & ::x` type query could be common for selecting one or more
draft feature branches being worked on.
Before this patch, `::x` may travel through the changelog DAG for a long
distance until it gets a smaller revision number than `min(draft())`. It
could be very slow on long changelog with distant (in terms of revision
numbers) drafts.
This patch adds a fast path for this situation, and will stop traveling the
changelog DAG once `::x` hits a non-draft revision.
The fast path also works for `secret()` and `not public()`.
To measure the performance difference, I used drawdag to create a repo that
emulates distant drafts:
DRAFT4
|
DRAFT3 # draft
/
PUBLIC9999 # public
|
PUBLIC9998
|
. DRAFT2
. |
. DRAFT1 # draft
| /
PUBLIC0001 # public
And measured the performance using the repo:
(BEFORE)
$ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
! wall 0.017132 comb 0.010000 user 0.010000 sys 0.000000 (best of 156)
$ hg perfrevset 'draft() & ::(all())'
! wall 0.024221 comb 0.030000 user 0.030000 sys 0.000000 (best of 113)
(AFTER)
$ hg perfrevset 'draft() & ::(DRAFT2+DRAFT4)'
! wall 0.000243 comb 0.000000 user 0.000000 sys 0.000000 (best of 9303)
$ hg perfrevset 'draft() & ::(all())'
! wall 0.004319 comb 0.000000 user 0.000000 sys 0.000000 (best of 655)
Differential Revision: https://phab.mercurial-scm.org/D441
#!/bin/sh
# setup config and various utility to test obsolescence marker exchanges tests
cat >> $TESTTMP/prune.sh << EOF
rev=\`hg log --hidden --template '{node}\n' --rev "\$3"\`
hg debugobsolete --record-parents \$1 "\$2" \$rev \
&& hg up --quiet 'max((::.) - obsolete())'
EOF
cat >> $HGRCPATH <<EOF
[web]
# We test http pull and push, drop authentication requirement
push_ssl = false
allow_push = *
[ui]
# simpler log output
logtemplate ="{node|short} ({phase}): {desc}\n"
[phases]
# non publishing server
publish=False
[experimental]
# reduce output changes
bundle2-output-capture=True
# enable evolution
evolution=all
[extensions]
# we need to strip some changeset for some test cases
hgext.strip=
[devel]
strip-obsmarkers = no
[alias]
# fix date used to create obsolete markers.
debugobsolete=debugobsolete -d '0 0'
# poor man substiture to the evolve 'hg prune'. using prune makes the test clearer and
prune = !sh $TESTTMP/prune.sh \$1 "\$2" "\$3"
EOF
mkcommit() {
echo "$1" > "$1"
hg add "$1"
hg ci -m "$1"
}
getid() {
hg log --hidden --template '{node}\n' --rev "$1"
}
setuprepos() {
echo creating test repo for test case $1
mkdir $1
cd $1
echo - pulldest
hg init pushdest
cd pushdest
mkcommit O
hg phase --public .
cd ..
echo - main
hg clone -q pushdest main
echo - pushdest
hg clone -q main pulldest
echo 'cd into `main` and proceed with env setup'
}
inspect_obsmarkers (){
# This exist as its own function to help the evolve extension reuse the tests as is.
# The evolve extensions version will includes more advances query (eg:
# related to obsmarkers discovery) to this.
echo 'obsstore content'
echo '================'
hg debugobsolete
}
dotest() {
# dotest TESTNAME [TARGETNODE] [PUSHFLAGS+]
#
# test exchange for the given test case.
#
# This function performs push and pull in all directions through all
# protocols and display the resulting obsolescence markers on all sides.
testcase=$1
shift
target="$1"
if [ $# -gt 0 ]; then
shift
fi
targetnode=""
desccall=""
cd $testcase
echo "## Running testcase $testcase"
if [ -n "$target" ]; then
desccall="desc("\'"$target"\'")"
targetnode="`hg -R main id -qr \"$desccall\"`"
echo "# testing echange of \"$target\" ($targetnode)"
fi
echo "## initial state"
echo "# obstore: main"
hg -R main debugobsolete | sort
echo "# obstore: pushdest"
hg -R pushdest debugobsolete | sort
echo "# obstore: pulldest"
hg -R pulldest debugobsolete | sort
if [ -n "$target" ]; then
echo "## pushing \"$target\"" from main to pushdest
hg -R main push -r "$desccall" $@ pushdest
else
echo "## pushing from main to pushdest"
hg -R main push pushdest $@
fi
echo "## post push state"
echo "# obstore: main"
hg -R main debugobsolete | sort
echo "# obstore: pushdest"
hg -R pushdest debugobsolete | sort
echo "# obstore: pulldest"
hg -R pulldest debugobsolete | sort
if [ -n "$target" ]; then
echo "## pulling \"$targetnode\"" from main into pulldest
hg -R pulldest pull -r $targetnode $@ main
else
echo "## pulling from main into pulldest"
hg -R pulldest pull main $@
fi
echo "## post pull state"
echo "# obstore: main"
hg -R main debugobsolete | sort
echo "# obstore: pushdest"
hg -R pushdest debugobsolete | sort
echo "# obstore: pulldest"
hg -R pulldest debugobsolete | sort
cd ..
}