From 66e484fd8655b5b6105cc9f72e8952b9e158715d Mon Sep 17 00:00:00 2001 From: Christian Schilling Date: Thu, 3 Feb 2022 21:52:38 +0100 Subject: [PATCH] Add more optimiser rules for subtract Changing just the prefix part of a mapping in very large workspaces resulted in very expensive filtering that can be avoided by applying these additional rules. --- src/filter/opt.rs | 30 ++++++++ tests/filter/pretty_print.t | 21 ++++-- .../workspace_modify_chain_prefix_subtree.t | 69 +++---------------- 3 files changed, 56 insertions(+), 64 deletions(-) diff --git a/src/filter/opt.rs b/src/filter/opt.rs index ff07755ba..9d720da50 100644 --- a/src/filter/opt.rs +++ b/src/filter/opt.rs @@ -276,6 +276,22 @@ fn iterate(filter: Filter) -> Filter { filter } +fn is_prefix(op: Op) -> bool { + match op { + Op::Prefix(_) => true, + _ => false, + } +} + +fn prefix_of(op: Op) -> Filter { + let last = to_op(last_chain(to_filter(Op::Nop), to_filter(op.clone())).1); + to_filter(if is_prefix(last.clone()) { + last + } else { + Op::Nop + }) +} + /* * Attempt to apply one optimization rule to a filter. If no rule applies the input * is returned. @@ -335,6 +351,8 @@ fn step(filter: Filter) -> Filter { } Op::Chain(a, b) => match (to_op(a), to_op(b)) { (Op::Chain(x, y), b) => Op::Chain(x, to_filter(Op::Chain(y, to_filter(b)))), + (Op::Prefix(a), Op::Subdir(b)) if a == b => Op::Nop, + (Op::Prefix(a), Op::Subdir(b)) if a != b => Op::Empty, (Op::Nop, b) => b, (a, Op::Nop) => a, (Op::Empty, _) => Op::Empty, @@ -347,10 +365,22 @@ fn step(filter: Filter) -> Filter { Op::Subtract(a, b) if a == b => Op::Empty, Op::Subtract(af, bf) => match (to_op(af), to_op(bf)) { (Op::Empty, _) => Op::Empty, + (_, Op::Nop) => Op::Empty, (a, Op::Empty) => a, (Op::Chain(a, b), Op::Chain(c, d)) if a == c => { Op::Chain(a, to_filter(Op::Subtract(b, d))) } + (_, b) if prefix_of(b.clone()) != to_filter(Op::Nop) => { + Op::Subtract(af, last_chain(to_filter(Op::Nop), to_filter(b.clone())).0) + } + (a, _) if prefix_of(a.clone()) != to_filter(Op::Nop) => Op::Chain( + to_filter(Op::Subtract( + last_chain(to_filter(Op::Nop), to_filter(a.clone())).0, + bf, + )), + prefix_of(a), + ), + (_, b) if is_prefix(b.clone()) => Op::Subtract(af, to_filter(Op::Nop)), _ if common_post(&vec![af, bf]).is_some() => { let (cp, rest) = common_post(&vec![af, bf]).unwrap(); Op::Chain(to_filter(Op::Subtract(rest[0], rest[1])), cp) diff --git a/tests/filter/pretty_print.t b/tests/filter/pretty_print.t index 5ef91ab50..5de4a2895 100644 --- a/tests/filter/pretty_print.t +++ b/tests/filter/pretty_print.t @@ -27,6 +27,15 @@ :/b ] + $ josh-filter -p :subtract[a=:[::x/,::y/,::z/],b=:[::x/,::y/]] + a/z = :/z + $ josh-filter -p :subtract[a=:[::x/,::y/,::z/],a=:[::x/,::y/]] + a/z = :/z + $ josh-filter -p :subtract[a=:[::x/,::y/],a=:[::x/,::y/]] + :empty + $ josh-filter -p :subtract[a=:[::x/,::y/],b=:[::x/,::y/]] + :empty + $ cat > f < a/b = :/a/b > a/j = :/a/j @@ -71,9 +80,9 @@ > ]] > EOF $ josh-filter -p --file f - :subtract[ - ::b/ - ::c/ + b = :subtract[ + :/b + :/c ] $ cat > f < EOF $ josh-filter -p --file f - :subtract[ - x/g = :/a/x/g - p/au/bs/i1 = :/m/bs/m2/i/tc/i1 + x/g = :subtract[ + :/a/x/g + :/m/bs/m2/i/tc/i1 ] $ cat > f < file1 1> /dev/null $ git add . $ git commit -m "initial" 1> /dev/null - $ git checkout -b new1 - Switched to a new branch 'new1' + $ git checkout -q -b new1 $ echo content > newfile1 1> /dev/null $ git add . $ git commit -m "add newfile1" 1> /dev/null - $ git checkout master 1> /dev/null - Switched to branch 'master' + $ git checkout -q master 1> /dev/null $ echo content > newfile_master 1> /dev/null $ git add . $ git commit -m "newfile master" 1> /dev/null @@ -116,25 +113,7 @@ * add file2 * add file1 - $ git checkout HEAD~1 1> /dev/null - Note: switching to 'HEAD~1'. - - You are in 'detached HEAD' state. You can look around, make experimental - changes and commit them, and you can discard any commits you make in this - state without impacting any branches by switching back to a branch. - - If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -c with the switch command. Example: - - git switch -c - - Or undo this operation with: - - git switch - - - Turn off this advice by setting config variable advice.detachedHead to false - - HEAD is now at a4b6822 add workspace + $ git checkout -q HEAD~1 1> /dev/null $ tree . |-- a @@ -147,9 +126,7 @@ 4 directories, 3 files - $ git checkout HEAD~1 1> /dev/null - Previous HEAD position was a4b6822 add workspace - HEAD is now at 2a03ad0 add file2 + $ git checkout -q HEAD~1 1> /dev/null $ tree . |-- a @@ -161,9 +138,7 @@ 4 directories, 2 files - $ git checkout master 1> /dev/null - Previous HEAD position was 2a03ad0 add file2 - Switched to branch 'master' + $ git checkout -q master 1> /dev/null $ echo newfile_1_contents > c/subsub/newfile_1 $ git rm c/subsub/file1 @@ -282,25 +257,7 @@ Note that ws/d/ is now present in the ws cat: sub1/subsub/file1: No such file or directory [1] - $ git checkout HEAD~1 1> /dev/null - Note: switching to 'HEAD~1'. - - You are in 'detached HEAD' state. You can look around, make experimental - changes and commit them, and you can discard any commits you make in this - state without impacting any branches by switching back to a branch. - - If you want to create a new branch to retain commits you create, you may - do so (now or later) by using -c with the switch command. Example: - - git switch -c - - Or undo this operation with: - - git switch - - - Turn off this advice by setting config variable advice.detachedHead to false - - HEAD is now at edefd7d add in filter + $ git checkout -q HEAD~1 1> /dev/null $ git clean -ffdx 1> /dev/null $ tree . @@ -321,9 +278,7 @@ Note that ws/d/ is now present in the ws 5 directories, 9 files - $ git checkout HEAD~1 1> /dev/null - Previous HEAD position was edefd7d add in filter - HEAD is now at aaec05d mod workspace + $ git checkout -q HEAD~1 1> /dev/null $ git clean -ffdx 1> /dev/null $ tree . @@ -370,13 +325,11 @@ Note that ws/d/ is now present in the ws | | | `-- HEAD | | |-- %3A%2Fws%2Fd | | | `-- HEAD - | | |-- %3Aworkspace=ws - | | | `-- HEAD - | | `-- %3Aworkspace=ws%3Aprefix=pre%3A%2Fpre + | | `-- %3Aworkspace=ws | | `-- HEAD | |-- rewrites | | `-- real_repo.git - | | `-- 010e03f34d3497fc1e309e7c8bd06a95e399677b + | | `-- 7bd92d97e96693ea7fd7eb5757b3580002889948 | | |-- r_44edc62d506b9805a3edfc74db15b1cc0bfc6871 | | `-- r_9d72b88b11aed97d3313f0a6d80894ee2ffdf3e9 | `-- upstream @@ -388,6 +341,6 @@ Note that ws/d/ is now present in the ws |-- namespaces `-- tags - 21 directories, 12 files + 20 directories, 11 files $ cat ${TESTTMP}/josh-proxy.out | grep VIEW