environment: move access to "core.bigFileThreshold" into repo settings

The "core.bigFileThreshold" setting is stored in a global variable and populated via `git_default_core_config()`. This may cause issues in the case where one is handling multiple different repositories in a single process with different values for that config key, as we may or may not see the correct value in that case. Furthermore, global state blocks our path towards libification. Refactor the code so that we instead store the value in `struct repo_settings`, where the value is computed as-needed and cached. Note that this change requires us to adapt one test in t1050 that verifies that we die when parsing an invalid "core.bigFileThreshold" value. The exercised Git command doesn't use the value at all, and thus it won't hit the new code path that parses the value. This is addressed by using git-hash-object(1) instead, which does read the value. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 10, 2025 at 08:13 UTC 7835ee75cdffbce925246cbacc83e8b4a932a681
15 files changed +52 -22
archive.c
+1 -1
@@ -216,7 +216,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
216 /* Stream it? */
217 if (S_ISREG(mode) && !args->convert &&
218 oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
219 - size > big_file_threshold)
219 + size > repo_settings_get_big_file_threshold(the_repository))
220 return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
221
222 buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
builtin/fast-import.c
+2 -2
@@ -2021,7 +2021,7 @@ static void parse_and_store_blob(
2021 static struct strbuf buf = STRBUF_INIT;
2022 uintmax_t len;
2023
2024 - if (parse_data(&buf, big_file_threshold, &len))
2024 + if (parse_data(&buf, repo_settings_get_big_file_threshold(the_repository), &len))
2025 store_object(OBJ_BLOB, &buf, last, oidout, mark);
2026 else {
2027 if (last) {
@@ -3402,7 +3402,7 @@ static int parse_one_option(const char *option)
3402 unsigned long v;
3403 if (!git_parse_ulong(option, &v))
3404 return 0;
3405 - big_file_threshold = v;
3405 + repo_settings_set_big_file_threshold(the_repository, v);
3406 } else if (skip_prefix(option, "depth=", &option)) {
3407 option_depth(option);
3408 } else if (skip_prefix(option, "active-branches=", &option)) {
builtin/index-pack.c
+4 -2
@@ -485,7 +485,8 @@ static void *unpack_entry_data(off_t offset, unsigned long size,
485 git_hash_update(&c, hdr, hdrlen);
486 } else
487 oid = NULL;
488 - if (type == OBJ_BLOB && size > big_file_threshold)
488 + if (type == OBJ_BLOB &&
489 + size > repo_settings_get_big_file_threshold(the_repository))
490 buf = fixed_buf;
491 else
492 buf = xmallocz(size);
@@ -799,7 +800,8 @@ static int check_collison(struct object_entry *entry)
800 enum object_type type;
801 unsigned long size;
802
802 - if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB)
803 + if (entry->size <= repo_settings_get_big_file_threshold(the_repository) ||
804 + entry->type != OBJ_BLOB)
805 return -1;
806
807 memset(&data, 0, sizeof(data));
builtin/pack-objects.c
+4 -2
@@ -499,7 +499,8 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent
499
500 if (!usable_delta) {
501 if (oe_type(entry) == OBJ_BLOB &&
502 - oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
502 + oe_size_greater_than(&to_pack, entry,
503 + repo_settings_get_big_file_threshold(the_repository)) &&
504 (st = open_istream(the_repository, &entry->idx.oid, &type,
505 &size, NULL)) != NULL)
506 buf = NULL;
@@ -2454,7 +2455,8 @@ static void get_object_details(void)
2455 struct object_entry *entry = sorted_by_offset[i];
2456 check_object(entry, i);
2457 if (entry->type_valid &&
2457 - oe_size_greater_than(&to_pack, entry, big_file_threshold))
2458 + oe_size_greater_than(&to_pack, entry,
2459 + repo_settings_get_big_file_threshold(the_repository)))
2460 entry->no_try_delta = 1;
2461 display_progress(progress_state, i + 1);
2462 }
builtin/unpack-objects.c
+2 -1
@@ -553,7 +553,8 @@ static void unpack_one(unsigned nr)
553
554 switch (type) {
555 case OBJ_BLOB:
556 - if (!dry_run && size > big_file_threshold) {
556 + if (!dry_run &&
557 + size > repo_settings_get_big_file_threshold(the_repository)) {
558 stream_blob(size, nr);
559 return;
560 }
config.c
-5
@@ -1490,11 +1490,6 @@ static int git_default_core_config(const char *var, const char *value,
1490 return 0;
1491 }
1492
1493 - if (!strcmp(var, "core.bigfilethreshold")) {
1494 - big_file_threshold = git_config_ulong(var, value, ctx->kvi);
1495 - return 0;
1496 - }
1497 -
1493 if (!strcmp(var, "core.autocrlf")) {
1494 if (value && !strcasecmp(value, "input")) {
1495 auto_crlf = AUTO_CRLF_INPUT;
diff.c
+4 -2
@@ -4193,7 +4193,8 @@ int diff_populate_filespec(struct repository *r,
4193 * is probably fine.
4194 */
4195 if (check_binary &&
4196 - s->size > big_file_threshold && s->is_binary == -1) {
4196 + s->size > repo_settings_get_big_file_threshold(the_repository) &&
4197 + s->is_binary == -1) {
4198 s->is_binary = 1;
4199 return 0;
4200 }
@@ -4243,7 +4244,8 @@ object_read:
4244 if (size_only || check_binary) {
4245 if (size_only)
4246 return 0;
4246 - if (s->size > big_file_threshold && s->is_binary == -1) {
4247 + if (s->size > repo_settings_get_big_file_threshold(the_repository) &&
4248 + s->is_binary == -1) {
4249 s->is_binary = 1;
4250 return 0;
4251 }
environment.c
-1
@@ -49,7 +49,6 @@ int fsync_object_files = -1;
49 int use_fsync = -1;
50 enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
51 enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
52 -unsigned long big_file_threshold = 512 * 1024 * 1024;
52 char *editor_program;
53 char *askpass_program;
54 char *excludes_file;
environment.h
-1
@@ -154,7 +154,6 @@ extern int zlib_compression_level;
154 extern int pack_compression_level;
155 extern size_t packed_git_window_size;
156 extern size_t packed_git_limit;
157 -extern unsigned long big_file_threshold;
157 extern unsigned long pack_size_limit_cfg;
158 extern int max_allowed_tree_depth;
159
object-file.c
+4 -2
@@ -2803,7 +2803,8 @@ int index_fd(struct index_state *istate, struct object_id *oid,
2803 ret = index_stream_convert_blob(istate, oid, fd, path, flags);
2804 else if (!S_ISREG(st->st_mode))
2805 ret = index_pipe(istate, oid, fd, type, path, flags);
2806 - else if (st->st_size <= big_file_threshold || type != OBJ_BLOB ||
2806 + else if (st->st_size <= repo_settings_get_big_file_threshold(the_repository) ||
2807 + type != OBJ_BLOB ||
2808 (path && would_convert_to_git(istate, path)))
2809 ret = index_core(istate, oid, fd, xsize_t(st->st_size),
2810 type, path, flags);
@@ -3137,7 +3138,8 @@ int read_loose_object(const char *path,
3138 goto out;
3139 }
3140
3140 - if (*oi->typep == OBJ_BLOB && *size > big_file_threshold) {
3141 + if (*oi->typep == OBJ_BLOB &&
3142 + *size > repo_settings_get_big_file_threshold(the_repository)) {
3143 if (check_stream_oid(&stream, hdr, *size, path, expected_oid) < 0)
3144 goto out;
3145 } else {
pack-check.c
+2 -1
@@ -131,7 +131,8 @@ static int verify_packfile(struct repository *r,
131 type = unpack_object_header(p, w_curs, &curpos, &size);
132 unuse_pack(w_curs);
133
134 - if (type == OBJ_BLOB && big_file_threshold <= size) {
134 + if (type == OBJ_BLOB &&
135 + repo_settings_get_big_file_threshold(the_repository) <= size) {
136 /*
137 * Let stream_object_signature() check it with
138 * the streaming interface; no point slurping
repo-settings.c
+20
@@ -20,6 +20,13 @@ static void repo_cfg_int(struct repository *r, const char *key, int *dest,
20 *dest = def;
21 }
22
23 +static void repo_cfg_ulong(struct repository *r, const char *key, unsigned long *dest,
24 + unsigned long def)
25 +{
26 + if (repo_config_get_ulong(r, key, dest))
27 + *dest = def;
28 +}
29 +
30 void prepare_repo_settings(struct repository *r)
31 {
32 int experimental;
@@ -151,6 +158,19 @@ void repo_settings_clear(struct repository *r)
158 r->settings = empty;
159 }
160
161 +unsigned long repo_settings_get_big_file_threshold(struct repository *repo)
162 +{
163 + if (!repo->settings.big_file_threshold)
164 + repo_cfg_ulong(repo, "core.bigfilethreshold",
165 + &repo->settings.big_file_threshold, 512 * 1024 * 1024);
166 + return repo->settings.big_file_threshold;
167 +}
168 +
169 +void repo_settings_set_big_file_threshold(struct repository *repo, unsigned long value)
170 +{
171 + repo->settings.big_file_threshold = value;
172 +}
173 +
174 enum log_refs_config repo_settings_get_log_all_ref_updates(struct repository *repo)
175 {
176 const char *value;
repo-settings.h
+5
@@ -64,6 +64,7 @@ struct repo_settings {
64 size_t delta_base_cache_limit;
65 size_t packed_git_window_size;
66 size_t packed_git_limit;
67 + unsigned long big_file_threshold;
68
69 char *hooks_path;
70 };
@@ -88,6 +89,10 @@ int repo_settings_get_warn_ambiguous_refs(struct repository *repo);
89 /* Read the value for "core.hooksPath". */
90 const char *repo_settings_get_hooks_path(struct repository *repo);
91
92 +/* Read and set the value for "core.bigFileThreshold". */
93 +unsigned long repo_settings_get_big_file_threshold(struct repository *repo);
94 +void repo_settings_set_big_file_threshold(struct repository *repo, unsigned long value);
95 +
96 /* Read, set or reset the value for "core.sharedRepository". */
97 int repo_settings_get_shared_repository(struct repository *repo);
98 void repo_settings_set_shared_repository(struct repository *repo, int value);
streaming.c
+2 -1
@@ -431,7 +431,8 @@ static int istream_source(struct git_istream *st,
431 st->open = open_istream_loose;
432 return 0;
433 case OI_PACKED:
434 - if (!oi.u.packed.is_delta && big_file_threshold < size) {
434 + if (!oi.u.packed.is_delta &&
435 + repo_settings_get_big_file_threshold(the_repository) < size) {
436 st->u.in_pack.pack = oi.u.packed.pack;
437 st->u.in_pack.pos = oi.u.packed.offset;
438 st->open = open_istream_pack_non_delta;
t/t1050-large.sh
+2 -1
@@ -6,7 +6,8 @@ test_description='adding and checking out large blobs'
6 . ./test-lib.sh
7
8 test_expect_success 'core.bigFileThreshold must be non-negative' '
9 - test_must_fail git -c core.bigFileThreshold=-1 rev-parse >out 2>err &&
9 + : >input &&
10 + test_must_fail git -c core.bigFileThreshold=-1 hash-object input >out 2>err &&
11 grep "bad numeric config value" err &&
12 test_must_be_empty out
13 '