On Thu, Aug 8, 2013 at 6:35 AM, Nguyễn Thái Ngọc Duy <pclo...@gmail.com> wrote:
> This may happen when `git gc --auto` is run automatically, then the
> user, to avoid wait time, switches to a new terminal, keeps working
> and `git gc --auto` is started again because the first gc instance has
> not clean up the repository.
>
> This patch tries to avoid multiple gc running, especially in --auto
> mode. In the worst case, gc may be delayed 12 hours if a daemon reuses
> the pid stored in gc.pid.
>
> kill(pid, 0) support is added to MinGW port so it should work on
> Windows too.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
> ---
>  this patch is getting cooler:
>
>  - uname() is dropped in favor of gethostbyname(), which is supported
>    by MinGW port.
>  - host name is stored in gc.pid as junio suggested so...
>  - now we can say "gc is already running on _this host_ with _this pid_..."
>
>  Documentation/git-gc.txt |  6 ++++-
>  builtin/gc.c             | 67 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  compat/mingw.c           |  6 +++++
>  3 files changed, 78 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt
> index 2402ed6..e158a3b 100644
> --- a/Documentation/git-gc.txt
> +++ b/Documentation/git-gc.txt
> @@ -9,7 +9,7 @@ git-gc - Cleanup unnecessary files and optimize the local 
> repository
>  SYNOPSIS
>  --------
>  [verse]
> -'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune]
> +'git gc' [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] 
> [--force]
>
>  DESCRIPTION
>  -----------
> @@ -72,6 +72,10 @@ automatic consolidation of packs.
>  --quiet::
>         Suppress all progress reports.
>
> +--force::
> +       Force `git gc` to run even if there may be another `git gc`
> +       instance running on this repository.
> +
>  Configuration
>  -------------
>
> diff --git a/builtin/gc.c b/builtin/gc.c
> index 6be6c8d..99682f0 100644
> --- a/builtin/gc.c
> +++ b/builtin/gc.c
> @@ -167,11 +167,69 @@ static int need_to_gc(void)
>         return 1;
>  }
>
> +/* return NULL on success, else hostname running the gc */
> +static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
> +{
> +       static struct lock_file lock;
> +       static char locking_host[128];
> +       char my_host[128];
> +       struct strbuf sb = STRBUF_INIT;
> +       struct stat st;
> +       uintmax_t pid;

pid_t is always an signed type, therefore unintmax_t does not make
sense as a catch all value

fork() returns -1 on failure, and its return type is pid_t. i don't
know what fantasy unix system has an unsigned pid_t

> +       FILE *fp;
> +       int fd, should_exit;
> +
> +       if (gethostname(my_host, sizeof(my_host)))
> +               strcpy(my_host, "unknown");
> +
> +       fd = hold_lock_file_for_update(&lock, git_path("gc.pid"),
> +                                      LOCK_DIE_ON_ERROR);
> +       if (!force) {
> +               fp = fopen(git_path("gc.pid"), "r");
> +               memset(locking_host, 0, sizeof(locking_host));
> +               should_exit =
> +                       fp != NULL &&
> +                       !fstat(fileno(fp), &st) &&
> +                       /*
> +                        * 12 hour limit is very generous as gc should
> +                        * never take that long. On the other hand we
> +                        * don't really need a strict limit here,
> +                        * running gc --auto one day late is not a big
> +                        * problem. --force can be used in manual gc
> +                        * after the user verifies that no gc is
> +                        * running.
> +                        */
> +                       time(NULL) - st.st_mtime <= 12 * 3600 &&
> +                       fscanf(fp, "%"PRIuMAX" %127c", &pid, locking_host) == 
> 2 &&

similar comment wrt PRIuMAX

> +                       !strcmp(locking_host, my_host) &&
> +                       !kill(pid, 0);
> +               if (fp != NULL)
> +                       fclose(fp);
> +               if (should_exit) {
> +                       if (fd >= 0)
> +                               rollback_lock_file(&lock);
> +                       *ret_pid = pid;
> +                       return locking_host;

why not exponential backoff?

> +               }
> +       }
> +
> +       strbuf_addf(&sb, "%"PRIuMAX" %s",
> +                   (uintmax_t) getpid(), my_host);
> +       write_in_full(fd, sb.buf, sb.len);
> +       strbuf_release(&sb);
> +       commit_lock_file(&lock);
> +
> +       return NULL;
> +}
> +
>  int cmd_gc(int argc, const char **argv, const char *prefix)
>  {
>         int aggressive = 0;
>         int auto_gc = 0;
>         int quiet = 0;
> +       int force = 0;
> +       const char *name;
> +       pid_t pid;
>
>         struct option builtin_gc_options[] = {
>                 OPT__QUIET(&quiet, N_("suppress progress reporting")),
> @@ -180,6 +238,7 @@ int cmd_gc(int argc, const char **argv, const char 
> *prefix)
>                         PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
>                 OPT_BOOLEAN(0, "aggressive", &aggressive, N_("be more 
> thorough (increased runtime)")),
>                 OPT_BOOLEAN(0, "auto", &auto_gc, N_("enable auto-gc mode")),
> +               OPT_BOOL(0, "force", &force, N_("force running gc even if 
> there may be another gc running")),
>                 OPT_END()
>         };
>
> @@ -225,6 +284,14 @@ int cmd_gc(int argc, const char **argv, const char 
> *prefix)
>         } else
>                 add_repack_all_option();
>
> +       name = lock_repo_for_gc(force, &pid);
> +       if (name) {
> +               if (auto_gc)
> +                       return 0; /* be quiet on --auto */
> +               die(_("gc is already running on machine '%s' pid %"PRIuMAX" 
> (use --force if not)"),
> +                   name, (uintmax_t)pid);
> +       }
> +
>         if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
>                 return error(FAILED_RUN, pack_refs_cmd.argv[0]);
>
> diff --git a/compat/mingw.c b/compat/mingw.c
> index bb92c43..22ee9ef 100644
> --- a/compat/mingw.c
> +++ b/compat/mingw.c
> @@ -1086,6 +1086,12 @@ int mingw_kill(pid_t pid, int sig)
>                 errno = err_win_to_posix(GetLastError());
>                 CloseHandle(h);
>                 return -1;
> +       } else if (pid > 0 && sig == 0) {
> +               HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
> +               if (h) {
> +                       CloseHandle(h);
> +                       return 0;
> +               }
>         }
>
>         errno = EINVAL;
> --
> 1.8.2.83.gc99314b
>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to