1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
6 #include "../fetch-negotiator.h"
7 #include "../prio-queue.h"
9 #include "../repository.h"
12 /* Remember to update object flag allocation in object.h */
13 #define COMMON (1U << 2)
14 #define COMMON_REF (1U << 3)
15 #define SEEN (1U << 4)
16 #define POPPED (1U << 5)
20 struct negotiation_state
{
21 struct prio_queue rev_list
;
25 static void rev_list_push(struct negotiation_state
*ns
,
26 struct commit
*commit
, int mark
)
28 if (!(commit
->object
.flags
& mark
)) {
29 commit
->object
.flags
|= mark
;
31 if (repo_parse_commit(the_repository
, commit
))
34 prio_queue_put(&ns
->rev_list
, commit
);
36 if (!(commit
->object
.flags
& COMMON
))
37 ns
->non_common_revs
++;
41 static int clear_marks(const char *refname
, const char *referent UNUSED
, const struct object_id
*oid
,
45 struct object
*o
= deref_tag(the_repository
, parse_object(the_repository
, oid
), refname
, 0);
47 if (o
&& o
->type
== OBJ_COMMIT
)
48 clear_commit_marks((struct commit
*)o
,
49 COMMON
| COMMON_REF
| SEEN
| POPPED
);
54 * This function marks a rev and its ancestors as common.
55 * In some cases, it is desirable to mark only the ancestors (for example
56 * when only the server does not yet know that they are common).
58 static void mark_common(struct negotiation_state
*ns
, struct commit
*commit
,
59 int ancestors_only
, int dont_parse
)
61 struct prio_queue queue
= { NULL
};
63 if (!commit
|| (commit
->object
.flags
& COMMON
))
66 prio_queue_put(&queue
, commit
);
67 if (!ancestors_only
) {
68 commit
->object
.flags
|= COMMON
;
70 if ((commit
->object
.flags
& SEEN
) && !(commit
->object
.flags
& POPPED
))
71 ns
->non_common_revs
--;
73 while ((commit
= prio_queue_get(&queue
))) {
74 struct object
*o
= (struct object
*)commit
;
76 if (!(o
->flags
& SEEN
))
77 rev_list_push(ns
, commit
, SEEN
);
79 struct commit_list
*parents
;
81 if (!o
->parsed
&& !dont_parse
)
82 if (repo_parse_commit(the_repository
, commit
))
85 for (parents
= commit
->parents
;
87 parents
= parents
->next
) {
88 struct commit
*p
= parents
->item
;
90 if (p
->object
.flags
& COMMON
)
93 p
->object
.flags
|= COMMON
;
95 if ((p
->object
.flags
& SEEN
) && !(p
->object
.flags
& POPPED
))
96 ns
->non_common_revs
--;
98 prio_queue_put(&queue
, parents
->item
);
103 clear_prio_queue(&queue
);
107 * Get the next rev to send, ignoring the common.
109 static const struct object_id
*get_rev(struct negotiation_state
*ns
)
111 struct commit
*commit
= NULL
;
113 while (commit
== NULL
) {
115 struct commit_list
*parents
;
117 if (ns
->rev_list
.nr
== 0 || ns
->non_common_revs
== 0)
120 commit
= prio_queue_get(&ns
->rev_list
);
121 repo_parse_commit(the_repository
, commit
);
122 parents
= commit
->parents
;
124 commit
->object
.flags
|= POPPED
;
125 if (!(commit
->object
.flags
& COMMON
))
126 ns
->non_common_revs
--;
128 if (commit
->object
.flags
& COMMON
) {
129 /* do not send "have", and ignore ancestors */
131 mark
= COMMON
| SEEN
;
132 } else if (commit
->object
.flags
& COMMON_REF
)
133 /* send "have", and ignore ancestors */
134 mark
= COMMON
| SEEN
;
136 /* send "have", also for its ancestors */
140 if (!(parents
->item
->object
.flags
& SEEN
))
141 rev_list_push(ns
, parents
->item
, mark
);
143 mark_common(ns
, parents
->item
, 1, 0);
144 parents
= parents
->next
;
148 return &commit
->object
.oid
;
151 static void known_common(struct fetch_negotiator
*n
, struct commit
*c
)
153 if (!(c
->object
.flags
& SEEN
)) {
154 rev_list_push(n
->data
, c
, COMMON_REF
| SEEN
);
155 mark_common(n
->data
, c
, 1, 1);
159 static void add_tip(struct fetch_negotiator
*n
, struct commit
*c
)
161 n
->known_common
= NULL
;
162 rev_list_push(n
->data
, c
, SEEN
);
165 static const struct object_id
*next(struct fetch_negotiator
*n
)
167 n
->known_common
= NULL
;
169 return get_rev(n
->data
);
172 static int ack(struct fetch_negotiator
*n
, struct commit
*c
)
174 int known_to_be_common
= !!(c
->object
.flags
& COMMON
);
175 mark_common(n
->data
, c
, 0, 1);
176 return known_to_be_common
;
179 static void release(struct fetch_negotiator
*n
)
181 clear_prio_queue(&((struct negotiation_state
*)n
->data
)->rev_list
);
182 FREE_AND_NULL(n
->data
);
185 void default_negotiator_init(struct fetch_negotiator
*negotiator
)
187 struct negotiation_state
*ns
;
188 negotiator
->known_common
= known_common
;
189 negotiator
->add_tip
= add_tip
;
190 negotiator
->next
= next
;
191 negotiator
->ack
= ack
;
192 negotiator
->release
= release
;
193 negotiator
->data
= CALLOC_ARRAY(ns
, 1);
194 ns
->rev_list
.compare
= compare_commits_by_commit_date
;
197 refs_for_each_ref(get_main_ref_store(the_repository
),