tests/test-issue3084.t
author Gregory Szorc <gregory.szorc@gmail.com>
Thu, 06 Sep 2018 18:04:27 -0700
changeset 39570 f296c0b366c8
parent 24787 9d5c27890790
permissions -rw-r--r--
util: lower water mark when removing nodes after cost limit reached See the inline comment for the reasoning here. This is a pretty common strategy for garbage collectors, other cache-like primtives. The performance impact is substantial: $ hg perflrucachedict --size 4 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 100 ! inserts w/ cost limit ! wall 1.659181 comb 1.650000 user 1.650000 sys 0.000000 (best of 7) ! wall 1.722122 comb 1.720000 user 1.720000 sys 0.000000 (best of 6) ! mixed w/ cost limit ! wall 1.139955 comb 1.140000 user 1.140000 sys 0.000000 (best of 9) ! wall 1.182513 comb 1.180000 user 1.180000 sys 0.000000 (best of 9) $ hg perflrucachedict --size 1000 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 10000 ! inserts ! wall 0.679546 comb 0.680000 user 0.680000 sys 0.000000 (best of 15) ! sets ! wall 0.825147 comb 0.830000 user 0.830000 sys 0.000000 (best of 13) ! inserts w/ cost limit ! wall 25.105273 comb 25.080000 user 25.080000 sys 0.000000 (best of 3) ! wall 1.724397 comb 1.720000 user 1.720000 sys 0.000000 (best of 6) ! mixed ! wall 0.807096 comb 0.810000 user 0.810000 sys 0.000000 (best of 13) ! mixed w/ cost limit ! wall 12.104470 comb 12.070000 user 12.070000 sys 0.000000 (best of 3) ! wall 1.190563 comb 1.190000 user 1.190000 sys 0.000000 (best of 9) $ hg perflrucachedict --size 1000 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 10000 --mixedgetfreq 90 ! inserts ! wall 0.711177 comb 0.710000 user 0.710000 sys 0.000000 (best of 14) ! sets ! wall 0.846992 comb 0.850000 user 0.850000 sys 0.000000 (best of 12) ! inserts w/ cost limit ! wall 25.963028 comb 25.960000 user 25.960000 sys 0.000000 (best of 3) ! wall 2.184311 comb 2.180000 user 2.180000 sys 0.000000 (best of 5) ! mixed ! wall 0.728256 comb 0.730000 user 0.730000 sys 0.000000 (best of 14) ! mixed w/ cost limit ! wall 3.174256 comb 3.170000 user 3.170000 sys 0.000000 (best of 4) ! wall 0.773186 comb 0.770000 user 0.770000 sys 0.000000 (best of 13) $ hg perflrucachedict --size 100000 --gets 1000000 --sets 1000000 --mixed 1000000 --mixedgetfreq 90 --costlimit 5000000 ! gets ! wall 1.191368 comb 1.190000 user 1.190000 sys 0.000000 (best of 9) ! wall 1.195304 comb 1.190000 user 1.190000 sys 0.000000 (best of 9) ! inserts ! wall 0.950995 comb 0.950000 user 0.950000 sys 0.000000 (best of 11) ! inserts w/ cost limit ! wall 1.589732 comb 1.590000 user 1.590000 sys 0.000000 (best of 7) ! sets ! wall 1.094941 comb 1.100000 user 1.090000 sys 0.010000 (best of 9) ! mixed ! wall 0.936420 comb 0.940000 user 0.930000 sys 0.010000 (best of 10) ! mixed w/ cost limit ! wall 0.882780 comb 0.870000 user 0.870000 sys 0.000000 (best of 11) This puts us ~2x slower than caches without cost accounting. And for read-heavy workloads (the prime use cases for caches), performance is nearly identical. In the worst case (pure write workloads with cost accounting enabled), we're looking at ~1.5us per insert on large caches. That seems "fast enough." Differential Revision: https://phab.mercurial-scm.org/D4505


  $ echo "[extensions]" >> $HGRCPATH
  $ echo "largefiles =" >> $HGRCPATH

Create the repository outside $HOME since largefiles write to
$HOME/.cache/largefiles.

  $ hg init test
  $ cd test
  $ echo "root" > root
  $ hg add root
  $ hg commit -m "Root commit" --config extensions.largefiles=!

Ensure that .hg/largefiles isn't created before largefiles are added
#if unix-permissions
  $ chmod 555 .hg
#endif
  $ hg status
#if unix-permissions
  $ chmod 755 .hg
#endif

  $ test -f .hg/largefiles
  [1]

  $ echo "large" > foo
  $ hg add --large foo
  $ hg commit -m "Add foo as a largefile"

  $ hg update -r 0
  getting changed largefiles
  0 largefiles updated, 1 removed
  0 files updated, 0 files merged, 1 files removed, 0 files unresolved

  $ echo "normal" > foo
  $ hg add foo
  $ hg commit -m "Add foo as normal file"
  created new head

Normal file in the working copy, keeping the normal version:

  $ echo "n" | hg merge --config ui.interactive=Yes
  remote turned local normal file foo into a largefile
  use (l)argefile or keep (n)ormal file? n
  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)

  $ hg status
  $ cat foo
  normal

Normal file in the working copy, keeping the largefile version:

  $ hg update -q -C
  $ echo "l" | hg merge --config ui.interactive=Yes
  remote turned local normal file foo into a largefile
  use (l)argefile or keep (n)ormal file? l
  getting changed largefiles
  1 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)

  $ hg status
  M foo

  $ hg diff --nodates
  diff -r fa129ab6b5a7 .hglf/foo
  --- /dev/null
  +++ b/.hglf/foo
  @@ -0,0 +1,1 @@
  +7f7097b041ccf68cc5561e9600da4655d21c6d18
  diff -r fa129ab6b5a7 foo
  --- a/foo
  +++ /dev/null
  @@ -1,1 +0,0 @@
  -normal

  $ cat foo
  large

Largefile in the working copy, keeping the normal version:

  $ hg update -q -C -r 1
  $ echo "n" | hg merge --config ui.interactive=Yes
  remote turned local largefile foo into a normal file
  keep (l)argefile or use (n)ormal file? n
  getting changed largefiles
  0 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)

  $ hg status
  M foo

  $ hg diff --nodates
  diff -r ff521236428a .hglf/foo
  --- a/.hglf/foo
  +++ /dev/null
  @@ -1,1 +0,0 @@
  -7f7097b041ccf68cc5561e9600da4655d21c6d18
  diff -r ff521236428a foo
  --- /dev/null
  +++ b/foo
  @@ -0,0 +1,1 @@
  +normal

  $ cat foo
  normal

Largefile in the working copy, keeping the largefile version:

  $ hg update -q -C -r 1
  $ echo "l" | hg merge --config ui.interactive=Yes
  remote turned local largefile foo into a normal file
  keep (l)argefile or use (n)ormal file? l
  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)

  $ hg status

  $ cat foo
  large

Whatever ... commit something so we can invoke merge when updating

  $ hg commit -m '3: Merge'

Updating from largefile to normal - no reason to prompt

  $ hg up -r 2
  getting changed largefiles
  0 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ cat foo
  normal

(the update above used to leave the working dir in a very weird state - clean it
  $ hg up -qr null
  $ hg up -qr 2
)

Updating from normal to largefile - no reason to prompt

  $ hg up -r 3
  getting changed largefiles
  1 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  $ cat foo
  large

  $ cd ..


Systematic testing of merges involving largefiles:

Ancestor: normal  Parent: normal-id  Parent: large   result: large
Ancestor: normal  Parent: normal2    Parent: large   result: ?
Ancestor: large   Parent: large-id   Parent: normal  result: normal
Ancestor: large   Parent: large2     Parent: normal  result: ?

All cases should try merging both ways.

Prepare test repo:

  $ hg init merges
  $ cd merges

prepare cases with "normal" ancestor:

  $ hg up -qr null
  $ echo normal > f
  $ hg ci -Aqm "normal-ancestor"
  $ hg tag -l "normal-ancestor"
  $ touch f2
  $ hg ci -Aqm "normal-id"
  $ hg tag -l "normal-id"
  $ echo normal2 > f
  $ hg ci -m "normal2"
  $ hg tag -l "normal2"
  $ echo normal > f
  $ hg ci -Aqm "normal-same"
  $ hg tag -l "normal-same"
  $ hg up -qr "normal-ancestor"
  $ hg rm f
  $ echo large > f
  $ hg add --large f
  $ hg ci -qm "large"
  $ hg tag -l "large"

prepare cases with "large" ancestor:

  $ hg up -qr null
  $ echo large > f
  $ hg add --large f
  $ hg ci -qm "large-ancestor"
  $ hg tag -l "large-ancestor"
  $ touch f2
  $ hg ci -Aqm "large-id"
  $ hg tag -l "large-id"
  $ echo large2 > f
  $ hg ci -m "large2"
  $ hg tag -l "large2"
  $ echo large > f
  $ hg ci -Aqm "large-same"
  $ hg tag -l "large-same"
  $ hg up -qr "large-ancestor"
  $ hg rm f
  $ echo normal > f
  $ hg ci -qAm "normal"
  $ hg tag -l "normal"

  $ hg log -GT '{tags}'
  @  normal tip
  |
  | o  large-same
  | |
  | o  large2
  | |
  | o  large-id
  |/
  o  large-ancestor
  
  o  large
  |
  | o  normal-same
  | |
  | o  normal2
  | |
  | o  normal-id
  |/
  o  normal-ancestor
  


Ancestor: normal  Parent: normal-id  Parent: large   result: large

  $ hg up -Cqr normal-id
  $ hg merge -r large
  getting changed largefiles
  1 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

swap

  $ hg up -Cqr large
  $ hg merge -r normal-id
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

Ancestor: normal  Parent: normal-same  Parent: large   result: large

  $ hg up -Cqr normal-same
  $ hg merge -r large
  getting changed largefiles
  1 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

swap

  $ hg up -Cqr large
  $ hg merge -r normal-same
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

Ancestor: normal  Parent: normal2  Parent: large   result: ?
(annoying extra prompt ... but it do not do any serious harm)

  $ hg up -Cqr normal2
  $ hg merge -r large
  remote turned local normal file f into a largefile
  use (l)argefile or keep (n)ormal file? l
  getting changed largefiles
  1 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

  $ hg up -Cqr normal2
  $ echo n | hg merge -r large --config ui.interactive=Yes
  remote turned local normal file f into a largefile
  use (l)argefile or keep (n)ormal file? n
  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal2

swap

  $ hg up -Cqr large
  $ hg merge -r normal2
  remote turned local largefile f into a normal file
  keep (l)argefile or use (n)ormal file? l
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large

  $ hg up -Cqr large
  $ echo n | hg merge -r normal2 --config ui.interactive=Yes
  remote turned local largefile f into a normal file
  keep (l)argefile or use (n)ormal file? n
  getting changed largefiles
  0 largefiles updated, 0 removed
  2 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal2

Ancestor: large   Parent: large-id   Parent: normal  result: normal

  $ hg up -Cqr large-id
  $ hg merge -r normal
  getting changed largefiles
  0 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

swap

  $ hg up -Cqr normal
  $ hg merge -r large-id
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

Ancestor: large   Parent: large-same   Parent: normal  result: normal

  $ hg up -Cqr large-same
  $ hg merge -r normal
  getting changed largefiles
  0 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

swap

  $ hg up -Cqr normal
  $ hg merge -r large-same
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

Ancestor: large   Parent: large2   Parent: normal  result: ?
(annoying extra prompt ... but it do not do any serious harm)

  $ hg up -Cqr large2
  $ hg merge -r normal
  remote turned local largefile f into a normal file
  keep (l)argefile or use (n)ormal file? l
  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large2

  $ hg up -Cqr large2
  $ echo n | hg merge -r normal --config ui.interactive=Yes
  remote turned local largefile f into a normal file
  keep (l)argefile or use (n)ormal file? n
  getting changed largefiles
  0 largefiles updated, 0 removed
  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

swap

  $ hg up -Cqr normal
  $ hg merge -r large2
  remote turned local normal file f into a largefile
  use (l)argefile or keep (n)ormal file? l
  getting changed largefiles
  1 largefiles updated, 0 removed
  2 files updated, 0 files merged, 1 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  large2

  $ hg up -Cqr normal
  $ echo n | hg merge -r large2 --config ui.interactive=Yes
  remote turned local normal file f into a largefile
  use (l)argefile or keep (n)ormal file? n
  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
  (branch merge, don't forget to commit)
  $ cat f
  normal

  $ cd ..