git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v14 41/41] builtin/am: use apply API in run_apply()

From
Christian Couder <christian.couder@gmail.com>
Date
Sep 4, 2016, 20:18 UTC
Message-ID
<20160904201833.21676-42-chriscool@tuxfamily.org>
In-Reply-To
<20160904201833.21676-1-chriscool@tuxfamily.org>

This replaces run_apply() implementation with a new one that uses the apply API that has been previously prepared in apply.c and apply.h.

This shoud improve performance a lot in certain cases.

As the previous implementation was creating a new `git apply` process to apply each patch, it could be slow on systems like Windows where it is costly to create new processes.

Also the new `git apply` process had to read the index from disk, and when the process was done the calling process discarded its own index and read back from disk the new index that had been created by the `git apply` process.

This could be very inefficient with big repositories that have big index files, especially when the system decided that it was a good idea to run the `git apply` processes on a different processor core.

Also eliminating index reads enables further performance improvements by using:

`git update-index --split-index`

For example here is a benchmark of a multi hundred commit rebase on the Linux kernel on a Debian laptop with SSD:

command: git rebase --onto 1993b17 52bef0c 29dde7c

Vanilla "next" without split index: 1m54.953s Vanilla "next" with split index: 1m22.476s This series on top of "next" without split index: 1m12.034s This series on top of "next" with split index: 0m15.678s

(using branch "next" from mid April 2016.)
Benchmarked-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 builtin/am.c | 65 ++++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 43 insertions(+), 22 deletions(-)
diff --git a/builtin/am.c b/builtin/am.c
index 739b34d..38d5d11 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -28,6 +28,7 @@
 #include "rerere.h"
 #include "prompt.h"
 #include "mailinfo.h"
+#include "apply.h"
 
 /**
  * Returns 1 if the file is empty or does not exist, 0 otherwise.
@@ -1522,39 +1523,59 @@ static int parse_mail_rebase(struct am_state *state, const char *mail)
  */
 static int run_apply(const struct am_state *state, const char *index_file)
 {
-	struct child_process cp = CHILD_PROCESS_INIT;
-
-	cp.git_cmd = 1;
-
-	if (index_file)
-		argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s", index_file);
+	struct argv_array apply_paths = ARGV_ARRAY_INIT;
+	struct argv_array apply_opts = ARGV_ARRAY_INIT;
+	struct apply_state apply_state;
+	int res, opts_left;
+	static struct lock_file lock_file;
+	int force_apply = 0;
+	int options = 0;
+
+	if (init_apply_state(&apply_state, NULL, &lock_file))
+		die("BUG: init_apply_state() failed");
+
+	argv_array_push(&apply_opts, "apply");
+	argv_array_pushv(&apply_opts, state->git_apply_opts.argv);
+
+	opts_left = apply_parse_options(apply_opts.argc, apply_opts.argv,
+					&apply_state, &force_apply, &options,
+					NULL);
+
+	if (opts_left != 0)
+		die("unknown option passed through to git apply");
+
+	if (index_file) {
+		apply_state.index_file = index_file;
+		apply_state.cached = 1;
+	} else
+		apply_state.check_index = 1;
 
 	/*
 	 * If we are allowed to fall back on 3-way merge, don't give false
 	 * errors during the initial attempt.
 	 */
-	if (state->threeway && !index_file) {
-		cp.no_stdout = 1;
-		cp.no_stderr = 1;
-	}
+	if (state->threeway && !index_file)
+		apply_state.apply_verbosity = verbosity_silent;
 
-	argv_array_push(&cp.args, "apply");
+	if (check_apply_state(&apply_state, force_apply))
+		die("BUG: check_apply_state() failed");
 
-	argv_array_pushv(&cp.args, state->git_apply_opts.argv);
+	argv_array_push(&apply_paths, am_path(state, "patch"));
 
-	if (index_file)
-		argv_array_push(&cp.args, "--cached");
-	else
-		argv_array_push(&cp.args, "--index");
+	res = apply_all_patches(&apply_state, apply_paths.argc, apply_paths.argv, options);
 
-	argv_array_push(&cp.args, am_path(state, "patch"));
+	argv_array_clear(&apply_paths);
+	argv_array_clear(&apply_opts);
+	clear_apply_state(&apply_state);
 
-	if (run_command(&cp))
-		return -1;
+	if (res)
+		return res;
 
-	/* Reload index as git-apply will have modified it. */
-	discard_cache();
-	read_cache_from(index_file ? index_file : get_index_file());
+	if (index_file) {
+		/* Reload index as apply_all_patches() will have modified it. */
+		discard_cache();
+		read_cache_from(index_file);
+	}
 
 	return 0;
 }
-- 
2.10.0.41.g9df52c3
Previous: Christian CouderNext: Christian Couder
Message 30 of 44 in “libify apply and use lib in am, part 2”
  1. 00/41 libify apply and use lib in am, part 2Christian Couder, Sep 4, 2016
  2. 01/41 apply: make some names more specificChristian Couder, Sep 4, 2016
  3. 02/41 apply: move 'struct apply_state' to apply.hChristian Couder, Sep 4, 2016
  4. 04/41 builtin/apply: read_patch_file() return -1 instead of die()ingChristian Couder, Sep 4, 2016
  5. 03/41 builtin/apply: make apply_patch() return -1 or -128 instead of die()ingChristian Couder, Sep 4, 2016
  6. 12/41 builtin/apply: make check_apply_state() return -1 instead of die()ingChristian Couder, Sep 4, 2016
  7. 11/41 apply: make init_apply_state() return -1 instead of exit()ingChristian Couder, Sep 4, 2016
  8. 14/41 builtin/apply: make apply_all_patches() return 128 or 1 on errorChristian Couder, Sep 4, 2016
  9. 15/41 builtin/apply: make parse_traditional_patch() return -1 on errorChristian Couder, Sep 4, 2016
  10. 17/41 builtin/apply: make gitdiff_*() return -1 on errorChristian Couder, Sep 4, 2016
  11. 13/41 builtin/apply: move check_apply_state() to apply.cChristian Couder, Sep 4, 2016
  12. 19/41 builtin/apply: make build_fake_ancestor() return -1 on errorChristian Couder, Sep 4, 2016
  13. 20/41 builtin/apply: make remove_file() return -1 on errorChristian Couder, Sep 4, 2016
  14. 16/41 builtin/apply: make gitdiff_*() return 1 at end of headerChristian Couder, Sep 4, 2016
  15. 23/41 builtin/apply: make create_file() return -1 on errorChristian Couder, Sep 4, 2016
  16. 22/41 builtin/apply: make add_index_file() return -1 on errorChristian Couder, Sep 4, 2016
  17. 18/41 builtin/apply: change die_on_unsafe_path() to check_unsafe_path()Christian Couder, Sep 4, 2016
  18. 24/41 builtin/apply: make write_out_one_result() return -1 on errorChristian Couder, Sep 4, 2016
  19. 21/41 builtin/apply: make add_conflicted_stages_file() return -1 on errorChristian Couder, Sep 4, 2016
  20. 25/41 builtin/apply: make write_out_results() return -1 on errorChristian Couder, Sep 4, 2016
  21. 29/41 apply: rename and move opt constants to apply.hChristian Couder, Sep 4, 2016
  22. 27/41 builtin/apply: make create_one_file() return -1 on errorChristian Couder, Sep 4, 2016
  23. 31/41 apply: make some parsing functions static againChristian Couder, Sep 4, 2016
  24. 32/41 apply: use error_errno() where possibleChristian Couder, Sep 4, 2016
  25. 28/41 builtin/apply: rename option parsing functionsChristian Couder, Sep 4, 2016
  26. 33/41 apply: make it possible to silently applyChristian Couder, Sep 4, 2016
  27. 34/41 apply: don't print on stdout in verbosity_silent modeChristian Couder, Sep 4, 2016
  28. 26/41 builtin/apply: make try_create_file() return -1 on errorChristian Couder, Sep 4, 2016
  29. 35/41 usage: add set_warn_routine()Christian Couder, Sep 4, 2016
  30. 41/41 builtin/am: use apply API in run_apply()Christian Couder, Sep 4, 2016
  31. 40/41 apply: learn to use a different index fileChristian Couder, Sep 4, 2016
  32. 39/41 apply: pass apply state to build_fake_ancestor()Christian Couder, Sep 4, 2016
  33. 38/41 apply: refactor `git apply` option parsingChristian Couder, Sep 4, 2016
  34. 37/41 apply: change error_routine when silentChristian Couder, Sep 4, 2016
  35. 36/41 usage: add get_error_routine() and get_warn_routine()Christian Couder, Sep 4, 2016
  36. 06/41 builtin/apply: make parse_chunk() return a negative integer on errorChristian Couder, Sep 4, 2016
  37. 10/41 builtin/apply: move init_apply_state() to apply.cChristian Couder, Sep 4, 2016
  38. 09/41 builtin/apply: make parse_ignorewhitespace_option() return -1 instead of die()ingChristian Couder, Sep 4, 2016
  39. 07/41 builtin/apply: make parse_single_patch() return -1 on errorChristian Couder, Sep 4, 2016
  40. 08/41 builtin/apply: make parse_whitespace_option() return -1 instead of die()ingChristian Couder, Sep 4, 2016
  41. 05/41 builtin/apply: make find_header() return -128 instead of die()ingChristian Couder, Sep 4, 2016
  42. Stefan BellerSep 6, 2016
  43. Junio C HamanoSep 7, 2016
  44. Stefan BellerSep 6, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.