fetch-pack.con commit git-fetch-pack: Support multi_ack extension (c4c86f0)
   1#include "cache.h"
   2#include "refs.h"
   3#include "pkt-line.h"
   4#include "commit.h"
   5#include "tag.h"
   6#include <time.h>
   7#include <sys/wait.h>
   8
   9static int quiet;
  10static int verbose;
  11static const char fetch_pack_usage[] =
  12"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
  13static const char *exec = "git-upload-pack";
  14
  15#define COMPLETE        (1U << 0)
  16#define COMMON          (1U << 1)
  17#define COMMON_REF      (1U << 2)
  18#define SEEN            (1U << 3)
  19#define POPPED          (1U << 4)
  20
  21static struct commit_list *rev_list = NULL;
  22static int non_common_revs = 0, multi_ack = 0;
  23
  24static void rev_list_push(struct commit *commit, int mark)
  25{
  26        if (!(commit->object.flags & mark)) {
  27                commit->object.flags |= mark;
  28
  29                if (!(commit->object.parsed))
  30                        parse_commit(commit);
  31
  32                insert_by_date(commit, &rev_list);
  33
  34                if (!(commit->object.flags & COMMON))
  35                        non_common_revs++;
  36        }
  37}
  38
  39static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
  40{
  41        struct object *o = deref_tag(parse_object(sha1));
  42
  43        if (o->type == commit_type)
  44                rev_list_push((struct commit *)o, SEEN);
  45
  46        return 0;
  47}
  48
  49/*
  50   This function marks a rev and its ancestors as common.
  51   In some cases, it is desirable to mark only the ancestors (for example
  52   when only the server does not yet know that they are common).
  53*/
  54
  55static void mark_common(struct commit *commit,
  56                int ancestors_only, int dont_parse)
  57{
  58        if (commit != NULL && !(commit->object.flags & COMMON)) {
  59                struct object *o = (struct object *)commit;
  60
  61                if (!ancestors_only)
  62                        o->flags |= COMMON;
  63
  64                if (!(o->flags & SEEN))
  65                        rev_list_push(commit, SEEN);
  66                else {
  67                        struct commit_list *parents;
  68
  69                        if (!ancestors_only && !(o->flags & POPPED))
  70                                non_common_revs--;
  71                        if (!o->parsed && !dont_parse)
  72                                parse_commit(commit);
  73
  74                        for (parents = commit->parents;
  75                                        parents;
  76                                        parents = parents->next)
  77                                mark_common(parents->item, 0, dont_parse);
  78                }
  79        }
  80}
  81
  82/*
  83  Get the next rev to send, ignoring the common.
  84*/
  85
  86static const unsigned char* get_rev()
  87{
  88        struct commit *commit = NULL;
  89
  90        while (commit == NULL) {
  91                unsigned int mark;
  92                struct commit_list* parents;
  93
  94                if (rev_list == NULL || non_common_revs == 0)
  95                        return NULL;
  96
  97                commit = rev_list->item;
  98                if (!(commit->object.parsed))
  99                        parse_commit(commit);
 100                commit->object.flags |= POPPED;
 101                if (!(commit->object.flags & COMMON))
 102                        non_common_revs--;
 103        
 104                parents = commit->parents;
 105
 106                if (commit->object.flags & COMMON) {
 107                        /* do not send "have", and ignore ancestors */
 108                        commit = NULL;
 109                        mark = COMMON | SEEN;
 110                } else if (commit->object.flags & COMMON_REF)
 111                        /* send "have", and ignore ancestors */
 112                        mark = COMMON | SEEN;
 113                else
 114                        /* send "have", also for its ancestors */
 115                        mark = SEEN;
 116
 117                while (parents) {
 118                        if (!(parents->item->object.flags & SEEN))
 119                                rev_list_push(parents->item, mark);
 120                        if (mark & COMMON)
 121                                mark_common(parents->item, 1, 0);
 122                        parents = parents->next;
 123                }
 124
 125                rev_list = rev_list->next;
 126        }
 127
 128        return commit->object.sha1;
 129}
 130
 131static int find_common(int fd[2], unsigned char *result_sha1,
 132                       struct ref *refs)
 133{
 134        int fetching;
 135        int count = 0, flushes = 0, retval;
 136        const unsigned char *sha1;
 137
 138        for_each_ref(rev_list_insert_ref);
 139
 140        fetching = 0;
 141        for ( ; refs ; refs = refs->next) {
 142                unsigned char *remote = refs->old_sha1;
 143                struct object *o;
 144
 145                /*
 146                 * If that object is complete (i.e. it is an ancestor of a
 147                 * local ref), we tell them we have it but do not have to
 148                 * tell them about its ancestors, which they already know
 149                 * about.
 150                 *
 151                 * We use lookup_object here because we are only
 152                 * interested in the case we *know* the object is
 153                 * reachable and we have already scanned it.
 154                 */
 155                if (((o = lookup_object(remote)) != NULL) &&
 156                                (o->flags & COMPLETE)) {
 157                        continue;
 158                }
 159
 160                packet_write(fd[1], "want %s%s\n", sha1_to_hex(remote),
 161                        multi_ack ? " multi_ack" : "");
 162                fetching++;
 163        }
 164        packet_flush(fd[1]);
 165        if (!fetching)
 166                return 1;
 167
 168        flushes = 0;
 169        retval = -1;
 170        while ((sha1 = get_rev())) {
 171                packet_write(fd[1], "have %s\n", sha1_to_hex(sha1));
 172                if (verbose)
 173                        fprintf(stderr, "have %s\n", sha1_to_hex(sha1));
 174                if (!(31 & ++count)) {
 175                        int ack;
 176
 177                        packet_flush(fd[1]);
 178                        flushes++;
 179
 180                        /*
 181                         * We keep one window "ahead" of the other side, and
 182                         * will wait for an ACK only on the next one
 183                         */
 184                        if (count == 32)
 185                                continue;
 186
 187                        do {
 188                                ack = get_ack(fd[0], result_sha1);
 189                                if (verbose && ack)
 190                                        fprintf(stderr, "got ack %d %s\n", ack,
 191                                                        sha1_to_hex(result_sha1));
 192                                if (ack == 1) {
 193                                        flushes = 0;
 194                                        multi_ack = 0;
 195                                        retval = 0;
 196                                        goto done;
 197                                } else if (ack == 2) {
 198                                        struct commit *commit =
 199                                                lookup_commit(result_sha1);
 200                                        mark_common(commit, 0, 1);
 201                                        retval = 0;
 202                                }
 203                        } while (ack);
 204                        flushes--;
 205                }
 206        }
 207done:
 208        packet_write(fd[1], "done\n");
 209        if (verbose)
 210                fprintf(stderr, "done\n");
 211        if (retval != 0) {
 212                multi_ack = 0;
 213                flushes++;
 214        }
 215        while (flushes || multi_ack) {
 216                int ack = get_ack(fd[0], result_sha1);
 217                if (ack) {
 218                        if (verbose)
 219                                fprintf(stderr, "got ack (%d) %s\n", ack,
 220                                        sha1_to_hex(result_sha1));
 221                        if (ack == 1)
 222                                return 0;
 223                        multi_ack = 1;
 224                        continue;
 225                }
 226                flushes--;
 227        }
 228        return retval;
 229}
 230
 231static struct commit_list *complete = NULL;
 232
 233static int mark_complete(const char *path, const unsigned char *sha1)
 234{
 235        struct object *o = parse_object(sha1);
 236
 237        while (o && o->type == tag_type) {
 238                struct tag *t = (struct tag *) o;
 239                if (!t->tagged)
 240                        break; /* broken repository */
 241                o->flags |= COMPLETE;
 242                o = parse_object(t->tagged->sha1);
 243        }
 244        if (o && o->type == commit_type) {
 245                struct commit *commit = (struct commit *)o;
 246                commit->object.flags |= COMPLETE;
 247                insert_by_date(commit, &complete);
 248        }
 249        return 0;
 250}
 251
 252static void mark_recent_complete_commits(unsigned long cutoff)
 253{
 254        while (complete && cutoff <= complete->item->date) {
 255                if (verbose)
 256                        fprintf(stderr, "Marking %s as complete\n",
 257                                sha1_to_hex(complete->item->object.sha1));
 258                pop_most_recent_commit(&complete, COMPLETE);
 259        }
 260}
 261
 262static void filter_refs(struct ref **refs, int nr_match, char **match)
 263{
 264        struct ref *prev, *current, *next;
 265
 266        if (!nr_match)
 267                return;
 268
 269        for (prev = NULL, current = *refs; current; current = next) {
 270                next = current->next;
 271                if ((!memcmp(current->name, "refs/", 5) &&
 272                                        check_ref_format(current->name + 5)) ||
 273                                !path_match(current->name, nr_match, match)) {
 274                        if (prev == NULL)
 275                                *refs = next;
 276                        else
 277                                prev->next = next;
 278                        free(current);
 279                } else
 280                        prev = current;
 281        }
 282}
 283
 284static int everything_local(struct ref **refs, int nr_match, char **match)
 285{
 286        struct ref *ref;
 287        int retval;
 288        unsigned long cutoff = 0;
 289
 290        track_object_refs = 0;
 291        save_commit_buffer = 0;
 292
 293        for (ref = *refs; ref; ref = ref->next) {
 294                struct object *o;
 295
 296                o = parse_object(ref->old_sha1);
 297                if (!o)
 298                        continue;
 299
 300                /* We already have it -- which may mean that we were
 301                 * in sync with the other side at some time after
 302                 * that (it is OK if we guess wrong here).
 303                 */
 304                if (o->type == commit_type) {
 305                        struct commit *commit = (struct commit *)o;
 306                        if (!cutoff || cutoff < commit->date)
 307                                cutoff = commit->date;
 308                }
 309        }
 310
 311        for_each_ref(mark_complete);
 312        if (cutoff)
 313                mark_recent_complete_commits(cutoff);
 314
 315        /*
 316         * Mark all complete remote refs as common refs.
 317         * Don't mark them common yet; the server has to be told so first.
 318         */
 319        for (ref = *refs; ref; ref = ref->next) {
 320                struct object *o = deref_tag(lookup_object(ref->old_sha1));
 321
 322                if (!o || o->type != commit_type || !(o->flags & COMPLETE))
 323                        continue;
 324
 325                if (!(o->flags & SEEN)) {
 326                        rev_list_push((struct commit *)o, COMMON_REF | SEEN);
 327
 328                        mark_common((struct commit *)o, 1, 1);
 329                }
 330        }
 331
 332        filter_refs(refs, nr_match, match);
 333
 334        for (retval = 1, ref = *refs; ref ; ref = ref->next) {
 335                const unsigned char *remote = ref->old_sha1;
 336                unsigned char local[20];
 337                struct object *o;
 338
 339                o = lookup_object(remote);
 340                if (!o || !(o->flags & COMPLETE)) {
 341                        retval = 0;
 342                        if (!verbose)
 343                                continue;
 344                        fprintf(stderr,
 345                                "want %s (%s)\n", sha1_to_hex(remote),
 346                                ref->name);
 347                        continue;
 348                }
 349
 350                memcpy(ref->new_sha1, local, 20);
 351                if (!verbose)
 352                        continue;
 353                fprintf(stderr,
 354                        "already have %s (%s)\n", sha1_to_hex(remote),
 355                        ref->name);
 356        }
 357        return retval;
 358}
 359
 360static int fetch_pack(int fd[2], int nr_match, char **match)
 361{
 362        struct ref *ref;
 363        unsigned char sha1[20];
 364        int status;
 365        pid_t pid;
 366
 367        get_remote_heads(fd[0], &ref, 0, NULL, 0);
 368        if (server_supports("multi_ack")) {
 369                if (verbose)
 370                        fprintf(stderr, "Server supports multi_ack\n");
 371                multi_ack = 1;
 372        }
 373        if (!ref) {
 374                packet_flush(fd[1]);
 375                die("no matching remote head");
 376        }
 377        if (everything_local(&ref, nr_match, match)) {
 378                packet_flush(fd[1]);
 379                goto all_done;
 380        }
 381        if (find_common(fd, sha1, ref) < 0)
 382                fprintf(stderr, "warning: no common commits\n");
 383        pid = fork();
 384        if (pid < 0)
 385                die("git-fetch-pack: unable to fork off git-unpack-objects");
 386        if (!pid) {
 387                dup2(fd[0], 0);
 388                close(fd[0]);
 389                close(fd[1]);
 390                execlp("git-unpack-objects", "git-unpack-objects",
 391                       quiet ? "-q" : NULL, NULL);
 392                die("git-unpack-objects exec failed");
 393        }
 394        close(fd[0]);
 395        close(fd[1]);
 396        while (waitpid(pid, &status, 0) < 0) {
 397                if (errno != EINTR)
 398                        die("waiting for git-unpack-objects: %s", strerror(errno));
 399        }
 400        if (WIFEXITED(status)) {
 401                int code = WEXITSTATUS(status);
 402                if (code)
 403                        die("git-unpack-objects died with error code %d", code);
 404all_done:
 405                while (ref) {
 406                        printf("%s %s\n",
 407                               sha1_to_hex(ref->old_sha1), ref->name);
 408                        ref = ref->next;
 409                }
 410                return 0;
 411        }
 412        if (WIFSIGNALED(status)) {
 413                int sig = WTERMSIG(status);
 414                die("git-unpack-objects died of signal %d", sig);
 415        }
 416        die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
 417}
 418
 419int main(int argc, char **argv)
 420{
 421        int i, ret, nr_heads;
 422        char *dest = NULL, **heads;
 423        int fd[2];
 424        pid_t pid;
 425
 426        nr_heads = 0;
 427        heads = NULL;
 428        for (i = 1; i < argc; i++) {
 429                char *arg = argv[i];
 430
 431                if (*arg == '-') {
 432                        if (!strncmp("--exec=", arg, 7)) {
 433                                exec = arg + 7;
 434                                continue;
 435                        }
 436                        if (!strcmp("-q", arg)) {
 437                                quiet = 1;
 438                                continue;
 439                        }
 440                        if (!strcmp("-v", arg)) {
 441                                verbose = 1;
 442                                continue;
 443                        }
 444                        usage(fetch_pack_usage);
 445                }
 446                dest = arg;
 447                heads = argv + i + 1;
 448                nr_heads = argc - i - 1;
 449                break;
 450        }
 451        if (!dest)
 452                usage(fetch_pack_usage);
 453        pid = git_connect(fd, dest, exec);
 454        if (pid < 0)
 455                return 1;
 456        ret = fetch_pack(fd, nr_heads, heads);
 457        close(fd[0]);
 458        close(fd[1]);
 459        finish_connect(pid);
 460        return ret;
 461}