]> git.ipfire.org Git - thirdparty/git.git/blob - promisor-remote.c
Merge branch 'en/ort-perf-batch-13'
[thirdparty/git.git] / promisor-remote.c
1 #include "cache.h"
2 #include "object-store.h"
3 #include "promisor-remote.h"
4 #include "config.h"
5 #include "transport.h"
6 #include "strvec.h"
7
8 static char *repository_format_partial_clone;
9
10 void set_repository_format_partial_clone(char *partial_clone)
11 {
12 repository_format_partial_clone = xstrdup_or_null(partial_clone);
13 }
14
15 static int fetch_objects(struct repository *repo,
16 const char *remote_name,
17 const struct object_id *oids,
18 int oid_nr)
19 {
20 struct child_process child = CHILD_PROCESS_INIT;
21 int i;
22 FILE *child_in;
23
24 child.git_cmd = 1;
25 child.in = -1;
26 strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",
27 "fetch", remote_name, "--no-tags",
28 "--no-write-fetch-head", "--recurse-submodules=no",
29 "--filter=blob:none", "--stdin", NULL);
30 if (start_command(&child))
31 die(_("promisor-remote: unable to fork off fetch subprocess"));
32 child_in = xfdopen(child.in, "w");
33
34 trace2_data_intmax("promisor", repo, "fetch_count", oid_nr);
35
36 for (i = 0; i < oid_nr; i++) {
37 if (fputs(oid_to_hex(&oids[i]), child_in) < 0)
38 die_errno(_("promisor-remote: could not write to fetch subprocess"));
39 if (fputc('\n', child_in) < 0)
40 die_errno(_("promisor-remote: could not write to fetch subprocess"));
41 }
42
43 if (fclose(child_in) < 0)
44 die_errno(_("promisor-remote: could not close stdin to fetch subprocess"));
45 return finish_command(&child) ? -1 : 0;
46 }
47
48 static struct promisor_remote *promisors;
49 static struct promisor_remote **promisors_tail = &promisors;
50
51 static struct promisor_remote *promisor_remote_new(const char *remote_name)
52 {
53 struct promisor_remote *r;
54
55 if (*remote_name == '/') {
56 warning(_("promisor remote name cannot begin with '/': %s"),
57 remote_name);
58 return NULL;
59 }
60
61 FLEX_ALLOC_STR(r, name, remote_name);
62
63 *promisors_tail = r;
64 promisors_tail = &r->next;
65
66 return r;
67 }
68
69 static struct promisor_remote *promisor_remote_lookup(const char *remote_name,
70 struct promisor_remote **previous)
71 {
72 struct promisor_remote *r, *p;
73
74 for (p = NULL, r = promisors; r; p = r, r = r->next)
75 if (!strcmp(r->name, remote_name)) {
76 if (previous)
77 *previous = p;
78 return r;
79 }
80
81 return NULL;
82 }
83
84 static void promisor_remote_move_to_tail(struct promisor_remote *r,
85 struct promisor_remote *previous)
86 {
87 if (r->next == NULL)
88 return;
89
90 if (previous)
91 previous->next = r->next;
92 else
93 promisors = r->next ? r->next : r;
94 r->next = NULL;
95 *promisors_tail = r;
96 promisors_tail = &r->next;
97 }
98
99 static int promisor_remote_config(const char *var, const char *value, void *data)
100 {
101 const char *name;
102 size_t namelen;
103 const char *subkey;
104
105 if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
106 return 0;
107
108 if (!strcmp(subkey, "promisor")) {
109 char *remote_name;
110
111 if (!git_config_bool(var, value))
112 return 0;
113
114 remote_name = xmemdupz(name, namelen);
115
116 if (!promisor_remote_lookup(remote_name, NULL))
117 promisor_remote_new(remote_name);
118
119 free(remote_name);
120 return 0;
121 }
122 if (!strcmp(subkey, "partialclonefilter")) {
123 struct promisor_remote *r;
124 char *remote_name = xmemdupz(name, namelen);
125
126 r = promisor_remote_lookup(remote_name, NULL);
127 if (!r)
128 r = promisor_remote_new(remote_name);
129
130 free(remote_name);
131
132 if (!r)
133 return 0;
134
135 return git_config_string(&r->partial_clone_filter, var, value);
136 }
137
138 return 0;
139 }
140
141 static int initialized;
142
143 static void promisor_remote_init(void)
144 {
145 if (initialized)
146 return;
147 initialized = 1;
148
149 git_config(promisor_remote_config, NULL);
150
151 if (repository_format_partial_clone) {
152 struct promisor_remote *o, *previous;
153
154 o = promisor_remote_lookup(repository_format_partial_clone,
155 &previous);
156 if (o)
157 promisor_remote_move_to_tail(o, previous);
158 else
159 promisor_remote_new(repository_format_partial_clone);
160 }
161 }
162
163 static void promisor_remote_clear(void)
164 {
165 while (promisors) {
166 struct promisor_remote *r = promisors;
167 promisors = promisors->next;
168 free(r);
169 }
170
171 promisors_tail = &promisors;
172 }
173
174 void promisor_remote_reinit(void)
175 {
176 initialized = 0;
177 promisor_remote_clear();
178 promisor_remote_init();
179 }
180
181 struct promisor_remote *promisor_remote_find(const char *remote_name)
182 {
183 promisor_remote_init();
184
185 if (!remote_name)
186 return promisors;
187
188 return promisor_remote_lookup(remote_name, NULL);
189 }
190
191 int has_promisor_remote(void)
192 {
193 return !!promisor_remote_find(NULL);
194 }
195
196 static int remove_fetched_oids(struct repository *repo,
197 struct object_id **oids,
198 int oid_nr, int to_free)
199 {
200 int i, remaining_nr = 0;
201 int *remaining = xcalloc(oid_nr, sizeof(*remaining));
202 struct object_id *old_oids = *oids;
203 struct object_id *new_oids;
204
205 for (i = 0; i < oid_nr; i++)
206 if (oid_object_info_extended(repo, &old_oids[i], NULL,
207 OBJECT_INFO_SKIP_FETCH_OBJECT)) {
208 remaining[i] = 1;
209 remaining_nr++;
210 }
211
212 if (remaining_nr) {
213 int j = 0;
214 CALLOC_ARRAY(new_oids, remaining_nr);
215 for (i = 0; i < oid_nr; i++)
216 if (remaining[i])
217 oidcpy(&new_oids[j++], &old_oids[i]);
218 *oids = new_oids;
219 if (to_free)
220 free(old_oids);
221 }
222
223 free(remaining);
224
225 return remaining_nr;
226 }
227
228 int promisor_remote_get_direct(struct repository *repo,
229 const struct object_id *oids,
230 int oid_nr)
231 {
232 struct promisor_remote *r;
233 struct object_id *remaining_oids = (struct object_id *)oids;
234 int remaining_nr = oid_nr;
235 int to_free = 0;
236 int res = -1;
237
238 if (oid_nr == 0)
239 return 0;
240
241 promisor_remote_init();
242
243 for (r = promisors; r; r = r->next) {
244 if (fetch_objects(repo, r->name, remaining_oids, remaining_nr) < 0) {
245 if (remaining_nr == 1)
246 continue;
247 remaining_nr = remove_fetched_oids(repo, &remaining_oids,
248 remaining_nr, to_free);
249 if (remaining_nr) {
250 to_free = 1;
251 continue;
252 }
253 }
254 res = 0;
255 break;
256 }
257
258 if (to_free)
259 free(remaining_oids);
260
261 return res;
262 }