4 #include "../fetch-negotiator.h"
5 #include "../prio-queue.h"
9 /* Remember to update object flag allocation in object.h */
10 #define COMMON (1U << 2)
11 #define COMMON_REF (1U << 3)
12 #define SEEN (1U << 4)
13 #define POPPED (1U << 5)
17 struct negotiation_state
{
18 struct prio_queue rev_list
;
22 static void rev_list_push(struct negotiation_state
*ns
,
23 struct commit
*commit
, int mark
)
25 if (!(commit
->object
.flags
& mark
)) {
26 commit
->object
.flags
|= mark
;
28 if (parse_commit(commit
))
31 prio_queue_put(&ns
->rev_list
, commit
);
33 if (!(commit
->object
.flags
& COMMON
))
34 ns
->non_common_revs
++;
38 static int clear_marks(const char *refname
, const struct object_id
*oid
,
39 int flag
, void *cb_data
)
41 struct object
*o
= deref_tag(the_repository
, parse_object(the_repository
, oid
), refname
, 0);
43 if (o
&& o
->type
== OBJ_COMMIT
)
44 clear_commit_marks((struct commit
*)o
,
45 COMMON
| COMMON_REF
| SEEN
| POPPED
);
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).
54 static void mark_common(struct negotiation_state
*ns
, struct commit
*commit
,
55 int ancestors_only
, int dont_parse
)
57 if (commit
!= NULL
&& !(commit
->object
.flags
& COMMON
)) {
58 struct object
*o
= (struct object
*)commit
;
63 if (!(o
->flags
& SEEN
))
64 rev_list_push(ns
, commit
, SEEN
);
66 struct commit_list
*parents
;
68 if (!ancestors_only
&& !(o
->flags
& POPPED
))
69 ns
->non_common_revs
--;
70 if (!o
->parsed
&& !dont_parse
)
71 if (parse_commit(commit
))
74 for (parents
= commit
->parents
;
76 parents
= parents
->next
)
77 mark_common(ns
, parents
->item
, 0,
84 * Get the next rev to send, ignoring the common.
86 static const struct object_id
*get_rev(struct negotiation_state
*ns
)
88 struct commit
*commit
= NULL
;
90 while (commit
== NULL
) {
92 struct commit_list
*parents
;
94 if (ns
->rev_list
.nr
== 0 || ns
->non_common_revs
== 0)
97 commit
= prio_queue_get(&ns
->rev_list
);
99 parents
= commit
->parents
;
101 commit
->object
.flags
|= POPPED
;
102 if (!(commit
->object
.flags
& COMMON
))
103 ns
->non_common_revs
--;
105 if (commit
->object
.flags
& COMMON
) {
106 /* do not send "have", and ignore ancestors */
108 mark
= COMMON
| SEEN
;
109 } else if (commit
->object
.flags
& COMMON_REF
)
110 /* send "have", and ignore ancestors */
111 mark
= COMMON
| SEEN
;
113 /* send "have", also for its ancestors */
117 if (!(parents
->item
->object
.flags
& SEEN
))
118 rev_list_push(ns
, parents
->item
, mark
);
120 mark_common(ns
, parents
->item
, 1, 0);
121 parents
= parents
->next
;
125 return &commit
->object
.oid
;
128 static void known_common(struct fetch_negotiator
*n
, struct commit
*c
)
130 if (!(c
->object
.flags
& SEEN
)) {
131 rev_list_push(n
->data
, c
, COMMON_REF
| SEEN
);
132 mark_common(n
->data
, c
, 1, 1);
136 static void add_tip(struct fetch_negotiator
*n
, struct commit
*c
)
138 n
->known_common
= NULL
;
139 rev_list_push(n
->data
, c
, SEEN
);
142 static const struct object_id
*next(struct fetch_negotiator
*n
)
144 n
->known_common
= NULL
;
146 return get_rev(n
->data
);
149 static int ack(struct fetch_negotiator
*n
, struct commit
*c
)
151 int known_to_be_common
= !!(c
->object
.flags
& COMMON
);
152 mark_common(n
->data
, c
, 0, 1);
153 return known_to_be_common
;
156 static void release(struct fetch_negotiator
*n
)
158 clear_prio_queue(&((struct negotiation_state
*)n
->data
)->rev_list
);
159 FREE_AND_NULL(n
->data
);
162 void default_negotiator_init(struct fetch_negotiator
*negotiator
)
164 struct negotiation_state
*ns
;
165 negotiator
->known_common
= known_common
;
166 negotiator
->add_tip
= add_tip
;
167 negotiator
->next
= next
;
168 negotiator
->ack
= ack
;
169 negotiator
->release
= release
;
170 negotiator
->data
= ns
= xcalloc(1, sizeof(*ns
));
171 ns
->rev_list
.compare
= compare_commits_by_commit_date
;
174 for_each_ref(clear_marks
, NULL
);