Squashed 'third_party/git/' content from commit cb71568594
git-subtree-dir: third_party/git git-subtree-split: cb715685942260375e1eb8153b0768a376e4ece7
This commit is contained in:
commit
1b593e1ea4
3629 changed files with 1139935 additions and 0 deletions
176
negotiator/default.c
Normal file
176
negotiator/default.c
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
#include "cache.h"
|
||||
#include "default.h"
|
||||
#include "../commit.h"
|
||||
#include "../fetch-negotiator.h"
|
||||
#include "../prio-queue.h"
|
||||
#include "../refs.h"
|
||||
#include "../tag.h"
|
||||
|
||||
/* Remember to update object flag allocation in object.h */
|
||||
#define COMMON (1U << 2)
|
||||
#define COMMON_REF (1U << 3)
|
||||
#define SEEN (1U << 4)
|
||||
#define POPPED (1U << 5)
|
||||
|
||||
static int marked;
|
||||
|
||||
struct negotiation_state {
|
||||
struct prio_queue rev_list;
|
||||
int non_common_revs;
|
||||
};
|
||||
|
||||
static void rev_list_push(struct negotiation_state *ns,
|
||||
struct commit *commit, int mark)
|
||||
{
|
||||
if (!(commit->object.flags & mark)) {
|
||||
commit->object.flags |= mark;
|
||||
|
||||
if (parse_commit(commit))
|
||||
return;
|
||||
|
||||
prio_queue_put(&ns->rev_list, commit);
|
||||
|
||||
if (!(commit->object.flags & COMMON))
|
||||
ns->non_common_revs++;
|
||||
}
|
||||
}
|
||||
|
||||
static int clear_marks(const char *refname, const struct object_id *oid,
|
||||
int flag, void *cb_data)
|
||||
{
|
||||
struct object *o = deref_tag(the_repository, parse_object(the_repository, oid), refname, 0);
|
||||
|
||||
if (o && o->type == OBJ_COMMIT)
|
||||
clear_commit_marks((struct commit *)o,
|
||||
COMMON | COMMON_REF | SEEN | POPPED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function marks a rev and its ancestors as common.
|
||||
* In some cases, it is desirable to mark only the ancestors (for example
|
||||
* when only the server does not yet know that they are common).
|
||||
*/
|
||||
static void mark_common(struct negotiation_state *ns, struct commit *commit,
|
||||
int ancestors_only, int dont_parse)
|
||||
{
|
||||
if (commit != NULL && !(commit->object.flags & COMMON)) {
|
||||
struct object *o = (struct object *)commit;
|
||||
|
||||
if (!ancestors_only)
|
||||
o->flags |= COMMON;
|
||||
|
||||
if (!(o->flags & SEEN))
|
||||
rev_list_push(ns, commit, SEEN);
|
||||
else {
|
||||
struct commit_list *parents;
|
||||
|
||||
if (!ancestors_only && !(o->flags & POPPED))
|
||||
ns->non_common_revs--;
|
||||
if (!o->parsed && !dont_parse)
|
||||
if (parse_commit(commit))
|
||||
return;
|
||||
|
||||
for (parents = commit->parents;
|
||||
parents;
|
||||
parents = parents->next)
|
||||
mark_common(ns, parents->item, 0,
|
||||
dont_parse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the next rev to send, ignoring the common.
|
||||
*/
|
||||
static const struct object_id *get_rev(struct negotiation_state *ns)
|
||||
{
|
||||
struct commit *commit = NULL;
|
||||
|
||||
while (commit == NULL) {
|
||||
unsigned int mark;
|
||||
struct commit_list *parents;
|
||||
|
||||
if (ns->rev_list.nr == 0 || ns->non_common_revs == 0)
|
||||
return NULL;
|
||||
|
||||
commit = prio_queue_get(&ns->rev_list);
|
||||
parse_commit(commit);
|
||||
parents = commit->parents;
|
||||
|
||||
commit->object.flags |= POPPED;
|
||||
if (!(commit->object.flags & COMMON))
|
||||
ns->non_common_revs--;
|
||||
|
||||
if (commit->object.flags & COMMON) {
|
||||
/* do not send "have", and ignore ancestors */
|
||||
commit = NULL;
|
||||
mark = COMMON | SEEN;
|
||||
} else if (commit->object.flags & COMMON_REF)
|
||||
/* send "have", and ignore ancestors */
|
||||
mark = COMMON | SEEN;
|
||||
else
|
||||
/* send "have", also for its ancestors */
|
||||
mark = SEEN;
|
||||
|
||||
while (parents) {
|
||||
if (!(parents->item->object.flags & SEEN))
|
||||
rev_list_push(ns, parents->item, mark);
|
||||
if (mark & COMMON)
|
||||
mark_common(ns, parents->item, 1, 0);
|
||||
parents = parents->next;
|
||||
}
|
||||
}
|
||||
|
||||
return &commit->object.oid;
|
||||
}
|
||||
|
||||
static void known_common(struct fetch_negotiator *n, struct commit *c)
|
||||
{
|
||||
if (!(c->object.flags & SEEN)) {
|
||||
rev_list_push(n->data, c, COMMON_REF | SEEN);
|
||||
mark_common(n->data, c, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_tip(struct fetch_negotiator *n, struct commit *c)
|
||||
{
|
||||
n->known_common = NULL;
|
||||
rev_list_push(n->data, c, SEEN);
|
||||
}
|
||||
|
||||
static const struct object_id *next(struct fetch_negotiator *n)
|
||||
{
|
||||
n->known_common = NULL;
|
||||
n->add_tip = NULL;
|
||||
return get_rev(n->data);
|
||||
}
|
||||
|
||||
static int ack(struct fetch_negotiator *n, struct commit *c)
|
||||
{
|
||||
int known_to_be_common = !!(c->object.flags & COMMON);
|
||||
mark_common(n->data, c, 0, 1);
|
||||
return known_to_be_common;
|
||||
}
|
||||
|
||||
static void release(struct fetch_negotiator *n)
|
||||
{
|
||||
clear_prio_queue(&((struct negotiation_state *)n->data)->rev_list);
|
||||
FREE_AND_NULL(n->data);
|
||||
}
|
||||
|
||||
void default_negotiator_init(struct fetch_negotiator *negotiator)
|
||||
{
|
||||
struct negotiation_state *ns;
|
||||
negotiator->known_common = known_common;
|
||||
negotiator->add_tip = add_tip;
|
||||
negotiator->next = next;
|
||||
negotiator->ack = ack;
|
||||
negotiator->release = release;
|
||||
negotiator->data = ns = xcalloc(1, sizeof(*ns));
|
||||
ns->rev_list.compare = compare_commits_by_commit_date;
|
||||
|
||||
if (marked)
|
||||
for_each_ref(clear_marks, NULL);
|
||||
marked = 1;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue