Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 651afd0

Browse files
ethomsonEdward Thomson
authored and
Edward Thomson
committed
checkout: introduce git_checkout_perfdata
Checkout can now provide performance data about the number of (some) syscalls performed using an optional callback. This structure remains internal-only in maintenance branches.
1 parent 91fa31f commit 651afd0

File tree

5 files changed

+135
-50
lines changed

5 files changed

+135
-50
lines changed

src/checkout.c

Lines changed: 74 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ typedef struct {
6565
bool reload_submodules;
6666
size_t total_steps;
6767
size_t completed_steps;
68+
git_checkout_perfdata perfdata;
6869
} checkout_data;
6970

7071
typedef struct {
@@ -1218,50 +1219,86 @@ static int checkout_get_actions(
12181219
return error;
12191220
}
12201221

1222+
static int checkout_mkdir(
1223+
checkout_data *data,
1224+
const char *path,
1225+
const char *base,
1226+
mode_t mode,
1227+
unsigned int flags)
1228+
{
1229+
struct git_futils_mkdir_perfdata mkdir_perfdata = {0};
1230+
1231+
int error = git_futils_mkdir_withperf(
1232+
path, base, mode, flags, &mkdir_perfdata);
1233+
1234+
data->perfdata.mkdir_calls += mkdir_perfdata.mkdir_calls;
1235+
data->perfdata.stat_calls += mkdir_perfdata.stat_calls;
1236+
data->perfdata.chmod_calls += mkdir_perfdata.chmod_calls;
1237+
1238+
return error;
1239+
}
1240+
1241+
static int mkpath2file(
1242+
checkout_data *data, const char *path, unsigned int mode)
1243+
{
1244+
return checkout_mkdir(
1245+
data, path, git_repository_workdir(data->repo), mode,
1246+
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
1247+
}
1248+
12211249
static int buffer_to_file(
1250+
checkout_data *data,
12221251
struct stat *st,
12231252
git_buf *buf,
12241253
const char *path,
1225-
mode_t dir_mode,
1226-
int file_open_flags,
12271254
mode_t file_mode)
12281255
{
12291256
int error;
12301257

1231-
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
1258+
if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
12321259
return error;
12331260

12341261
if ((error = git_futils_writebuffer(
1235-
buf, path, file_open_flags, file_mode)) < 0)
1262+
buf, path, data->opts.file_open_flags, file_mode)) < 0)
12361263
return error;
12371264

1238-
if (st != NULL && (error = p_stat(path, st)) < 0)
1239-
giterr_set(GITERR_OS, "Error statting '%s'", path);
1265+
if (st) {
1266+
data->perfdata.stat_calls++;
1267+
1268+
if ((error = p_stat(path, st)) < 0) {
1269+
giterr_set(GITERR_OS, "Error statting '%s'", path);
1270+
return error;
1271+
}
1272+
}
12401273

1241-
else if (GIT_PERMS_IS_EXEC(file_mode) &&
1242-
(error = p_chmod(path, file_mode)) < 0)
1243-
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
1274+
if (GIT_PERMS_IS_EXEC(file_mode)) {
1275+
data->perfdata.chmod_calls++;
1276+
1277+
if ((error = p_chmod(path, file_mode)) < 0)
1278+
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
1279+
}
12441280

12451281
return error;
12461282
}
12471283

12481284
static int blob_content_to_file(
1285+
checkout_data *data,
12491286
struct stat *st,
12501287
git_blob *blob,
12511288
const char *path,
12521289
const char * hint_path,
1253-
mode_t entry_filemode,
1254-
git_checkout_options *opts)
1290+
mode_t entry_filemode)
12551291
{
1256-
int error = 0;
1257-
mode_t file_mode = opts->file_mode ? opts->file_mode : entry_filemode;
1292+
mode_t file_mode = data->opts.file_mode ?
1293+
data->opts.file_mode : entry_filemode;
12581294
git_buf out = GIT_BUF_INIT;
12591295
git_filter_list *fl = NULL;
1296+
int error = 0;
12601297

12611298
if (hint_path == NULL)
12621299
hint_path = path;
12631300

1264-
if (!opts->disable_filters)
1301+
if (!data->opts.disable_filters)
12651302
error = git_filter_list_load(
12661303
&fl, git_blob_owner(blob), blob, hint_path,
12671304
GIT_FILTER_TO_WORKTREE, GIT_FILTER_OPT_DEFAULT);
@@ -1272,9 +1309,7 @@ static int blob_content_to_file(
12721309
git_filter_list_free(fl);
12731310

12741311
if (!error) {
1275-
error = buffer_to_file(
1276-
st, &out, path, opts->dir_mode, opts->file_open_flags, file_mode);
1277-
1312+
error = buffer_to_file(data, st, &out, path, file_mode);
12781313
st->st_mode = entry_filemode;
12791314

12801315
git_buf_free(&out);
@@ -1284,29 +1319,30 @@ static int blob_content_to_file(
12841319
}
12851320

12861321
static int blob_content_to_link(
1322+
checkout_data *data,
12871323
struct stat *st,
12881324
git_blob *blob,
1289-
const char *path,
1290-
mode_t dir_mode,
1291-
int can_symlink)
1325+
const char *path)
12921326
{
12931327
git_buf linktarget = GIT_BUF_INIT;
12941328
int error;
12951329

1296-
if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
1330+
if ((error = mkpath2file(data, path, data->opts.dir_mode)) < 0)
12971331
return error;
12981332

12991333
if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
13001334
return error;
13011335

1302-
if (can_symlink) {
1336+
if (data->can_symlink) {
13031337
if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
13041338
giterr_set(GITERR_OS, "Could not create symlink %s\n", path);
13051339
} else {
13061340
error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
13071341
}
13081342

13091343
if (!error) {
1344+
data->perfdata.stat_calls++;
1345+
13101346
if ((error = p_lstat(path, st)) < 0)
13111347
giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
13121348

@@ -1350,6 +1386,7 @@ static int checkout_submodule_update_index(
13501386
if (git_buf_puts(&data->path, file->path) < 0)
13511387
return -1;
13521388

1389+
data->perfdata.stat_calls++;
13531390
if (p_stat(git_buf_cstr(&data->path), &st) < 0) {
13541391
giterr_set(
13551392
GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
@@ -1371,7 +1408,8 @@ static int checkout_submodule(
13711408
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
13721409
return 0;
13731410

1374-
if ((error = git_futils_mkdir(
1411+
if ((error = checkout_mkdir(
1412+
data,
13751413
file->path, data->opts.target_directory,
13761414
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
13771415
return error;
@@ -1410,10 +1448,13 @@ static void report_progress(
14101448
data->opts.progress_payload);
14111449
}
14121450

1413-
static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
1451+
static int checkout_safe_for_update_only(
1452+
checkout_data *data, const char *path, mode_t expected_mode)
14141453
{
14151454
struct stat st;
14161455

1456+
data->perfdata.stat_calls++;
1457+
14171458
if (p_lstat(path, &st) < 0) {
14181459
/* if doesn't exist, then no error and no update */
14191460
if (errno == ENOENT || errno == ENOTDIR)
@@ -1446,11 +1487,9 @@ static int checkout_write_content(
14461487
return error;
14471488

14481489
if (S_ISLNK(mode))
1449-
error = blob_content_to_link(
1450-
st, blob, full_path, data->opts.dir_mode, data->can_symlink);
1490+
error = blob_content_to_link(data, st, blob, full_path);
14511491
else
1452-
error = blob_content_to_file(
1453-
st, blob, full_path, hint_path, mode, &data->opts);
1492+
error = blob_content_to_file(data, st, blob, full_path, hint_path, mode);
14541493

14551494
git_blob_free(blob);
14561495

@@ -1481,7 +1520,7 @@ static int checkout_blob(
14811520

14821521
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
14831522
int rval = checkout_safe_for_update_only(
1484-
git_buf_cstr(&data->path), file->mode);
1523+
data, git_buf_cstr(&data->path), file->mode);
14851524
if (rval <= 0)
14861525
return rval;
14871526
}
@@ -1736,7 +1775,7 @@ static int checkout_write_entry(
17361775
}
17371776

17381777
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
1739-
(error = checkout_safe_for_update_only(git_buf_cstr(&data->path), side->mode)) <= 0)
1778+
(error = checkout_safe_for_update_only(data, git_buf_cstr(&data->path), side->mode)) <= 0)
17401779
return error;
17411780

17421781
return checkout_write_content(data,
@@ -1835,7 +1874,7 @@ static int checkout_write_merge(
18351874
goto done;
18361875

18371876
if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
1838-
(error = checkout_safe_for_update_only(git_buf_cstr(&path_workdir), result.mode)) <= 0)
1877+
(error = checkout_safe_for_update_only(data, git_buf_cstr(&path_workdir), result.mode)) <= 0)
18391878
goto done;
18401879

18411880
if (!data->opts.disable_filters) {
@@ -1851,7 +1890,7 @@ static int checkout_write_merge(
18511890
out_data.size = result.len;
18521891
}
18531892

1854-
if ((error = git_futils_mkpath2file(path_workdir.ptr, 0755)) < 0 ||
1893+
if ((error = mkpath2file(data, path_workdir.ptr, data->opts.dir_mode)) < 0 ||
18551894
(error = git_filebuf_open(&output, git_buf_cstr(&path_workdir), GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
18561895
(error = git_filebuf_write(&output, out_data.ptr, out_data.size)) < 0 ||
18571896
(error = git_filebuf_commit(&output)) < 0)
@@ -2056,8 +2095,9 @@ static int checkout_data_init(
20562095
if (!data->opts.target_directory)
20572096
data->opts.target_directory = git_repository_workdir(repo);
20582097
else if (!git_path_isdir(data->opts.target_directory) &&
2059-
(error = git_futils_mkdir(data->opts.target_directory, NULL,
2060-
GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
2098+
(error = checkout_mkdir(data,
2099+
data->opts.target_directory, NULL,
2100+
GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
20612101
goto cleanup;
20622102

20632103
/* refresh config and index content unless NO_REFRESH is given */

src/checkout.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@
1212

1313
#define GIT_CHECKOUT__NOTIFY_CONFLICT_TREE (1u << 12)
1414

15+
/** Internal structure; this is exposed in future versions. */
16+
typedef struct {
17+
size_t mkdir_calls;
18+
size_t stat_calls;
19+
size_t chmod_calls;
20+
} git_checkout_perfdata;
21+
1522
/**
1623
* Update the working directory to match the target iterator. The
1724
* expected baseline value can be passed in via the checkout options

src/fileops.c

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,12 @@ void git_futils_mmap_free(git_map *out)
279279
p_munmap(out);
280280
}
281281

282-
int git_futils_mkdir(
282+
int git_futils_mkdir_withperf(
283283
const char *path,
284284
const char *base,
285285
mode_t mode,
286-
uint32_t flags)
286+
uint32_t flags,
287+
struct git_futils_mkdir_perfdata *perfdata)
287288
{
288289
int error = -1;
289290
git_buf make_path = GIT_BUF_INIT;
@@ -352,15 +353,20 @@ int git_futils_mkdir(
352353
st.st_mode = 0;
353354

354355
/* make directory */
356+
perfdata->mkdir_calls++;
357+
355358
if (p_mkdir(make_path.ptr, mode) < 0) {
356359
int tmp_errno = giterr_system_last();
357360

358361
/* ignore error if not at end or if directory already exists */
359-
if (lastch == '\0' &&
360-
(p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) {
361-
giterr_system_set(tmp_errno);
362-
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
363-
goto done;
362+
if (lastch == '\0') {
363+
perfdata->stat_calls++;
364+
365+
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
366+
giterr_system_set(tmp_errno);
367+
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr);
368+
goto done;
369+
}
364370
}
365371

366372
/* with exclusive create, existing dir is an error */
@@ -374,29 +380,46 @@ int git_futils_mkdir(
374380
/* chmod if requested and necessary */
375381
if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 ||
376382
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) &&
377-
st.st_mode != mode &&
378-
(error = p_chmod(make_path.ptr, mode)) < 0 &&
379-
lastch == '\0') {
380-
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr);
381-
goto done;
383+
st.st_mode != mode) {
384+
385+
perfdata->chmod_calls++;
386+
387+
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
388+
lastch == '\0') {
389+
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr);
390+
goto done;
391+
}
382392
}
383393
}
384394

385395
error = 0;
386396

387397
/* check that full path really is a directory if requested & needed */
388398
if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 &&
389-
lastch != '\0' &&
390-
(p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) {
391-
giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr);
392-
error = GIT_ENOTFOUND;
399+
lastch != '\0') {
400+
perfdata->stat_calls++;
401+
402+
if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) {
403+
giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr);
404+
error = GIT_ENOTFOUND;
405+
}
393406
}
394407

395408
done:
396409
git_buf_free(&make_path);
397410
return error;
398411
}
399412

413+
int git_futils_mkdir(
414+
const char *path,
415+
const char *base,
416+
mode_t mode,
417+
uint32_t flags)
418+
{
419+
struct git_futils_mkdir_perfdata perfdata = {0};
420+
return git_futils_mkdir_withperf(path, base, mode, flags, &perfdata);
421+
}
422+
400423
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
401424
{
402425
return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);

src/fileops.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ typedef enum {
8484
GIT_MKDIR_VERIFY_DIR = 64,
8585
} git_futils_mkdir_flags;
8686

87+
struct git_futils_mkdir_perfdata
88+
{
89+
size_t stat_calls;
90+
size_t mkdir_calls;
91+
size_t chmod_calls;
92+
};
93+
8794
/**
8895
* Create a directory or entire path.
8996
*
@@ -95,8 +102,15 @@ typedef enum {
95102
* @param base Root for relative path. These directories will never be made.
96103
* @param mode The mode to use for created directories.
97104
* @param flags Combination of the mkdir flags above.
105+
* @param perfdata Performance data, use `git_futils_mkdir` if you don't want this data.
98106
* @return 0 on success, else error code
99107
*/
108+
extern int git_futils_mkdir_withperf(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata);
109+
110+
/**
111+
* Create a directory or entire path. Similar to `git_futils_mkdir_withperf`
112+
* without performance data.
113+
*/
100114
extern int git_futils_mkdir(const char *path, const char *base, mode_t mode, uint32_t flags);
101115

102116
/**

tests/checkout/tree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,3 +948,4 @@ void test_checkout_tree__filemode_preserved_in_index(void)
948948
git_commit_free(commit);
949949
git_index_free(index);
950950
}
951+

0 commit comments

Comments
 (0)