/src/git/odb/source-files.c
Line | Count | Source |
1 | | #include "git-compat-util.h" |
2 | | #include "abspath.h" |
3 | | #include "blob.h" |
4 | | #include "chdir-notify.h" |
5 | | #include "config.h" |
6 | | #include "gettext.h" |
7 | | #include "hex.h" |
8 | | #include "lockfile.h" |
9 | | #include "object-file.h" |
10 | | #include "odb.h" |
11 | | #include "odb/source.h" |
12 | | #include "odb/source-files.h" |
13 | | #include "odb/source-loose.h" |
14 | | #include "pack-objects.h" |
15 | | #include "packfile.h" |
16 | | #include "path.h" |
17 | | #include "promisor-remote.h" |
18 | | #include "quote.h" |
19 | | #include "repack.h" |
20 | | #include "run-command.h" |
21 | | #include "strbuf.h" |
22 | | #include "string-list.h" |
23 | | #include "strmap.h" |
24 | | #include "strvec.h" |
25 | | #include "tree.h" |
26 | | #include "write-or-die.h" |
27 | | |
28 | | struct odb_files_dir *odb_files_dir_new(struct object_database *odb, |
29 | | const char *path, bool local) |
30 | 0 | { |
31 | 0 | struct odb_files_dir *dir; |
32 | |
|
33 | 0 | CALLOC_ARRAY(dir, 1); |
34 | 0 | dir->abspath = absolute_pathdup(path); |
35 | 0 | dir->local = local; |
36 | 0 | dir->loose = odb_source_loose_new(odb, path); |
37 | 0 | dir->packed = odb_source_packed_new(odb, path, local); |
38 | |
|
39 | 0 | return dir; |
40 | 0 | } |
41 | | |
42 | | void odb_files_dir_free(struct odb_files_dir *dir) |
43 | 0 | { |
44 | 0 | if (!dir) |
45 | 0 | return; |
46 | 0 | odb_source_free(&dir->loose->base); |
47 | 0 | odb_source_free(&dir->packed->base); |
48 | 0 | free(dir->abspath); |
49 | 0 | free(dir); |
50 | 0 | } |
51 | | |
52 | | static void odb_source_files_reparent(const char *old_cwd, |
53 | | const char *new_cwd, |
54 | | void *cb_data) |
55 | 0 | { |
56 | 0 | struct odb_source_files *files = cb_data; |
57 | 0 | char *path = reparent_relative_path(old_cwd, new_cwd, |
58 | 0 | files->base.path); |
59 | |
|
60 | 0 | free(files->base.path); |
61 | 0 | files->base.path = path; |
62 | 0 | } |
63 | | |
64 | | static void odb_source_files_free(struct odb_source *source) |
65 | 0 | { |
66 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
67 | |
|
68 | 0 | chdir_notify_unregister(odb_source_files_reparent, files); |
69 | |
|
70 | 0 | while (files->dirs) { |
71 | 0 | struct odb_files_dir *next = files->dirs->next; |
72 | 0 | odb_files_dir_free(files->dirs); |
73 | 0 | files->dirs = next; |
74 | 0 | } |
75 | 0 | strset_clear(&files->dir_paths); |
76 | 0 | stat_validity_clear(&files->alternates_validity); |
77 | |
|
78 | 0 | odb_source_release(&files->base); |
79 | 0 | free(files); |
80 | 0 | } |
81 | | |
82 | | static void odb_source_files_close(struct odb_source *source) |
83 | 0 | { |
84 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
85 | |
|
86 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
87 | 0 | odb_source_close(&dir->loose->base); |
88 | 0 | odb_source_close(&dir->packed->base); |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | static int odb_source_files_create_on_disk(struct odb_source *source, |
93 | | const struct odb_create_on_disk_options *opts) |
94 | 0 | { |
95 | 0 | struct lock_file alternates_lock = LOCK_INIT; |
96 | 0 | struct strbuf path = STRBUF_INIT; |
97 | 0 | struct strset seen = STRSET_INIT; |
98 | 0 | struct strbuf line = STRBUF_INIT; |
99 | 0 | int ret; |
100 | |
|
101 | 0 | safe_create_dir(source->odb->repo, source->path, 1); |
102 | |
|
103 | 0 | strbuf_addf(&path, "%s/pack", source->path); |
104 | 0 | safe_create_dir(source->odb->repo, path.buf, 1); |
105 | |
|
106 | 0 | strbuf_reset(&path); |
107 | 0 | strbuf_addf(&path, "%s/info", source->path); |
108 | 0 | safe_create_dir(source->odb->repo, path.buf, 1); |
109 | |
|
110 | 0 | if (opts->alternates && opts->alternates->nr) { |
111 | 0 | FILE *alternates, *orig; |
112 | |
|
113 | 0 | strbuf_reset(&path); |
114 | 0 | strbuf_addf(&path, "%s/info/alternates", source->path); |
115 | |
|
116 | 0 | repo_hold_lock_file_for_update(source->odb->repo, &alternates_lock, |
117 | 0 | path.buf, LOCK_DIE_ON_ERROR); |
118 | |
|
119 | 0 | alternates = fdopen_lock_file(&alternates_lock, "w"); |
120 | 0 | if (!alternates) { |
121 | 0 | ret = error_errno(_("unable to fdopen alternates lockfile")); |
122 | 0 | goto out; |
123 | 0 | } |
124 | | |
125 | | /* |
126 | | * The alternates file may already exist, e.g. when it has been |
127 | | * seeded from a template directory. Read any preexisting |
128 | | * entries so that we don't end up writing duplicates. |
129 | | */ |
130 | 0 | orig = fopen(path.buf, "r"); |
131 | 0 | if (orig) { |
132 | 0 | while (strbuf_getline(&line, orig) != EOF) { |
133 | 0 | strset_add(&seen, line.buf); |
134 | 0 | fprintf(alternates, "%s\n", line.buf); |
135 | 0 | } |
136 | |
|
137 | 0 | if (ferror(orig)) { |
138 | 0 | ret = error_errno(_("unable to read alternates file")); |
139 | 0 | fclose(orig); |
140 | 0 | goto out; |
141 | 0 | } |
142 | | |
143 | 0 | fclose(orig); |
144 | 0 | } else if (errno != ENOENT) { |
145 | 0 | ret = error_errno(_("unable to read alternates file")); |
146 | 0 | goto out; |
147 | 0 | } |
148 | | |
149 | 0 | for (size_t i = 0; i < opts->alternates->nr; i++) { |
150 | 0 | const char *alternate = opts->alternates->v[i]; |
151 | 0 | if (!strset_add(&seen, alternate)) |
152 | 0 | continue; |
153 | 0 | fprintf(alternates, "%s\n", alternate); |
154 | 0 | } |
155 | |
|
156 | 0 | if (ferror(alternates)) { |
157 | 0 | ret = error_errno(_("unable to write alternates file")); |
158 | 0 | goto out; |
159 | 0 | } |
160 | | |
161 | 0 | if (commit_lock_file(&alternates_lock)) { |
162 | 0 | ret = error_errno(_("unable to commit alternates file")); |
163 | 0 | goto out; |
164 | 0 | } |
165 | 0 | } |
166 | | |
167 | | /* Reprepare the object database to activate alternates. */ |
168 | 0 | odb_reprepare(source->odb); |
169 | |
|
170 | 0 | ret = 0; |
171 | |
|
172 | 0 | out: |
173 | 0 | rollback_lock_file(&alternates_lock); |
174 | 0 | strbuf_release(&line); |
175 | 0 | strbuf_release(&path); |
176 | 0 | strset_clear(&seen); |
177 | 0 | return ret; |
178 | 0 | } |
179 | | |
180 | | /* |
181 | | * Return non-zero iff the path is usable as an alternate object directory. |
182 | | */ |
183 | | static bool odb_files_dir_is_usable(struct odb_source_files *files, |
184 | | const char *path) |
185 | 0 | { |
186 | 0 | struct strbuf buf = STRBUF_INIT; |
187 | 0 | bool usable = false; |
188 | | |
189 | | /* |
190 | | * Prevent the common mistake of listing the same thing twice, |
191 | | * or object directory itself. |
192 | | * |
193 | | * NEEDSWORK: we're using "core.ignoreCase" to deduplicate |
194 | | * alternates that _may_ be the same. This requires quite a bit |
195 | | * of boilerplate for dubious benefit: |
196 | | * |
197 | | * - Duplicating alternates should really only lead to |
198 | | * regressed performance. |
199 | | * |
200 | | * - We don't properly resolve symlinks or mointpoints, so we |
201 | | * may still end up duplicating alternates. |
202 | | * |
203 | | * - The value may be lying, in which case we might |
204 | | * deduplicate alternates that are in fact not mapping to the |
205 | | * same directory. |
206 | | * |
207 | | * We should investigate whether we can remove this whole |
208 | | * mechanism outright. |
209 | | */ |
210 | 0 | if (strset_empty(&files->dir_paths)) { |
211 | 0 | files->dir_paths_icase = 0; |
212 | 0 | repo_config_get_bool(files->base.odb->repo, "core.ignorecase", |
213 | 0 | &files->dir_paths_icase); |
214 | |
|
215 | 0 | strbuf_realpath(&buf, files->base.path, 1); |
216 | 0 | if (files->dir_paths_icase) |
217 | 0 | strbuf_tolower(&buf); |
218 | 0 | strset_add(&files->dir_paths, buf.buf); |
219 | |
|
220 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
221 | 0 | strbuf_reset(&buf); |
222 | 0 | strbuf_addstr(&buf, dir->abspath); |
223 | 0 | if (files->dir_paths_icase) |
224 | 0 | strbuf_tolower(&buf); |
225 | 0 | strset_add(&files->dir_paths, buf.buf); |
226 | 0 | } |
227 | 0 | } |
228 | |
|
229 | 0 | strbuf_reset(&buf); |
230 | 0 | strbuf_addstr(&buf, path); |
231 | 0 | if (files->dir_paths_icase) |
232 | 0 | strbuf_tolower(&buf); |
233 | |
|
234 | 0 | if (strset_contains(&files->dir_paths, buf.buf)) |
235 | 0 | goto out; |
236 | | |
237 | | /* Detect cases where alternate disappeared */ |
238 | 0 | if (!is_directory(path)) { |
239 | 0 | error(_("object directory %s does not exist; " |
240 | 0 | "check .git/objects/info/alternates"), |
241 | 0 | path); |
242 | 0 | goto out; |
243 | 0 | } |
244 | | |
245 | 0 | usable = true; |
246 | |
|
247 | 0 | out: |
248 | 0 | strbuf_release(&buf); |
249 | 0 | return usable; |
250 | 0 | } |
251 | | |
252 | | static void parse_alternates(const char *string, |
253 | | int sep, |
254 | | const char *relative_base, |
255 | | struct strvec *out) |
256 | 0 | { |
257 | 0 | struct strbuf pathbuf = STRBUF_INIT; |
258 | 0 | struct strbuf buf = STRBUF_INIT; |
259 | |
|
260 | 0 | if (!string || !*string) |
261 | 0 | return; |
262 | | |
263 | 0 | while (*string) { |
264 | 0 | const char *end; |
265 | |
|
266 | 0 | strbuf_reset(&buf); |
267 | 0 | strbuf_reset(&pathbuf); |
268 | |
|
269 | 0 | if (*string == '#') { |
270 | | /* comment; consume up to next separator */ |
271 | 0 | end = strchrnul(string, sep); |
272 | 0 | } else if (*string == '"' && !unquote_c_style(&buf, string, &end)) { |
273 | | /* |
274 | | * quoted path; unquote_c_style has copied the |
275 | | * data for us and set "end". Broken quoting (e.g., |
276 | | * an entry that doesn't end with a quote) falls |
277 | | * back to the unquoted case below. |
278 | | */ |
279 | 0 | } else { |
280 | | /* normal, unquoted path */ |
281 | 0 | end = strchrnul(string, sep); |
282 | 0 | strbuf_add(&buf, string, end - string); |
283 | 0 | } |
284 | |
|
285 | 0 | if (*end) |
286 | 0 | end++; |
287 | 0 | string = end; |
288 | |
|
289 | 0 | if (!buf.len) |
290 | 0 | continue; |
291 | | |
292 | 0 | if (!is_absolute_path(buf.buf) && relative_base) { |
293 | 0 | strbuf_realpath(&pathbuf, relative_base, 1); |
294 | 0 | strbuf_addch(&pathbuf, '/'); |
295 | 0 | } |
296 | 0 | strbuf_addbuf(&pathbuf, &buf); |
297 | |
|
298 | 0 | strbuf_reset(&buf); |
299 | 0 | if (!strbuf_realpath(&buf, pathbuf.buf, 0)) { |
300 | 0 | error(_("unable to normalize alternate object path: %s"), |
301 | 0 | pathbuf.buf); |
302 | 0 | continue; |
303 | 0 | } |
304 | | |
305 | | /* |
306 | | * The trailing slash after the directory name is given by |
307 | | * this function at the end. Remove duplicates. |
308 | | */ |
309 | 0 | while (buf.len && buf.buf[buf.len - 1] == '/') |
310 | 0 | strbuf_setlen(&buf, buf.len - 1); |
311 | |
|
312 | 0 | strvec_push(out, buf.buf); |
313 | 0 | } |
314 | |
|
315 | 0 | strbuf_release(&pathbuf); |
316 | 0 | strbuf_release(&buf); |
317 | 0 | } |
318 | | |
319 | | static void read_alternates(const char *object_dir, struct strvec *out, |
320 | | struct stat_validity *validity) |
321 | 0 | { |
322 | 0 | struct strbuf buf = STRBUF_INIT; |
323 | 0 | char *path; |
324 | |
|
325 | 0 | path = xstrfmt("%s/info/alternates", object_dir); |
326 | 0 | if (!validity || !stat_validity_check(validity, path)) { |
327 | 0 | bool successful = false; |
328 | 0 | int fd; |
329 | |
|
330 | 0 | fd = open(path, O_RDONLY); |
331 | 0 | if (fd < 0) { |
332 | 0 | warn_on_fopen_errors(path); |
333 | 0 | } else { |
334 | 0 | if (validity) |
335 | 0 | stat_validity_update(validity, fd); |
336 | 0 | if (strbuf_read(&buf, fd, 1024) < 0) { |
337 | 0 | warning_errno(_("unable to read alternates file '%s'"), |
338 | 0 | path); |
339 | 0 | } else { |
340 | 0 | parse_alternates(buf.buf, '\n', object_dir, out); |
341 | 0 | successful = true; |
342 | 0 | } |
343 | 0 | } |
344 | |
|
345 | 0 | if (validity && !successful) |
346 | 0 | stat_validity_clear(validity); |
347 | 0 | if (fd >= 0) |
348 | 0 | close(fd); |
349 | 0 | } |
350 | |
|
351 | 0 | strbuf_release(&buf); |
352 | 0 | free(path); |
353 | 0 | } |
354 | | |
355 | | static void add_alternate_recursively(struct odb_source_files *files, |
356 | | const char *path, |
357 | | int depth) |
358 | 0 | { |
359 | 0 | struct odb_files_dir *alternate; |
360 | 0 | struct strvec alternates = STRVEC_INIT; |
361 | |
|
362 | 0 | if (!odb_files_dir_is_usable(files, path)) |
363 | 0 | goto out; |
364 | | |
365 | 0 | alternate = odb_files_dir_new(files->base.odb, path, false); |
366 | | |
367 | | /* add the alternate entry */ |
368 | 0 | *files->dirs_tail = alternate; |
369 | 0 | files->dirs_tail = &(alternate->next); |
370 | |
|
371 | 0 | if (files->dir_paths_icase) { |
372 | 0 | struct strbuf path = STRBUF_INIT; |
373 | |
|
374 | 0 | strbuf_addstr(&path, alternate->abspath); |
375 | 0 | strbuf_tolower(&path); |
376 | 0 | strset_add(&files->dir_paths, path.buf); |
377 | |
|
378 | 0 | strbuf_release(&path); |
379 | 0 | } else { |
380 | 0 | strset_add(&files->dir_paths, alternate->abspath); |
381 | 0 | } |
382 | | |
383 | | /* recursively add alternates */ |
384 | 0 | read_alternates(alternate->abspath, &alternates, NULL); |
385 | 0 | if (alternates.nr && depth + 1 > 5) { |
386 | 0 | error(_("%s: ignoring alternate object stores, nesting too deep"), |
387 | 0 | path); |
388 | 0 | } else { |
389 | 0 | for (size_t i = 0; i < alternates.nr; i++) |
390 | 0 | add_alternate_recursively(files, alternates.v[i], depth + 1); |
391 | 0 | } |
392 | |
|
393 | 0 | out: |
394 | 0 | strvec_clear(&alternates); |
395 | 0 | } |
396 | | |
397 | | static void prepare_alternates(struct odb_source_files *files, |
398 | | const char *alternate_db) |
399 | 0 | { |
400 | 0 | struct strvec alternates = STRVEC_INIT; |
401 | |
|
402 | 0 | parse_alternates(alternate_db, PATH_SEP, NULL, &alternates); |
403 | 0 | read_alternates(files->base.path, &alternates, |
404 | 0 | &files->alternates_validity); |
405 | |
|
406 | 0 | for (size_t i = 0; i < alternates.nr; i++) |
407 | 0 | add_alternate_recursively(files, alternates.v[i], 0); |
408 | |
|
409 | 0 | strvec_clear(&alternates); |
410 | 0 | } |
411 | | |
412 | | static void odb_source_files_prepare(struct odb_source *source, |
413 | | enum odb_prepare_flags flags) |
414 | 0 | { |
415 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
416 | | |
417 | | /* |
418 | | * Reprepare alternates, in case the alternates file was modified |
419 | | * during the course of this process. This only _adds_ directories to |
420 | | * the linked list, so existing directories will continue to exist |
421 | | * for the lifetime of the process. |
422 | | */ |
423 | 0 | if (flags & ODB_PREPARE_FLUSH_CACHES) |
424 | 0 | prepare_alternates(files, NULL); |
425 | |
|
426 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
427 | 0 | odb_source_prepare(&dir->loose->base, flags); |
428 | 0 | odb_source_prepare(&dir->packed->base, flags); |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | | static enum odb_read_status odb_source_files_read_object_info(struct odb_source *source, |
433 | | const struct object_id *oid, |
434 | | struct object_info *oi, |
435 | | enum object_info_flags flags, |
436 | | struct strbuf *errmsg) |
437 | 0 | { |
438 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
439 | 0 | struct odb_files_dir **tail = NULL; |
440 | 0 | enum odb_read_status status = ODB_READ_NOT_FOUND; |
441 | 0 | enum odb_read_status ret; |
442 | 0 | bool retry = false; |
443 | |
|
444 | 0 | retry: |
445 | | /* |
446 | | * Reading an object may fail even though the object exists, for |
447 | | * example because it is corrupt. Report this failure to the caller in |
448 | | * case none of the directories was able to read the object, and |
449 | | * prefer the first such error in case multiple reads have failed. |
450 | | */ |
451 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
452 | 0 | if (retry) |
453 | 0 | odb_source_prepare(&dir->packed->base, ODB_PREPARE_FLUSH_CACHES); |
454 | |
|
455 | 0 | ret = odb_source_read_object_info(&dir->packed->base, oid, oi, flags, |
456 | 0 | status == ODB_READ_NOT_FOUND ? errmsg : NULL); |
457 | 0 | if (!ret) |
458 | 0 | return 0; |
459 | 0 | if (ret != ODB_READ_NOT_FOUND && status == ODB_READ_NOT_FOUND) |
460 | 0 | status = ret; |
461 | 0 | } |
462 | | |
463 | | /* |
464 | | * When we have reprepared alternates then we only re-scan directories |
465 | | * that were newly added. |
466 | | */ |
467 | 0 | for (struct odb_files_dir *dir = tail ? *tail : files->dirs; dir; dir = dir->next) { |
468 | 0 | ret = odb_source_read_object_info(&dir->loose->base, oid, oi, flags, |
469 | 0 | status == ODB_READ_NOT_FOUND ? errmsg : NULL); |
470 | 0 | if (!ret) |
471 | 0 | return 0; |
472 | 0 | if (ret != ODB_READ_NOT_FOUND && status == ODB_READ_NOT_FOUND) |
473 | 0 | status = ret; |
474 | 0 | } |
475 | | |
476 | 0 | if (!retry && !(flags & OBJECT_INFO_QUICK)) { |
477 | 0 | tail = files->dirs_tail; |
478 | 0 | prepare_alternates(files, NULL); |
479 | 0 | retry = true; |
480 | 0 | goto retry; |
481 | 0 | } |
482 | | |
483 | 0 | return status; |
484 | 0 | } |
485 | | |
486 | | static int odb_source_files_read_object_stream(struct odb_stream **out, |
487 | | struct odb_source *source, |
488 | | const struct object_id *oid) |
489 | 0 | { |
490 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
491 | |
|
492 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) |
493 | 0 | if (!odb_source_read_object_stream(out, &dir->packed->base, oid)) |
494 | 0 | return 0; |
495 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) |
496 | 0 | if (!odb_source_read_object_stream(out, &dir->loose->base, oid)) |
497 | 0 | return 0; |
498 | | |
499 | 0 | return -1; |
500 | 0 | } |
501 | | |
502 | | static int odb_source_files_for_each_object(struct odb_source *source, |
503 | | const struct object_info *request, |
504 | | odb_for_each_object_cb cb, |
505 | | void *cb_data, |
506 | | const struct odb_for_each_object_options *opts) |
507 | 0 | { |
508 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
509 | 0 | int ret; |
510 | |
|
511 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
512 | 0 | if (opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !dir->local) |
513 | 0 | continue; |
514 | | |
515 | 0 | if (!(opts->flags & ODB_FOR_EACH_OBJECT_PROMISOR_ONLY)) { |
516 | 0 | ret = odb_source_for_each_object(&dir->loose->base, request, cb, cb_data, opts); |
517 | 0 | if (ret) |
518 | 0 | return ret; |
519 | 0 | } |
520 | | |
521 | 0 | ret = odb_source_for_each_object(&dir->packed->base, request, cb, cb_data, opts); |
522 | 0 | if (ret) |
523 | 0 | return ret; |
524 | 0 | } |
525 | | |
526 | 0 | return 0; |
527 | 0 | } |
528 | | |
529 | | static int odb_source_files_count_objects(struct odb_source *source, |
530 | | enum odb_count_objects_flags flags, |
531 | | unsigned long *out) |
532 | 0 | { |
533 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
534 | 0 | unsigned long count = 0; |
535 | 0 | int ret; |
536 | |
|
537 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
538 | 0 | unsigned long dir_count; |
539 | |
|
540 | 0 | ret = odb_source_count_objects(&dir->packed->base, flags, &dir_count); |
541 | 0 | if (ret < 0) |
542 | 0 | goto out; |
543 | 0 | count += dir_count; |
544 | |
|
545 | 0 | if (!(flags & ODB_COUNT_OBJECTS_APPROXIMATE)) { |
546 | 0 | ret = odb_source_count_objects(&dir->loose->base, flags, &dir_count); |
547 | 0 | if (ret < 0) |
548 | 0 | goto out; |
549 | 0 | count += dir_count; |
550 | 0 | } |
551 | 0 | } |
552 | | |
553 | 0 | *out = count; |
554 | 0 | ret = 0; |
555 | |
|
556 | 0 | out: |
557 | 0 | return ret; |
558 | 0 | } |
559 | | |
560 | | static int odb_source_files_find_abbrev_len(struct odb_source *source, |
561 | | const struct object_id *oid, |
562 | | unsigned min_len, |
563 | | unsigned *out) |
564 | 0 | { |
565 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
566 | 0 | unsigned len = min_len; |
567 | 0 | int ret = 0; |
568 | |
|
569 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
570 | 0 | ret = odb_source_find_abbrev_len(&dir->packed->base, oid, len, &len); |
571 | 0 | if (ret < 0) |
572 | 0 | goto out; |
573 | | |
574 | 0 | ret = odb_source_find_abbrev_len(&dir->loose->base, oid, len, &len); |
575 | 0 | if (ret < 0) |
576 | 0 | goto out; |
577 | 0 | } |
578 | | |
579 | 0 | *out = len; |
580 | 0 | ret = 0; |
581 | |
|
582 | 0 | out: |
583 | 0 | return ret; |
584 | 0 | } |
585 | | |
586 | | static int odb_source_files_freshen_object(struct odb_source *source, |
587 | | const struct object_id *oid, |
588 | | const time_t *mtime) |
589 | 0 | { |
590 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
591 | |
|
592 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) |
593 | 0 | if (odb_source_freshen_object(&dir->packed->base, oid, mtime) || |
594 | 0 | odb_source_freshen_object(&dir->loose->base, oid, mtime)) |
595 | 0 | return 1; |
596 | | |
597 | 0 | return 0; |
598 | 0 | } |
599 | | |
600 | | static int odb_source_files_write_object(struct odb_source *source, |
601 | | const void *buf, size_t len, |
602 | | enum object_type type, |
603 | | const struct object_id *oid, |
604 | | const struct object_id *compat_oid, |
605 | | const time_t *mtime, |
606 | | enum odb_write_object_flags flags) |
607 | 0 | { |
608 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
609 | 0 | return odb_source_write_object(&files->dirs->loose->base, buf, len, type, |
610 | 0 | oid, compat_oid, mtime, flags); |
611 | 0 | } |
612 | | |
613 | | static int odb_source_files_write_object_stream(struct odb_source *source, |
614 | | struct odb_stream *stream, |
615 | | struct object_id *oid) |
616 | 0 | { |
617 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
618 | 0 | return odb_source_write_object_stream(&files->dirs->loose->base, stream, oid); |
619 | 0 | } |
620 | | |
621 | | static int odb_source_files_begin_transaction(struct odb_source *source, |
622 | | struct odb_transaction **out, |
623 | | enum odb_transaction_flags flags) |
624 | 0 | { |
625 | 0 | return odb_transaction_files_begin(source, out, flags); |
626 | 0 | } |
627 | | |
628 | | static int too_many_loose_objects(struct odb_source_files *files, int limit) |
629 | 0 | { |
630 | 0 | unsigned long loose_count; |
631 | |
|
632 | 0 | if (limit <= 0) |
633 | 0 | return 0; |
634 | | |
635 | 0 | if (odb_source_count_objects(&files->dirs->loose->base, ODB_COUNT_OBJECTS_APPROXIMATE, |
636 | 0 | &loose_count) < 0) |
637 | 0 | return 0; |
638 | | |
639 | | /* |
640 | | * This is weird, but stems from legacy behaviour: the GC auto |
641 | | * threshold was always essentially interpreted as if it was rounded up |
642 | | * to the next multiple 256 of, so we retain this behaviour for now. |
643 | | */ |
644 | 0 | return loose_count > (DIV_ROUND_UP(((unsigned long) limit), 256) * 256); |
645 | 0 | } |
646 | | |
647 | | static struct packed_git *find_base_packs(struct odb_source_files *files, |
648 | | struct string_list *packs, |
649 | | unsigned long limit) |
650 | 0 | { |
651 | 0 | struct packfile_list_entry *e; |
652 | 0 | struct packed_git *base = NULL; |
653 | |
|
654 | 0 | for (e = packfile_store_get_packs(files->dirs->packed); e; e = e->next) { |
655 | 0 | if (e->pack->is_cruft) |
656 | 0 | continue; |
657 | 0 | if (limit) { |
658 | 0 | if ((uintmax_t) e->pack->pack_size >= limit) |
659 | 0 | string_list_append(packs, e->pack->pack_name); |
660 | 0 | } else if (!base || base->pack_size < e->pack->pack_size) { |
661 | 0 | base = e->pack; |
662 | 0 | } |
663 | 0 | } |
664 | |
|
665 | 0 | if (base) |
666 | 0 | string_list_append(packs, base->pack_name); |
667 | |
|
668 | 0 | return base; |
669 | 0 | } |
670 | | |
671 | | static int too_many_packs(struct odb_source_files *files, int gc_auto_pack_limit) |
672 | 0 | { |
673 | 0 | struct packfile_list_entry *e; |
674 | 0 | int cnt = 0; |
675 | |
|
676 | 0 | if (gc_auto_pack_limit <= 0) |
677 | 0 | return 0; |
678 | | |
679 | 0 | for (e = packfile_store_get_packs(files->dirs->packed); e; e = e->next) { |
680 | 0 | if (e->pack->pack_keep) |
681 | 0 | continue; |
682 | | /* |
683 | | * Perhaps check the size of the pack and count only |
684 | | * very small ones here? |
685 | | */ |
686 | 0 | cnt++; |
687 | 0 | } |
688 | 0 | return gc_auto_pack_limit < cnt; |
689 | 0 | } |
690 | | |
691 | | static uint64_t total_ram(void) |
692 | 0 | { |
693 | 0 | #if defined(HAVE_SYSINFO) |
694 | 0 | struct sysinfo si; |
695 | |
|
696 | 0 | if (!sysinfo(&si)) { |
697 | 0 | uint64_t total = si.totalram; |
698 | |
|
699 | 0 | if (si.mem_unit > 1) |
700 | 0 | total *= (uint64_t)si.mem_unit; |
701 | 0 | return total; |
702 | 0 | } |
703 | | #elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64)) |
704 | | uint64_t physical_memory; |
705 | | int mib[2]; |
706 | | size_t length; |
707 | | |
708 | | mib[0] = CTL_HW; |
709 | | # if defined(HW_MEMSIZE) |
710 | | mib[1] = HW_MEMSIZE; |
711 | | # elif defined(HW_PHYSMEM64) |
712 | | mib[1] = HW_PHYSMEM64; |
713 | | # else |
714 | | mib[1] = HW_PHYSMEM; |
715 | | # endif |
716 | | length = sizeof(physical_memory); |
717 | | if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) { |
718 | | if (length == 4) { |
719 | | uint32_t mem; |
720 | | |
721 | | if (!sysctl(mib, 2, &mem, &length, NULL, 0)) |
722 | | physical_memory = mem; |
723 | | } |
724 | | return physical_memory; |
725 | | } |
726 | | #elif defined(GIT_WINDOWS_NATIVE) |
727 | | MEMORYSTATUSEX memInfo; |
728 | | |
729 | | memInfo.dwLength = sizeof(MEMORYSTATUSEX); |
730 | | if (GlobalMemoryStatusEx(&memInfo)) |
731 | | return memInfo.ullTotalPhys; |
732 | | #endif |
733 | 0 | return 0; |
734 | 0 | } |
735 | | |
736 | | static uint64_t estimate_repack_memory(struct odb_source_files *files, |
737 | | struct packed_git *pack) |
738 | 0 | { |
739 | 0 | unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE; |
740 | 0 | unsigned long delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT; |
741 | 0 | unsigned long nr_objects; |
742 | 0 | size_t os_cache, heap; |
743 | |
|
744 | 0 | if (odb_source_count_objects(&files->base, ODB_COUNT_OBJECTS_APPROXIMATE, |
745 | 0 | &nr_objects) < 0) |
746 | 0 | return 0; |
747 | | |
748 | 0 | if (!pack || !nr_objects) |
749 | 0 | return 0; |
750 | | |
751 | 0 | repo_config_get_ulong(files->base.odb->repo, "pack.deltacachesize", |
752 | 0 | &max_delta_cache_size); |
753 | 0 | repo_config_get_ulong(files->base.odb->repo, "core.deltabasecachelimit", |
754 | 0 | &delta_base_cache_limit); |
755 | | |
756 | | /* |
757 | | * First we have to scan through at least one pack. |
758 | | * Assume enough room in OS file cache to keep the entire pack |
759 | | * or we may accidentally evict data of other processes from |
760 | | * the cache. |
761 | | */ |
762 | 0 | os_cache = pack->pack_size + pack->index_size; |
763 | | /* then pack-objects needs lots more for book keeping */ |
764 | 0 | heap = sizeof(struct object_entry) * nr_objects; |
765 | | /* |
766 | | * internal rev-list --all --objects takes up some memory too, |
767 | | * let's say half of it is for blobs |
768 | | */ |
769 | 0 | heap += sizeof(struct blob) * nr_objects / 2; |
770 | | /* |
771 | | * and the other half is for trees (commits and tags are |
772 | | * usually insignificant) |
773 | | */ |
774 | 0 | heap += sizeof(struct tree) * nr_objects / 2; |
775 | | /* and then obj_hash[], underestimated in fact */ |
776 | 0 | heap += sizeof(struct object *) * nr_objects; |
777 | | /* revindex is used also */ |
778 | 0 | heap += (sizeof(off_t) + sizeof(uint32_t)) * nr_objects; |
779 | | /* |
780 | | * read_sha1_file() (either at delta calculation phase, or |
781 | | * writing phase) also fills up the delta base cache |
782 | | */ |
783 | 0 | heap += delta_base_cache_limit; |
784 | | /* and of course pack-objects has its own delta cache */ |
785 | 0 | heap += max_delta_cache_size; |
786 | |
|
787 | 0 | return os_cache + heap; |
788 | 0 | } |
789 | | |
790 | | static int keep_one_pack(struct string_list_item *item, void *data) |
791 | 0 | { |
792 | 0 | struct strvec *args = data; |
793 | 0 | strvec_pushf(args, "--keep-pack=%s", basename(item->string)); |
794 | 0 | return 0; |
795 | 0 | } |
796 | | |
797 | | static void add_repack_all_option(struct repository *repo, |
798 | | const struct odb_optimize_options *opts, |
799 | | struct string_list *keep_pack, |
800 | | struct strvec *args) |
801 | 0 | { |
802 | 0 | char *repack_filter = NULL; |
803 | 0 | char *repack_filter_to = NULL; |
804 | |
|
805 | 0 | repo_config_get_string(repo, "gc.repackfilter", &repack_filter); |
806 | 0 | repo_config_get_string(repo, "gc.repackfilterto", &repack_filter_to); |
807 | |
|
808 | 0 | if (opts->prune_expire && !strcmp(opts->prune_expire, "now") && |
809 | 0 | !(opts->cruft_packs && opts->expire_to)) |
810 | 0 | strvec_push(args, "-a"); |
811 | 0 | else if (opts->cruft_packs) { |
812 | 0 | strvec_push(args, "--cruft"); |
813 | 0 | if (opts->prune_expire) |
814 | 0 | strvec_pushf(args, "--cruft-expiration=%s", opts->prune_expire); |
815 | 0 | if (opts->max_cruft_size) |
816 | 0 | strvec_pushf(args, "--max-cruft-size=%lu", |
817 | 0 | opts->max_cruft_size); |
818 | 0 | if (opts->expire_to) |
819 | 0 | strvec_pushf(args, "--expire-to=%s", opts->expire_to); |
820 | 0 | } else { |
821 | 0 | strvec_push(args, "-A"); |
822 | 0 | if (opts->prune_expire) |
823 | 0 | strvec_pushf(args, "--unpack-unreachable=%s", opts->prune_expire); |
824 | 0 | } |
825 | |
|
826 | 0 | if (keep_pack) |
827 | 0 | for_each_string_list(keep_pack, keep_one_pack, args); |
828 | |
|
829 | 0 | if (repack_filter && *repack_filter) |
830 | 0 | strvec_pushf(args, "--filter=%s", repack_filter); |
831 | 0 | if (repack_filter_to && *repack_filter_to) |
832 | 0 | strvec_pushf(args, "--filter-to=%s", repack_filter_to); |
833 | |
|
834 | 0 | free(repack_filter); |
835 | 0 | free(repack_filter_to); |
836 | 0 | } |
837 | | |
838 | | static void add_repack_incremental_option(struct strvec *args) |
839 | 0 | { |
840 | 0 | strvec_push(args, "--no-write-bitmap-index"); |
841 | 0 | } |
842 | | |
843 | | bool odb_source_files_optimize_required(struct odb_source *source, |
844 | | const struct odb_optimize_options *opts) |
845 | 0 | { |
846 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
847 | 0 | struct repository *repo = source->odb->repo; |
848 | |
|
849 | 0 | switch (opts->strategy) { |
850 | 0 | case ODB_OPTIMIZE_INCREMENTAL: { |
851 | 0 | int gc_auto_threshold = 6700; |
852 | 0 | int gc_auto_pack_limit = 50; |
853 | |
|
854 | 0 | repo_config_get_int(repo, "gc.auto", &gc_auto_threshold); |
855 | 0 | repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit); |
856 | | |
857 | | /* |
858 | | * Setting gc.auto to 0 or negative can disable the |
859 | | * automatic gc. |
860 | | */ |
861 | 0 | if (gc_auto_threshold <= 0) |
862 | 0 | return false; |
863 | 0 | if (!too_many_packs(files, gc_auto_pack_limit) && |
864 | 0 | !too_many_loose_objects(files, gc_auto_threshold)) |
865 | 0 | return false; |
866 | | |
867 | 0 | return true; |
868 | 0 | } |
869 | 0 | case ODB_OPTIMIZE_GEOMETRIC: { |
870 | 0 | struct pack_geometry geometry = { |
871 | 0 | .split_factor = 2, |
872 | 0 | }; |
873 | 0 | struct pack_objects_args po_args = { |
874 | 0 | .local = 1, |
875 | 0 | }; |
876 | 0 | struct existing_packs existing_packs = EXISTING_PACKS_INIT; |
877 | 0 | struct string_list kept_packs = STRING_LIST_INIT_DUP; |
878 | 0 | int auto_value = 6700; |
879 | 0 | bool ret; |
880 | |
|
881 | 0 | repo_config_get_int(repo, "maintenance.geometric-repack.auto", |
882 | 0 | &auto_value); |
883 | 0 | if (!auto_value) |
884 | 0 | return false; |
885 | 0 | if (auto_value < 0) |
886 | 0 | return true; |
887 | | |
888 | 0 | repo_config_get_int(repo, "maintenance.geometric-repack.splitFactor", |
889 | 0 | &geometry.split_factor); |
890 | |
|
891 | 0 | existing_packs.repo = repo; |
892 | 0 | existing_packs_collect(&existing_packs, &kept_packs); |
893 | 0 | pack_geometry_init(&geometry, &existing_packs, &po_args); |
894 | 0 | pack_geometry_split(&geometry); |
895 | | |
896 | | /* |
897 | | * When we'd merge at least two packs with one another we always |
898 | | * perform the repack. |
899 | | */ |
900 | 0 | if (geometry.split) { |
901 | 0 | ret = true; |
902 | 0 | goto out; |
903 | 0 | } |
904 | | |
905 | | /* |
906 | | * Otherwise, we estimate the number of loose objects to determine |
907 | | * whether we want to create a new packfile or not. |
908 | | */ |
909 | 0 | if (too_many_loose_objects(files, auto_value)) { |
910 | 0 | ret = true; |
911 | 0 | goto out; |
912 | 0 | } |
913 | | |
914 | 0 | ret = false; |
915 | |
|
916 | 0 | out: |
917 | 0 | existing_packs_release(&existing_packs); |
918 | 0 | pack_geometry_release(&geometry); |
919 | 0 | return ret; |
920 | 0 | } |
921 | 0 | default: |
922 | 0 | BUG("unknown maintenance strategy '%d'", opts->strategy); |
923 | 0 | } |
924 | 0 | } |
925 | | |
926 | | int odb_source_files_optimize(struct odb_source *source, |
927 | | const struct odb_optimize_options *opts) |
928 | 0 | { |
929 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
930 | 0 | struct repository *repo = source->odb->repo; |
931 | 0 | struct child_process repack_cmd = CHILD_PROCESS_INIT; |
932 | 0 | unsigned long big_pack_threshold = 0; |
933 | 0 | int gc_auto_threshold = 6700; |
934 | 0 | int gc_auto_pack_limit = 50; |
935 | 0 | int ret; |
936 | |
|
937 | 0 | repo_config_get_int(repo, "gc.auto", &gc_auto_threshold); |
938 | 0 | repo_config_get_int(repo, "gc.autopacklimit", &gc_auto_pack_limit); |
939 | 0 | repo_config_get_ulong(repo, "gc.bigpackthreshold", &big_pack_threshold); |
940 | |
|
941 | 0 | if (repo->repository_format_precious_objects) |
942 | 0 | return 0; |
943 | | |
944 | 0 | repack_cmd.git_cmd = 1; |
945 | 0 | repack_cmd.odb_to_close = repo->objects; |
946 | |
|
947 | 0 | strvec_pushl(&repack_cmd.args, "repack", "-d", "-l", NULL); |
948 | 0 | if (opts->flags & ODB_OPTIMIZE_NO_REUSE_DELTAS) |
949 | 0 | strvec_push(&repack_cmd.args, "-f"); |
950 | 0 | if (opts->depth > 0) |
951 | 0 | strvec_pushf(&repack_cmd.args, "--depth=%d", opts->depth); |
952 | 0 | if (opts->window > 0) |
953 | 0 | strvec_pushf(&repack_cmd.args, "--window=%d", opts->window); |
954 | 0 | if (!(opts->flags & ODB_OPTIMIZE_VERBOSE)) |
955 | 0 | strvec_push(&repack_cmd.args, "-q"); |
956 | | |
957 | | /* |
958 | | * There's three cases we need to consider: |
959 | | * |
960 | | * - If we're invoked without `--auto` we'll need to perform a full |
961 | | * repack. |
962 | | * |
963 | | * - If we're invoked with `--auto` and there's too many packs, then |
964 | | * we perform a full repack, as well. |
965 | | * |
966 | | * - Otherwise we perform an incremental repack. |
967 | | */ |
968 | 0 | switch (opts->strategy) { |
969 | 0 | case ODB_OPTIMIZE_INCREMENTAL: |
970 | 0 | if (!(opts->flags & ODB_OPTIMIZE_AUTO)) { |
971 | 0 | struct string_list keep_pack = STRING_LIST_INIT_NODUP; |
972 | |
|
973 | 0 | if (opts->keep_largest_pack != -1) { |
974 | 0 | if (opts->keep_largest_pack) |
975 | 0 | find_base_packs(files, &keep_pack, 0); |
976 | 0 | } else if (big_pack_threshold) { |
977 | 0 | find_base_packs(files, &keep_pack, big_pack_threshold); |
978 | 0 | } |
979 | |
|
980 | 0 | add_repack_all_option(repo, opts, &keep_pack, &repack_cmd.args); |
981 | 0 | string_list_clear(&keep_pack, 0); |
982 | 0 | } else { |
983 | 0 | if (too_many_packs(files, gc_auto_pack_limit)) { |
984 | 0 | struct string_list keep_pack = STRING_LIST_INIT_NODUP; |
985 | |
|
986 | 0 | if (big_pack_threshold) { |
987 | 0 | find_base_packs(files, &keep_pack, big_pack_threshold); |
988 | 0 | if (keep_pack.nr >= (unsigned long) gc_auto_pack_limit) { |
989 | 0 | string_list_clear(&keep_pack, 0); |
990 | 0 | find_base_packs(files, &keep_pack, 0); |
991 | 0 | } |
992 | 0 | } else { |
993 | 0 | struct packed_git *p = find_base_packs(files, &keep_pack, 0); |
994 | 0 | uint64_t mem_have, mem_want; |
995 | |
|
996 | 0 | mem_have = total_ram(); |
997 | 0 | mem_want = estimate_repack_memory(files, p); |
998 | | |
999 | | /* |
1000 | | * Only allow 1/2 of memory for pack-objects, leave |
1001 | | * the rest for the OS and other processes in the |
1002 | | * system. |
1003 | | */ |
1004 | 0 | if (!mem_have || mem_want < mem_have / 2) |
1005 | 0 | string_list_clear(&keep_pack, 0); |
1006 | 0 | } |
1007 | |
|
1008 | 0 | add_repack_all_option(repo, opts, &keep_pack, &repack_cmd.args); |
1009 | 0 | string_list_clear(&keep_pack, 0); |
1010 | 0 | } else { |
1011 | 0 | add_repack_incremental_option(&repack_cmd.args); |
1012 | 0 | } |
1013 | 0 | } |
1014 | |
|
1015 | 0 | break; |
1016 | 0 | case ODB_OPTIMIZE_GEOMETRIC: { |
1017 | 0 | struct pack_geometry geometry = { |
1018 | 0 | .split_factor = 2, |
1019 | 0 | }; |
1020 | 0 | struct pack_objects_args po_args = { |
1021 | 0 | .local = 1, |
1022 | 0 | }; |
1023 | 0 | struct existing_packs existing_packs = EXISTING_PACKS_INIT; |
1024 | 0 | struct string_list kept_packs = STRING_LIST_INIT_DUP; |
1025 | |
|
1026 | 0 | repo_config_get_int(repo, "maintenance.geometric-repack.splitFactor", |
1027 | 0 | &geometry.split_factor); |
1028 | |
|
1029 | 0 | existing_packs.repo = repo; |
1030 | 0 | existing_packs_collect(&existing_packs, &kept_packs); |
1031 | 0 | pack_geometry_init(&geometry, &existing_packs, &po_args); |
1032 | 0 | pack_geometry_split(&geometry); |
1033 | |
|
1034 | 0 | if (geometry.split < geometry.pack_nr) { |
1035 | 0 | strvec_pushf(&repack_cmd.args, "--geometric=%d", |
1036 | 0 | geometry.split_factor); |
1037 | 0 | } else { |
1038 | 0 | add_repack_all_option(repo, opts, NULL, &repack_cmd.args); |
1039 | 0 | } |
1040 | 0 | if (repo->settings.core_multi_pack_index) |
1041 | 0 | strvec_push(&repack_cmd.args, "--write-midx"); |
1042 | |
|
1043 | 0 | existing_packs_release(&existing_packs); |
1044 | 0 | pack_geometry_release(&geometry); |
1045 | 0 | break; |
1046 | 0 | } |
1047 | 0 | default: |
1048 | 0 | die("unknown maintenance strategy '%d'", opts->strategy); |
1049 | 0 | } |
1050 | | |
1051 | 0 | if (run_command(&repack_cmd)) { |
1052 | 0 | ret = error("failed to run %s", repack_cmd.args.v[0]); |
1053 | 0 | goto out; |
1054 | 0 | } |
1055 | | |
1056 | | /* Geometric repacking uses cruft packs, so we don't have to prune separately. */ |
1057 | 0 | if (opts->strategy != ODB_OPTIMIZE_GEOMETRIC && opts->prune_expire) { |
1058 | 0 | struct child_process prune_cmd = CHILD_PROCESS_INIT; |
1059 | |
|
1060 | 0 | strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL); |
1061 | | /* run `git prune` even if using cruft packs */ |
1062 | 0 | strvec_push(&prune_cmd.args, opts->prune_expire); |
1063 | 0 | if (!(opts->flags & ODB_OPTIMIZE_VERBOSE)) |
1064 | 0 | strvec_push(&prune_cmd.args, "--no-progress"); |
1065 | 0 | if (repo_has_promisor_remote(repo)) |
1066 | 0 | strvec_push(&prune_cmd.args, |
1067 | 0 | "--exclude-promisor-objects"); |
1068 | 0 | prune_cmd.git_cmd = 1; |
1069 | |
|
1070 | 0 | if (run_command(&prune_cmd)) { |
1071 | 0 | ret = error("failed to run %s", prune_cmd.args.v[0]); |
1072 | 0 | goto out; |
1073 | 0 | } |
1074 | 0 | } |
1075 | | |
1076 | 0 | if (opts->flags & ODB_OPTIMIZE_AUTO && too_many_loose_objects(files, gc_auto_threshold)) |
1077 | 0 | warning(_("There are too many unreachable loose objects; " |
1078 | 0 | "run 'git prune' to remove them.")); |
1079 | |
|
1080 | 0 | ret = 0; |
1081 | |
|
1082 | 0 | out: |
1083 | 0 | return ret; |
1084 | 0 | } |
1085 | | |
1086 | | struct odb_pack_generator_files { |
1087 | | struct odb_pack_generator base; |
1088 | | struct child_process cp; |
1089 | | }; |
1090 | | |
1091 | | static int odb_pack_generator_files_finish(struct odb_pack_generator *_generator) |
1092 | 0 | { |
1093 | 0 | struct odb_pack_generator_files *generator = |
1094 | 0 | (struct odb_pack_generator_files *)_generator; |
1095 | 0 | int ret; |
1096 | |
|
1097 | 0 | ret = finish_command(&generator->cp); |
1098 | 0 | free(generator); |
1099 | |
|
1100 | 0 | if (ret) { |
1101 | | /* |
1102 | | * On failure, pack-objects is expected to have written a |
1103 | | * useful error message to its standard error stream already. |
1104 | | * Death by signal is worth mentioning, though, with the |
1105 | | * exception of SIGPIPE: that is a normal occurrence when the |
1106 | | * consumer of the pack hangs up. |
1107 | | */ |
1108 | 0 | if (ret > 128 && ret - 128 == SIGPIPE) |
1109 | 0 | return -1; |
1110 | 0 | if (ret > 128) |
1111 | 0 | error(_("pack-objects died of signal %d"), ret - 128); |
1112 | 0 | return -1; |
1113 | 0 | } |
1114 | | |
1115 | 0 | return 0; |
1116 | 0 | } |
1117 | | |
1118 | | static int odb_source_files_generate_pack(struct odb_source *source UNUSED, |
1119 | | struct odb_pack_generator **out, |
1120 | | const struct odb_generate_pack_options *opts) |
1121 | 0 | { |
1122 | 0 | struct odb_pack_generator_files *generator; |
1123 | 0 | struct child_process *cp; |
1124 | 0 | FILE *in; |
1125 | |
|
1126 | 0 | CALLOC_ARRAY(generator, 1); |
1127 | 0 | child_process_init(&generator->cp); |
1128 | 0 | cp = &generator->cp; |
1129 | | |
1130 | | /* |
1131 | | * The hook is expected to spawn "$hook git pack-objects <args...>" |
1132 | | * and to behave like git-pack-objects(1) would have. This can for |
1133 | | * example be used to serve precomputed packfiles. |
1134 | | */ |
1135 | 0 | if (opts->pack_objects_hook) { |
1136 | 0 | strvec_push(&cp->args, opts->pack_objects_hook); |
1137 | 0 | strvec_push(&cp->args, "git"); |
1138 | 0 | cp->use_shell = 1; |
1139 | 0 | } else { |
1140 | 0 | cp->git_cmd = 1; |
1141 | 0 | } |
1142 | | |
1143 | | /* |
1144 | | * The caller-provided shallow boundary overrides any shallow state |
1145 | | * that the repository itself may have, so the shallow file needs to |
1146 | | * be neutralized. |
1147 | | */ |
1148 | 0 | if (opts->shallows.nr) { |
1149 | 0 | strvec_push(&cp->args, "--shallow-file"); |
1150 | 0 | strvec_push(&cp->args, ""); |
1151 | 0 | } |
1152 | 0 | strvec_push(&cp->args, "pack-objects"); |
1153 | 0 | strvec_push(&cp->args, "--revs"); |
1154 | 0 | strvec_push(&cp->args, "--stdout"); |
1155 | 0 | if (opts->thin) |
1156 | 0 | strvec_push(&cp->args, "--thin"); |
1157 | 0 | if (opts->shallow) |
1158 | 0 | strvec_push(&cp->args, "--shallow"); |
1159 | 0 | if (opts->ofs_delta) |
1160 | 0 | strvec_push(&cp->args, "--delta-base-offset"); |
1161 | 0 | if (opts->include_tag) |
1162 | 0 | strvec_push(&cp->args, "--include-tag"); |
1163 | 0 | if (opts->missing_allow_promisor) |
1164 | 0 | strvec_push(&cp->args, "--missing=allow-promisor"); |
1165 | 0 | if (opts->disable_bitmaps) |
1166 | 0 | strvec_push(&cp->args, "--no-use-bitmap-index"); |
1167 | 0 | switch (opts->progress) { |
1168 | 0 | case ODB_GENERATE_PACK_PROGRESS_NONE: |
1169 | 0 | strvec_push(&cp->args, "--quiet"); |
1170 | 0 | break; |
1171 | 0 | case ODB_GENERATE_PACK_PROGRESS_STANDARD: |
1172 | 0 | strvec_push(&cp->args, "--progress"); |
1173 | 0 | break; |
1174 | 0 | case ODB_GENERATE_PACK_PROGRESS_VERBOSE: |
1175 | 0 | strvec_push(&cp->args, "--all-progress"); |
1176 | 0 | break; |
1177 | 0 | default: |
1178 | 0 | BUG("unknown progress option %d", opts->progress); |
1179 | 0 | } |
1180 | 0 | if (opts->filter_spec) |
1181 | 0 | strvec_pushf(&cp->args, "--filter=%s", opts->filter_spec); |
1182 | 0 | if (opts->uri_protocols) |
1183 | 0 | for (size_t i = 0; i < opts->uri_protocols->nr; i++) |
1184 | 0 | strvec_pushf(&cp->args, "--uri-protocol=%s", |
1185 | 0 | opts->uri_protocols->items[i].string); |
1186 | |
|
1187 | 0 | cp->in = -1; |
1188 | 0 | cp->out = opts->pack_fd; |
1189 | 0 | cp->err = opts->progress_fd; |
1190 | 0 | cp->clean_on_exit = 1; |
1191 | |
|
1192 | 0 | if (start_command(cp)) { |
1193 | 0 | free(generator); |
1194 | 0 | return error(_("could not spawn pack-objects")); |
1195 | 0 | } |
1196 | | |
1197 | | /* |
1198 | | * Feed the objects to pack-objects. This is safe to do synchronously |
1199 | | * because pack-objects consumes all of its standard input before it |
1200 | | * starts to generate the pack. |
1201 | | */ |
1202 | 0 | in = xfdopen(cp->in, "w"); |
1203 | 0 | for (size_t i = 0; i < opts->shallows.nr; i++) |
1204 | 0 | fprintf(in, "--shallow %s\n", oid_to_hex(&opts->shallows.oid[i])); |
1205 | 0 | for (size_t i = 0; i < opts->wants.nr; i++) |
1206 | 0 | fprintf(in, "%s\n", oid_to_hex(&opts->wants.oid[i])); |
1207 | 0 | fprintf(in, "--not\n"); |
1208 | 0 | for (size_t i = 0; i < opts->haves.nr; i++) |
1209 | 0 | fprintf(in, "%s\n", oid_to_hex(&opts->haves.oid[i])); |
1210 | 0 | fprintf(in, "\n"); |
1211 | 0 | fflush(in); |
1212 | 0 | if (ferror(in)) { |
1213 | 0 | error(_("error writing to pack-objects")); |
1214 | 0 | fclose(in); |
1215 | 0 | if (opts->pack_fd < 0) |
1216 | 0 | close(cp->out); |
1217 | 0 | if (opts->progress_fd < 0) |
1218 | 0 | close(cp->err); |
1219 | 0 | finish_command(cp); |
1220 | 0 | free(generator); |
1221 | 0 | return -1; |
1222 | 0 | } |
1223 | 0 | fclose(in); |
1224 | |
|
1225 | 0 | generator->base.out = opts->pack_fd < 0 ? cp->out : -1; |
1226 | 0 | generator->base.err = opts->progress_fd < 0 ? cp->err : -1; |
1227 | 0 | generator->base.finish = odb_pack_generator_files_finish; |
1228 | |
|
1229 | 0 | *out = &generator->base; |
1230 | 0 | return 0; |
1231 | 0 | } |
1232 | | |
1233 | | static int odb_source_files_fsck(struct odb_source *source, |
1234 | | struct odb_fsck_options *opts) |
1235 | 0 | { |
1236 | 0 | struct odb_source_files *files = odb_source_files_downcast(source); |
1237 | 0 | int ret = 0; |
1238 | |
|
1239 | 0 | for (struct odb_files_dir *dir = files->dirs; dir; dir = dir->next) { |
1240 | 0 | if (!(opts->flags & ODB_FSCK_FULL) && !dir->local) |
1241 | 0 | continue; |
1242 | | |
1243 | 0 | ret |= odb_source_fsck(&dir->loose->base, opts); |
1244 | 0 | ret |= odb_source_fsck(&dir->packed->base, opts); |
1245 | 0 | } |
1246 | |
|
1247 | 0 | return ret; |
1248 | 0 | } |
1249 | | |
1250 | | struct odb_files_dir *odb_source_files_find_dir(struct object_database *odb, const char *obj_dir) |
1251 | 0 | { |
1252 | 0 | struct odb_source_files *files = odb_source_files_downcast(odb->source); |
1253 | 0 | char *obj_dir_real = real_pathdup(obj_dir, 1); |
1254 | 0 | struct strbuf odb_path_real = STRBUF_INIT; |
1255 | 0 | struct odb_files_dir *dir; |
1256 | |
|
1257 | 0 | for (dir = files->dirs; dir; dir = dir->next) { |
1258 | 0 | strbuf_realpath(&odb_path_real, dir->abspath, 1); |
1259 | 0 | if (!strcmp(obj_dir_real, odb_path_real.buf)) |
1260 | 0 | break; |
1261 | 0 | } |
1262 | |
|
1263 | 0 | free(obj_dir_real); |
1264 | 0 | strbuf_release(&odb_path_real); |
1265 | 0 | return dir; |
1266 | 0 | } |
1267 | | |
1268 | | struct odb_source_files *odb_source_files_new(struct object_database *odb, |
1269 | | const char *payload, |
1270 | | enum odb_new_flags flags) |
1271 | 0 | { |
1272 | 0 | struct odb_source_files *files; |
1273 | 0 | char *object_dir = NULL; |
1274 | 0 | char *alternates = NULL; |
1275 | |
|
1276 | 0 | if (flags & ODB_NEW_HONOR_ENV) { |
1277 | 0 | object_dir = xstrdup_or_null(getenv(DB_ENVIRONMENT)); |
1278 | 0 | alternates = xstrdup_or_null(getenv(ALTERNATE_DB_ENVIRONMENT)); |
1279 | 0 | } |
1280 | 0 | if (!object_dir && payload) { |
1281 | 0 | if (is_absolute_path(payload)) |
1282 | 0 | object_dir = xstrdup(payload); |
1283 | 0 | else |
1284 | 0 | object_dir = xstrfmt("%s/%s", odb->repo->commondir, payload); |
1285 | 0 | } |
1286 | 0 | if (!object_dir) |
1287 | 0 | object_dir = xstrfmt("%s/objects", odb->repo->commondir); |
1288 | |
|
1289 | 0 | CALLOC_ARRAY(files, 1); |
1290 | 0 | odb_source_init(&files->base, odb, ODB_SOURCE_FILES, object_dir); |
1291 | |
|
1292 | 0 | files->dirs = odb_files_dir_new(odb, object_dir, true); |
1293 | 0 | files->dirs_tail = &files->dirs->next; |
1294 | 0 | strset_init(&files->dir_paths); |
1295 | |
|
1296 | 0 | files->base.free = odb_source_files_free; |
1297 | 0 | files->base.close = odb_source_files_close; |
1298 | 0 | files->base.create_on_disk = odb_source_files_create_on_disk; |
1299 | 0 | files->base.prepare = odb_source_files_prepare; |
1300 | 0 | files->base.fsck = odb_source_files_fsck; |
1301 | 0 | files->base.read_object_info = odb_source_files_read_object_info; |
1302 | 0 | files->base.read_object_stream = odb_source_files_read_object_stream; |
1303 | 0 | files->base.for_each_object = odb_source_files_for_each_object; |
1304 | 0 | files->base.count_objects = odb_source_files_count_objects; |
1305 | 0 | files->base.find_abbrev_len = odb_source_files_find_abbrev_len; |
1306 | 0 | files->base.freshen_object = odb_source_files_freshen_object; |
1307 | 0 | files->base.write_object = odb_source_files_write_object; |
1308 | 0 | files->base.write_object_stream = odb_source_files_write_object_stream; |
1309 | 0 | files->base.begin_transaction = odb_source_files_begin_transaction; |
1310 | 0 | files->base.optimize = odb_source_files_optimize; |
1311 | 0 | files->base.optimize_required = odb_source_files_optimize_required; |
1312 | 0 | files->base.generate_pack = odb_source_files_generate_pack; |
1313 | | |
1314 | | /* |
1315 | | * Ideally, we would only ever store absolute paths in the source. This |
1316 | | * is not (yet) possible though because we access and assume relative |
1317 | | * paths in the primary ODB source in some user-facing functionality. |
1318 | | */ |
1319 | 0 | if (!is_absolute_path(object_dir)) |
1320 | 0 | chdir_notify_register(odb_source_files_reparent, files); |
1321 | |
|
1322 | 0 | prepare_alternates(files, alternates); |
1323 | |
|
1324 | 0 | free(object_dir); |
1325 | 0 | free(alternates); |
1326 | 0 | return files; |
1327 | 0 | } |