Merge branch 'vl/grep-configurable-threads'
authorJunio C Hamano <gitster@pobox.com>
Tue, 12 Jan 2016 23:16:55 +0000 (15:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 12 Jan 2016 23:16:55 +0000 (15:16 -0800)
"git grep" can now be configured (or told from the command line)
how many threads to use when searching in the working tree files.

* vl/grep-configurable-threads:
grep: add --threads=<num> option and grep.threads configuration
grep: slight refactoring to the code that disables threading
grep: allow threading even on a single-core machine

1  2 
Documentation/config.txt
builtin/grep.c
contrib/completion/git-completion.bash
diff --combined Documentation/config.txt
index f61788668e89b659439e2fa5d600aebabdd733a5,ff2179901ebfc7d5abe7d61aabcc1f5981da4d7a..beb18da14354a4b8b475b74113d103d404c70a7d
@@@ -1122,9 -1122,6 +1122,9 @@@ credential.<url>.*:
        example.com. See linkgit:gitcredentials[7] for details on how URLs are
        matched.
  
 +credentialCache.ignoreSIGHUP::
 +      Tell git-credential-cache--daemon to ignore SIGHUP, instead of quitting.
 +
  include::diff-config.txt[]
  
  difftool.<tool>.path::
@@@ -1450,6 -1447,10 +1450,10 @@@ grep.extendedRegexp:
        option is ignored when the 'grep.patternType' option is set to a value
        other than 'default'.
  
+ grep.threads::
+       Number of grep worker threads to use.
+       See `grep.threads` in linkgit:git-grep[1] for more information.
  gpg.program::
        Use this custom program instead of "gpg" found on $PATH when
        making or verifying a PGP signature. The program must support the
@@@ -2229,20 -2230,6 +2233,20 @@@ push.gpgSign:
        override a value from a lower-priority config file. An explicit
        command-line flag always overrides this config option.
  
 +push.recurseSubmodules::
 +      Make sure all submodule commits used by the revisions to be pushed
 +      are available on a remote-tracking branch. If the value is 'check'
 +      then Git will verify that all submodule commits that changed in the
 +      revisions to be pushed are available on at least one remote of the
 +      submodule. If any commits are missing, the push will be aborted and
 +      exit with non-zero status. If the value is 'on-demand' then all
 +      submodules that changed in the revisions to be pushed will be
 +      pushed. If on-demand was not able to push all necessary revisions
 +      it will also be aborted and exit with non-zero status. If the value
 +      is 'no' then default behavior of ignoring submodules when pushing
 +      is retained. You may override this configuration at time of push by
 +      specifying '--recurse-submodules=check|on-demand|no'.
 +
  rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
        rebase. False by default.
@@@ -2690,15 -2677,6 +2694,15 @@@ You may also include a `!` in front of 
  explicitly exposing it, even if an earlier entry marked it as hidden.
  If you have multiple hideRefs values, later entries override earlier ones
  (and entries in more-specific config files override less-specific ones).
 ++
 +If a namespace is in use, the namespace prefix is stripped from each
 +reference before it is matched against `transfer.hiderefs` patterns.
 +For example, if `refs/heads/master` is specified in `transfer.hideRefs` and
 +the current namespace is `foo`, then `refs/namespaces/foo/refs/heads/master`
 +is omitted from the advertisements but `refs/heads/master` and
 +`refs/namespaces/bar/refs/heads/master` are still advertised as so-called
 +"have" lines. In order to match refs before stripping, add a `^` in front of
 +the ref name. If you combine `!` and `^`, `!` must be specified first.
  
  transfer.unpackLimit::
        When `fetch.unpackLimit` or `receive.unpackLimit` are
diff --combined builtin/grep.c
index 4229cae390ddddcc74f3506dc892ed02b45d7eae,97d9ec33082d4f171d60fadf52ce356fa13dcadd..760dc8eae90f0c28cc8b4c664472fdec20fe688d
@@@ -24,11 -24,11 +24,11 @@@ static char const * const grep_usage[] 
        NULL
  };
  
- static int use_threads = 1;
+ #define GREP_NUM_THREADS_DEFAULT 8
+ static int num_threads;
  
  #ifndef NO_PTHREADS
- #define THREADS 8
- static pthread_t threads[THREADS];
+ static pthread_t *threads;
  
  /* We use one producer thread and THREADS consumer
   * threads. The producer adds struct work_items to 'todo' and the
@@@ -63,13 -63,13 +63,13 @@@ static pthread_mutex_t grep_mutex
  
  static inline void grep_lock(void)
  {
-       if (use_threads)
+       if (num_threads)
                pthread_mutex_lock(&grep_mutex);
  }
  
  static inline void grep_unlock(void)
  {
-       if (use_threads)
+       if (num_threads)
                pthread_mutex_unlock(&grep_mutex);
  }
  
@@@ -206,7 -206,8 +206,8 @@@ static void start_threads(struct grep_o
                strbuf_init(&todo[i].out, 0);
        }
  
-       for (i = 0; i < ARRAY_SIZE(threads); i++) {
+       threads = xcalloc(num_threads, sizeof(*threads));
+       for (i = 0; i < num_threads; i++) {
                int err;
                struct grep_opt *o = grep_opt_dup(opt);
                o->output = strbuf_out;
@@@ -238,12 -239,14 +239,14 @@@ static int wait_all(void
        pthread_cond_broadcast(&cond_add);
        grep_unlock();
  
-       for (i = 0; i < ARRAY_SIZE(threads); i++) {
+       for (i = 0; i < num_threads; i++) {
                void *h;
                pthread_join(threads[i], &h);
                hit |= (int) (intptr_t) h;
        }
  
+       free(threads);
        pthread_mutex_destroy(&grep_mutex);
        pthread_mutex_destroy(&grep_read_mutex);
        pthread_mutex_destroy(&grep_attr_mutex);
@@@ -267,6 -270,14 +270,14 @@@ static int grep_cmd_config(const char *
        int st = grep_config(var, value, cb);
        if (git_color_default_config(var, value, cb) < 0)
                st = -1;
+       if (!strcmp(var, "grep.threads")) {
+               num_threads = git_config_int(var, value);
+               if (num_threads < 0)
+                       die(_("invalid number of threads specified (%d) for %s"),
+                           num_threads, var);
+       }
        return st;
  }
  
@@@ -294,7 -305,7 +305,7 @@@ static int grep_sha1(struct grep_opt *o
        }
  
  #ifndef NO_PTHREADS
-       if (use_threads) {
+       if (num_threads) {
                add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, path, sha1);
                strbuf_release(&pathbuf);
                return 0;
@@@ -323,7 -334,7 +334,7 @@@ static int grep_file(struct grep_opt *o
                strbuf_addstr(&buf, filename);
  
  #ifndef NO_PTHREADS
-       if (use_threads) {
+       if (num_threads) {
                add_work(opt, GREP_SOURCE_FILE, buf.buf, filename, filename);
                strbuf_release(&buf);
                return 0;
@@@ -459,7 -470,7 +470,7 @@@ static int grep_object(struct grep_opt 
                       struct object *obj, const char *name, const char *path)
  {
        if (obj->type == OBJ_BLOB)
 -              return grep_sha1(opt, obj->sha1, name, 0, path);
 +              return grep_sha1(opt, obj->oid.hash, name, 0, path);
        if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
                struct tree_desc tree;
                void *data;
                int hit, len;
  
                grep_read_lock();
 -              data = read_object_with_reference(obj->sha1, tree_type,
 +              data = read_object_with_reference(obj->oid.hash, tree_type,
                                                  &size, NULL);
                grep_read_unlock();
  
                if (!data)
 -                      die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1));
 +                      die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
  
                len = name ? strlen(name) : 0;
                strbuf_init(&base, PATH_MAX + len + 1);
@@@ -612,6 -623,11 +623,6 @@@ static int pattern_callback(const struc
        return 0;
  }
  
 -static int help_callback(const struct option *opt, const char *arg, int unset)
 -{
 -      return -1;
 -}
 -
  int cmd_grep(int argc, const char **argv, const char *prefix)
  {
        int hit = 0;
                        N_("show <n> context lines before matches")),
                OPT_INTEGER('A', "after-context", &opt.post_context,
                        N_("show <n> context lines after matches")),
+               OPT_INTEGER(0, "threads", &num_threads,
+                       N_("use <n> worker threads")),
                OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
                        context_callback),
                OPT_BOOL('p', "show-function", &opt.funcname,
                        PARSE_OPT_OPTARG, NULL, (intptr_t)default_pager },
                OPT_BOOL(0, "ext-grep", &external_grep_allowed__ignored,
                         N_("allow calling of grep(1) (ignored by this build)")),
 -              { OPTION_CALLBACK, 0, "help-all", NULL, NULL, N_("show usage"),
 -                PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, help_callback },
                OPT_END()
        };
  
 -      /*
 -       * 'git grep -h', unlike 'git grep -h <pattern>', is a request
 -       * to show usage information and exit.
 -       */
 -      if (argc == 2 && !strcmp(argv[1], "-h"))
 -              usage_with_options(grep_usage, options);
 -
        init_grep_defaults();
        git_config(grep_cmd_config, NULL);
        grep_init(&opt, prefix);
         */
        argc = parse_options(argc, argv, prefix, options, grep_usage,
                             PARSE_OPT_KEEP_DASHDASH |
 -                           PARSE_OPT_STOP_AT_NON_OPTION |
 -                           PARSE_OPT_NO_INTERNAL_HELP);
 +                           PARSE_OPT_STOP_AT_NON_OPTION);
        grep_commit_pattern_type(pattern_type_arg, &opt);
  
        if (use_index && !startup_info->have_repository)
                opt.output_priv = &path_list;
                opt.output = append_path;
                string_list_append(&path_list, show_in_pager);
-               use_threads = 0;
        }
  
        if (!opt.pattern_list)
        }
  
  #ifndef NO_PTHREADS
-       if (list.nr || cached || online_cpus() == 1)
-               use_threads = 0;
+       if (list.nr || cached || show_in_pager)
+               num_threads = 0;
+       else if (num_threads == 0)
+               num_threads = GREP_NUM_THREADS_DEFAULT;
+       else if (num_threads < 0)
+               die(_("invalid number of threads specified (%d)"), num_threads);
  #else
-       use_threads = 0;
+       num_threads = 0;
  #endif
  
  #ifndef NO_PTHREADS
-       if (use_threads) {
+       if (num_threads) {
                if (!(opt.name_only || opt.unmatch_name_only || opt.count)
                    && (opt.pre_context || opt.post_context ||
                        opt.file_break || opt.funcbody))
                hit = grep_objects(&opt, &pathspec, &list);
        }
  
-       if (use_threads)
+       if (num_threads)
                hit |= wait_all();
        if (hit && show_in_pager)
                run_pager(&opt, prefix);
index 69568075191af7b22fc4e9e556cdcd3c19dc7a51,390d9c04c0d6a24694de48735a8f06cd34878628..ab4da7f979177a3304eb08d85869c1a141e81064
@@@ -10,7 -10,6 +10,7 @@@
  #    *) local and remote tag names
  #    *) .git/remotes file names
  #    *) git 'subcommands'
 +#    *) git email aliases for git-send-email
  #    *) tree paths within 'ref:path/to/file' expressions
  #    *) file paths within current working directory and index
  #    *) common --long-options
@@@ -664,7 -663,6 +664,7 @@@ __git_list_porcelain_commands (
                check-mailmap)    : plumbing;;
                check-ref-format) : plumbing;;
                checkout-index)   : plumbing;;
 +              column)           : internal helper;;
                commit-tree)      : plumbing;;
                count-objects)    : infrequent;;
                credential)       : credentials;;
@@@ -1312,6 -1310,7 +1312,7 @@@ _git_grep (
                        --full-name --line-number
                        --extended-regexp --basic-regexp --fixed-strings
                        --perl-regexp
+                       --threads
                        --files-with-matches --name-only
                        --files-without-match
                        --max-depth
@@@ -1713,15 -1712,6 +1714,15 @@@ __git_send_email_suppresscc_options="au
  
  _git_send_email ()
  {
 +      case "$prev" in
 +      --to|--cc|--bcc|--from)
 +              __gitcomp "
 +              $(git --git-dir="$(__gitdir)" send-email --dump-aliases 2>/dev/null)
 +              "
 +              return
 +              ;;
 +      esac
 +
        case "$cur" in
        --confirm=*)
                __gitcomp "
                        " "" "${cur##--thread=}"
                return
                ;;
 +      --to=*|--cc=*|--bcc=*|--from=*)
 +              __gitcomp "
 +              $(git --git-dir="$(__gitdir)" send-email --dump-aliases 2>/dev/null)
 +              " "" "${cur#--*=}"
 +              return
 +              ;;
        --*)
                __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
                        --compose --confirm= --dry-run --envelope-sender