Skip to content

Commit d24a531

Browse files
committed
Merge pull request libgit2#2866 from ethomson/checkout_perf2
Checkout performance
2 parents 8e29ae7 + fa89ff2 commit d24a531

File tree

20 files changed

+379
-129
lines changed

20 files changed

+379
-129
lines changed

src/attr.c

Lines changed: 95 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ git_attr_t git_attr_value(const char *attr)
2929

3030
static int collect_attr_files(
3131
git_repository *repo,
32+
git_attr_session *attr_session,
3233
uint32_t flags,
3334
const char *path,
3435
git_vector *files);
@@ -57,7 +58,7 @@ int git_attr_get(
5758
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
5859
return -1;
5960

60-
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
61+
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0)
6162
goto cleanup;
6263

6364
memset(&attr, 0, sizeof(attr));
@@ -90,9 +91,10 @@ typedef struct {
9091
git_attr_assignment *found;
9192
} attr_get_many_info;
9293

93-
int git_attr_get_many(
94+
int git_attr_get_many_with_session(
9495
const char **values,
9596
git_repository *repo,
97+
git_attr_session *attr_session,
9698
uint32_t flags,
9799
const char *pathname,
98100
size_t num_attr,
@@ -115,7 +117,7 @@ int git_attr_get_many(
115117
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
116118
return -1;
117119

118-
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0)
120+
if ((error = collect_attr_files(repo, attr_session, flags, pathname, &files)) < 0)
119121
goto cleanup;
120122

121123
info = git__calloc(num_attr, sizeof(attr_get_many_info));
@@ -161,6 +163,17 @@ int git_attr_get_many(
161163
return error;
162164
}
163165

166+
int git_attr_get_many(
167+
const char **values,
168+
git_repository *repo,
169+
uint32_t flags,
170+
const char *pathname,
171+
size_t num_attr,
172+
const char **names)
173+
{
174+
return git_attr_get_many_with_session(
175+
values, repo, NULL, flags, pathname, num_attr, names);
176+
}
164177

165178
int git_attr_foreach(
166179
git_repository *repo,
@@ -183,7 +196,7 @@ int git_attr_foreach(
183196
if (git_attr_path__init(&path, pathname, git_repository_workdir(repo)) < 0)
184197
return -1;
185198

186-
if ((error = collect_attr_files(repo, flags, pathname, &files)) < 0 ||
199+
if ((error = collect_attr_files(repo, NULL, flags, pathname, &files)) < 0 ||
187200
(error = git_strmap_alloc(&seen)) < 0)
188201
goto cleanup;
189202

@@ -219,6 +232,7 @@ int git_attr_foreach(
219232

220233
static int preload_attr_file(
221234
git_repository *repo,
235+
git_attr_session *attr_session,
222236
git_attr_file_source source,
223237
const char *base,
224238
const char *file)
@@ -229,59 +243,101 @@ static int preload_attr_file(
229243
if (!file)
230244
return 0;
231245
if (!(error = git_attr_cache__get(
232-
&preload, repo, source, base, file, git_attr_file__parse_buffer)))
246+
&preload, repo, attr_session, source, base, file, git_attr_file__parse_buffer)))
233247
git_attr_file__free(preload);
234248

235249
return error;
236250
}
237251

238-
static int attr_setup(git_repository *repo)
252+
static int system_attr_file(
253+
git_buf *out,
254+
git_attr_session *attr_session)
255+
{
256+
int error;
257+
258+
if (!attr_session) {
259+
error = git_sysdir_find_system_file(out, GIT_ATTR_FILE_SYSTEM);
260+
261+
if (error == GIT_ENOTFOUND)
262+
giterr_clear();
263+
264+
return error;
265+
}
266+
267+
if (!attr_session->init_sysdir) {
268+
error = git_sysdir_find_system_file(&attr_session->sysdir, GIT_ATTR_FILE_SYSTEM);
269+
270+
if (error == GIT_ENOTFOUND)
271+
giterr_clear();
272+
else if (error)
273+
return error;
274+
275+
attr_session->init_sysdir = 1;
276+
}
277+
278+
if (attr_session->sysdir.size == 0)
279+
return GIT_ENOTFOUND;
280+
281+
/* We can safely provide a git_buf with no allocation (asize == 0) to
282+
* a consumer. This allows them to treat this as a regular `git_buf`,
283+
* but their call to `git_buf_free` will not attempt to free it.
284+
*/
285+
out->ptr = attr_session->sysdir.ptr;
286+
out->size = attr_session->sysdir.size;
287+
out->asize = 0;
288+
return 0;
289+
}
290+
291+
static int attr_setup(git_repository *repo, git_attr_session *attr_session)
239292
{
240293
int error = 0;
241294
const char *workdir = git_repository_workdir(repo);
242295
git_index *idx = NULL;
243296
git_buf sys = GIT_BUF_INIT;
244297

298+
if (attr_session && attr_session->init_setup)
299+
return 0;
300+
245301
if ((error = git_attr_cache__init(repo)) < 0)
246302
return error;
247303

248304
/* preload attribute files that could contain macros so the
249305
* definitions will be available for later file parsing
250306
*/
251307

252-
if (!(error = git_sysdir_find_system_file(&sys, GIT_ATTR_FILE_SYSTEM))) {
308+
error = system_attr_file(&sys, attr_session);
309+
310+
if (error == 0)
253311
error = preload_attr_file(
254-
repo, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
255-
git_buf_free(&sys);
256-
}
257-
if (error < 0) {
258-
if (error == GIT_ENOTFOUND) {
259-
giterr_clear();
260-
error = 0;
261-
} else
262-
return error;
263-
}
312+
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, NULL, sys.ptr);
313+
else if (error != GIT_ENOTFOUND)
314+
return error;
315+
316+
git_buf_free(&sys);
264317

265318
if ((error = preload_attr_file(
266-
repo, GIT_ATTR_FILE__FROM_FILE,
319+
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
267320
NULL, git_repository_attr_cache(repo)->cfg_attr_file)) < 0)
268321
return error;
269322

270323
if ((error = preload_attr_file(
271-
repo, GIT_ATTR_FILE__FROM_FILE,
324+
repo, attr_session, GIT_ATTR_FILE__FROM_FILE,
272325
git_repository_path(repo), GIT_ATTR_FILE_INREPO)) < 0)
273326
return error;
274327

275328
if (workdir != NULL &&
276329
(error = preload_attr_file(
277-
repo, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
330+
repo, attr_session, GIT_ATTR_FILE__FROM_FILE, workdir, GIT_ATTR_FILE)) < 0)
278331
return error;
279332

280333
if ((error = git_repository_index__weakptr(&idx, repo)) < 0 ||
281334
(error = preload_attr_file(
282-
repo, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
335+
repo, attr_session, GIT_ATTR_FILE__FROM_INDEX, NULL, GIT_ATTR_FILE)) < 0)
283336
return error;
284337

338+
if (attr_session)
339+
attr_session->init_setup = 1;
340+
285341
return error;
286342
}
287343

@@ -321,6 +377,7 @@ int git_attr_add_macro(
321377

322378
typedef struct {
323379
git_repository *repo;
380+
git_attr_session *attr_session;
324381
uint32_t flags;
325382
const char *workdir;
326383
git_index *index;
@@ -356,6 +413,7 @@ static int attr_decide_sources(
356413

357414
static int push_attr_file(
358415
git_repository *repo,
416+
git_attr_session *attr_session,
359417
git_vector *list,
360418
git_attr_file_source source,
361419
const char *base,
@@ -364,8 +422,9 @@ static int push_attr_file(
364422
int error = 0;
365423
git_attr_file *file = NULL;
366424

367-
error = git_attr_cache__get(
368-
&file, repo, source, base, filename, git_attr_file__parse_buffer);
425+
error = git_attr_cache__get(&file, repo, attr_session,
426+
source, base, filename, git_attr_file__parse_buffer);
427+
369428
if (error < 0)
370429
return error;
371430

@@ -387,8 +446,8 @@ static int push_one_attr(void *ref, const char *path)
387446
info->flags, info->workdir != NULL, info->index != NULL, src);
388447

389448
for (i = 0; !error && i < n_src; ++i)
390-
error = push_attr_file(
391-
info->repo, info->files, src[i], path, GIT_ATTR_FILE);
449+
error = push_attr_file(info->repo, info->attr_session,
450+
info->files, src[i], path, GIT_ATTR_FILE);
392451

393452
return error;
394453
}
@@ -407,6 +466,7 @@ static void release_attr_files(git_vector *files)
407466

408467
static int collect_attr_files(
409468
git_repository *repo,
469+
git_attr_session *attr_session,
410470
uint32_t flags,
411471
const char *path,
412472
git_vector *files)
@@ -416,7 +476,7 @@ static int collect_attr_files(
416476
const char *workdir = git_repository_workdir(repo);
417477
attr_walk_up_info info = { NULL };
418478

419-
if ((error = attr_setup(repo)) < 0)
479+
if ((error = attr_setup(repo, attr_session)) < 0)
420480
return error;
421481

422482
/* Resolve path in a non-bare repo */
@@ -435,12 +495,13 @@ static int collect_attr_files(
435495
*/
436496

437497
error = push_attr_file(
438-
repo, files, GIT_ATTR_FILE__FROM_FILE,
498+
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
439499
git_repository_path(repo), GIT_ATTR_FILE_INREPO);
440500
if (error < 0)
441501
goto cleanup;
442502

443-
info.repo = repo;
503+
info.repo = repo;
504+
info.attr_session = attr_session;
444505
info.flags = flags;
445506
info.workdir = workdir;
446507
if (git_repository_index__weakptr(&info.index, repo) < 0)
@@ -457,21 +518,21 @@ static int collect_attr_files(
457518

458519
if (git_repository_attr_cache(repo)->cfg_attr_file != NULL) {
459520
error = push_attr_file(
460-
repo, files, GIT_ATTR_FILE__FROM_FILE,
521+
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
461522
NULL, git_repository_attr_cache(repo)->cfg_attr_file);
462523
if (error < 0)
463524
goto cleanup;
464525
}
465526

466527
if ((flags & GIT_ATTR_CHECK_NO_SYSTEM) == 0) {
467-
error = git_sysdir_find_system_file(&dir, GIT_ATTR_FILE_SYSTEM);
528+
error = system_attr_file(&dir, attr_session);
529+
468530
if (!error)
469531
error = push_attr_file(
470-
repo, files, GIT_ATTR_FILE__FROM_FILE, NULL, dir.ptr);
471-
else if (error == GIT_ENOTFOUND) {
472-
giterr_clear();
532+
repo, attr_session, files, GIT_ATTR_FILE__FROM_FILE,
533+
NULL, dir.ptr);
534+
else if (error == GIT_ENOTFOUND)
473535
error = 0;
474-
}
475536
}
476537

477538
cleanup:

0 commit comments

Comments
 (0)