Skip to content

Commit dc2a957

Browse files
jeffhostetlerdscho
authored andcommitted
gvfs:trace2:data: status deserialization information
Add trace2 region and data events describing attempts to deserialize status data using a status cache. A category:status, label:deserialize region is pushed around the deserialize code. Deserialization results when reading from a file are: category:status, path = <path> category:status, polled = <number_of_attempts> category:status, result = "ok" | "reject" When reading from STDIN are: category:status, path = "STDIN" category:status, result = "ok" | "reject" Status will fallback and run a normal status scan when a "reject" is reported (unless "--deserialize-wait=fail"). If "ok" is reported, status was able to use the status cache and avoid scanning the workdir. Additionally, a cmd_mode is emitted for each step: collection, deserialization, and serialization. For example, if deserialization is attempted and fails and status falls back to actually computing the status, a cmd_mode message containing "deserialize" is issued and then a cmd_mode for "collect" is issued. Also, if deserialization fails, a data message containing the rejection reason is emitted. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
1 parent fdee097 commit dc2a957

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

builtin/commit.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ static int opt_parse_porcelain(const struct option *opt, const char *arg, int un
179179
static int do_serialize = 0;
180180
static char *serialize_path = NULL;
181181

182+
static int reject_implicit = 0;
182183
static int do_implicit_deserialize = 0;
183184
static int do_explicit_deserialize = 0;
184185
static char *deserialize_path = NULL;
@@ -242,7 +243,7 @@ static int opt_parse_deserialize(const struct option *opt, const char *arg, int
242243
}
243244
if (!deserialize_path || !*deserialize_path)
244245
do_explicit_deserialize = 1; /* read stdin */
245-
else if (access(deserialize_path, R_OK) == 0)
246+
else if (wt_status_deserialize_access(deserialize_path, R_OK) == 0)
246247
do_explicit_deserialize = 1; /* can read from this file */
247248
else {
248249
/*
@@ -1591,6 +1592,8 @@ static int git_status_config(const char *k, const char *v,
15911592
if (v && *v && access(v, R_OK) == 0) {
15921593
do_implicit_deserialize = 1;
15931594
deserialize_path = xstrdup(v);
1595+
} else {
1596+
reject_implicit = 1;
15941597
}
15951598
return 0;
15961599
}
@@ -1745,6 +1748,17 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17451748

17461749
if (try_deserialize)
17471750
goto skip_init;
1751+
/*
1752+
* If we implicitly received a status cache pathname from the config
1753+
* and the file does not exist, we silently reject it and do the normal
1754+
* status "collect". Fake up some trace2 messages to reflect this and
1755+
* assist post-processors know this case is different.
1756+
*/
1757+
if (!do_serialize && reject_implicit) {
1758+
trace2_cmd_mode("implicit-deserialize");
1759+
trace2_data_string("status", the_repository, "deserialize/reject",
1760+
"status-cache/access");
1761+
}
17481762

17491763
enable_fscache(0);
17501764
if (status_format != STATUS_FORMAT_PORCELAIN &&
@@ -1788,6 +1802,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17881802
if (s.relative_paths)
17891803
s.prefix = prefix;
17901804

1805+
trace2_cmd_mode("deserialize");
17911806
result = wt_status_deserialize(&s, deserialize_path, dw);
17921807
if (result == DESERIALIZE_OK)
17931808
return 0;
@@ -1805,6 +1820,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
18051820
fd = -1;
18061821
}
18071822

1823+
trace2_cmd_mode("collect");
18081824
wt_status_collect(&s);
18091825

18101826
if (0 <= fd)
@@ -1819,6 +1835,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
18191835
if (fd_serialize < 0)
18201836
die_errno(_("could not serialize to '%s'"),
18211837
serialize_path);
1838+
trace2_cmd_mode("serialize");
18221839
wt_status_serialize_v1(fd_serialize, &s);
18231840
close(fd_serialize);
18241841
}

wt-status-deserialize.c

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@
77
#include "trace.h"
88
#include "statinfo.h"
99
#include "path.h"
10+
#include "trace2.h"
11+
12+
static void set_deserialize_reject_reason(const char *reason)
13+
{
14+
trace2_data_string("status", the_repository, "deserialize/reject",
15+
reason);
16+
}
17+
18+
int wt_status_deserialize_access(const char *path, int mode)
19+
{
20+
int a = access(path, mode);
21+
22+
if (a != 0)
23+
set_deserialize_reject_reason("status-cache/access");
24+
25+
return a;
26+
}
1027

1128
static struct trace_key trace_deserialize = TRACE_KEY_INIT(DESERIALIZE);
1229

@@ -54,13 +71,15 @@ static int my_validate_index(const struct cache_time *mtime_reported)
5471
struct cache_time mtime_observed_on_disk;
5572

5673
if (lstat(path, &st)) {
74+
set_deserialize_reject_reason("index/not-found");
5775
trace_printf_key(&trace_deserialize, "could not stat index");
5876
return DESERIALIZE_ERR;
5977
}
6078
mtime_observed_on_disk.sec = st.st_mtime;
6179
mtime_observed_on_disk.nsec = ST_MTIME_NSEC(st);
6280
if ((mtime_observed_on_disk.sec != mtime_reported->sec) ||
6381
(mtime_observed_on_disk.nsec != mtime_reported->nsec)) {
82+
set_deserialize_reject_reason("index/mtime-changed");
6483
trace_printf_key(&trace_deserialize,
6584
"index mtime changed [des %d %d][obs %d %d]",
6685
mtime_reported->sec, mtime_reported->nsec,
@@ -86,10 +105,12 @@ static int my_validate_excludes(const char *path, const char *key, const char *l
86105

87106
r = (strcmp(line, sb.buf) ? DESERIALIZE_ERR : DESERIALIZE_OK);
88107

89-
if (r == DESERIALIZE_ERR)
108+
if (r == DESERIALIZE_ERR) {
109+
set_deserialize_reject_reason("excludes/changed");
90110
trace_printf_key(&trace_deserialize,
91111
"%s changed [cached '%s'][observed '%s']",
92112
key, line, sb.buf);
113+
}
93114

94115
strbuf_release(&sb);
95116
return r;
@@ -145,6 +166,7 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
145166
&index_mtime.sec,
146167
&index_mtime.nsec);
147168
if (nr_fields != 2) {
169+
set_deserialize_reject_reason("v1-header/invalid-index-mtime");
148170
trace_printf_key(&trace_deserialize, "invalid index_mtime (%d) '%s'",
149171
nr_fields, line);
150172
return DESERIALIZE_ERR;
@@ -228,6 +250,7 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
228250
/* status_format */
229251
if (skip_prefix(line, "sha1_commit ", &arg)) {
230252
if (get_oid_hex(arg, &s->oid_commit)) {
253+
set_deserialize_reject_reason("v1-header/invalid-commit-sha");
231254
trace_printf_key(&trace_deserialize, "invalid sha1_commit");
232255
return DESERIALIZE_ERR;
233256
}
@@ -243,19 +266,23 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
243266
}
244267
/* prefix */
245268

269+
set_deserialize_reject_reason("v1-header/unexpected-line");
246270
trace_printf_key(&trace_deserialize, "unexpected line '%s'", line);
247271
return DESERIALIZE_ERR;
248272
}
249273

250274
if (!have_required_index_mtime) {
275+
set_deserialize_reject_reason("v1-header/missing-index-mtime");
251276
trace_printf_key(&trace_deserialize, "missing '%s'", "index_mtime");
252277
return DESERIALIZE_ERR;
253278
}
254279
if (!have_required_core_excludes) {
280+
set_deserialize_reject_reason("v1-header/missing-core-excludes");
255281
trace_printf_key(&trace_deserialize, "missing '%s'", "core_excludes");
256282
return DESERIALIZE_ERR;
257283
}
258284
if (!have_required_repo_excludes) {
285+
set_deserialize_reject_reason("v1-header/missing-repo-excludes");
259286
trace_printf_key(&trace_deserialize, "missing '%s'", "repo_excludes");
260287
return DESERIALIZE_ERR;
261288
}
@@ -342,6 +369,7 @@ static int wt_deserialize_v1_changed_items(const struct wt_status *cmd_s,
342369
* So we reject the status cache and let the fallback
343370
* code run.
344371
*/
372+
set_deserialize_reject_reason("v1-data/unmerged");
345373
trace_printf_key(
346374
&trace_deserialize,
347375
"reject: V2 format and umerged file: %s",
@@ -483,13 +511,15 @@ static int wt_deserialize_v1(const struct wt_status *cmd_s, struct wt_status *s,
483511
* the serialized data
484512
*/
485513
if (validate_untracked_files_arg(cmd_s->show_untracked_files, &s->show_untracked_files, &untracked_strategy)) {
514+
set_deserialize_reject_reason("args/untracked-files");
486515
trace_printf_key(&trace_deserialize, "reject: show_untracked_file: command: %d, serialized : %d",
487516
cmd_s->show_untracked_files,
488517
s->show_untracked_files);
489518
return DESERIALIZE_ERR;
490519
}
491520

492521
if (validate_ignored_files_arg(cmd_s->show_ignored_mode, s->show_ignored_mode, &ignored_strategy)) {
522+
set_deserialize_reject_reason("args/ignored-mode");
493523
trace_printf_key(&trace_deserialize, "reject: show_ignored_mode: command: %d, serialized: %d",
494524
cmd_s->show_ignored_mode,
495525
s->show_ignored_mode);
@@ -523,6 +553,7 @@ static int wt_deserialize_v1(const struct wt_status *cmd_s, struct wt_status *s,
523553
return DESERIALIZE_ERR;
524554
continue;
525555
}
556+
set_deserialize_reject_reason("v1-data/unexpected-line");
526557
trace_printf_key(&trace_deserialize, "unexpected line '%s'", line);
527558
return DESERIALIZE_ERR;
528559
}
@@ -544,6 +575,7 @@ static int wt_deserialize_parse(const struct wt_status *cmd_s, struct wt_status
544575
if (version == 1)
545576
return wt_deserialize_v1(cmd_s, s, fd);
546577
}
578+
set_deserialize_reject_reason("status-cache/unsupported-version");
547579
trace_printf_key(&trace_deserialize, "missing/unsupported version");
548580
return DESERIALIZE_ERR;
549581
}
@@ -564,6 +596,7 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
564596
* Check the path spec on the current command
565597
*/
566598
if (cmd_s->pathspec.nr > 1) {
599+
set_deserialize_reject_reason("args/multiple-pathspecs");
567600
trace_printf_key(&trace_deserialize, "reject: multiple pathspecs");
568601
return DESERIALIZE_ERR;
569602
}
@@ -574,6 +607,7 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
574607
*/
575608
if (cmd_s->pathspec.nr == 1 &&
576609
my_strcmp_null(cmd_s->pathspec.items[0].match, "")) {
610+
set_deserialize_reject_reason("args/root-pathspec");
577611
trace_printf_key(&trace_deserialize, "reject: pathspec");
578612
return DESERIALIZE_ERR;
579613
}
@@ -590,20 +624,24 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
590624
* or "--ignored" settings).
591625
*/
592626
if (cmd_s->is_initial != des_s->is_initial) {
627+
set_deserialize_reject_reason("args/is-initial-changed");
593628
trace_printf_key(&trace_deserialize, "reject: is_initial");
594629
return DESERIALIZE_ERR;
595630
}
596631
if (my_strcmp_null(cmd_s->branch, des_s->branch)) {
632+
set_deserialize_reject_reason("args/branch-changed");
597633
trace_printf_key(&trace_deserialize, "reject: branch");
598634
return DESERIALIZE_ERR;
599635
}
600636
if (my_strcmp_null(cmd_s->reference, des_s->reference)) {
637+
set_deserialize_reject_reason("args/reference-changed");
601638
trace_printf_key(&trace_deserialize, "reject: reference");
602639
return DESERIALIZE_ERR;
603640
}
604641
/* verbose */
605642
/* amend */
606643
if (cmd_s->whence != des_s->whence) {
644+
set_deserialize_reject_reason("args/whence-changed");
607645
trace_printf_key(&trace_deserialize, "reject: whence");
608646
return DESERIALIZE_ERR;
609647
}
@@ -637,19 +675,23 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
637675
/* hints */
638676
/* ahead_behind_flags */
639677
if (cmd_s->detect_rename != des_s->detect_rename) {
678+
set_deserialize_reject_reason("args/detect-rename-changed");
640679
trace_printf_key(&trace_deserialize, "reject: detect_rename");
641680
return DESERIALIZE_ERR;
642681
}
643682
if (cmd_s->rename_score != des_s->rename_score) {
683+
set_deserialize_reject_reason("args/rename-score-changed");
644684
trace_printf_key(&trace_deserialize, "reject: rename_score");
645685
return DESERIALIZE_ERR;
646686
}
647687
if (cmd_s->rename_limit != des_s->rename_limit) {
688+
set_deserialize_reject_reason("args/rename-limit-changed");
648689
trace_printf_key(&trace_deserialize, "reject: rename_limit");
649690
return DESERIALIZE_ERR;
650691
}
651692
/* status_format */
652693
if (!oideq(&cmd_s->oid_commit, &des_s->oid_commit)) {
694+
set_deserialize_reject_reason("args/commit-changed");
653695
trace_printf_key(&trace_deserialize, "reject: sha1_commit");
654696
return DESERIALIZE_ERR;
655697
}
@@ -738,15 +780,18 @@ static int try_deserialize_read_from_file(const struct wt_status *cmd_s,
738780
enum wt_status_deserialize_wait dw,
739781
struct wt_status *des_s)
740782
{
741-
int k, limit;
783+
int k = 0;
784+
int limit;
742785
int result = DESERIALIZE_ERR;
743786

744787
/*
745788
* For "fail" or "no", try exactly once to read the status cache.
746789
* Return an error if the file is stale.
747790
*/
748-
if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO)
749-
return try_deserialize_read_from_file_1(cmd_s, path, des_s);
791+
if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO) {
792+
result = try_deserialize_read_from_file_1(cmd_s, path, des_s);
793+
goto done;
794+
}
750795

751796
/*
752797
* Wait for the status cache file to refresh. Wait duration can
@@ -771,6 +816,12 @@ static int try_deserialize_read_from_file(const struct wt_status *cmd_s,
771816
sleep_millisec(100);
772817
}
773818

819+
done:
820+
trace2_data_string("status", the_repository, "deserialize/path", path);
821+
trace2_data_intmax("status", the_repository, "deserialize/polled", k);
822+
trace2_data_string("status", the_repository, "deserialize/result",
823+
((result == DESERIALIZE_OK) ? "ok" : "reject"));
824+
774825
trace_printf_key(&trace_deserialize,
775826
"wait polled=%d result=%d '%s'",
776827
k, result, path);
@@ -796,6 +847,8 @@ int wt_status_deserialize(const struct wt_status *cmd_s,
796847
struct wt_status des_s;
797848
int result;
798849

850+
trace2_region_enter("status", "deserialize", the_repository);
851+
799852
if (path && *path && strcmp(path, "0")) {
800853
result = try_deserialize_read_from_file(cmd_s, path, dw, &des_s);
801854
} else {
@@ -806,8 +859,14 @@ int wt_status_deserialize(const struct wt_status *cmd_s,
806859
* term, since we cannot read stdin multiple times.
807860
*/
808861
result = wt_deserialize_fd(cmd_s, &des_s, 0);
862+
863+
trace2_data_string("status", the_repository, "deserialize/path", "STDIN");
864+
trace2_data_string("status", the_repository, "deserialize/result",
865+
((result == DESERIALIZE_OK) ? "ok" : "reject"));
809866
}
810867

868+
trace2_region_leave("status", "deserialize", the_repository);
869+
811870
if (result == DESERIALIZE_OK) {
812871
wt_status_get_state(cmd_s->repo, &des_s.state, des_s.branch &&
813872
!strcmp(des_s.branch, "HEAD"));

wt-status.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ int wt_status_deserialize(const struct wt_status *cmd_s,
243243
const char *path,
244244
enum wt_status_deserialize_wait dw);
245245

246+
int wt_status_deserialize_access(const char *path, int mode);
247+
246248
/*
247249
* A helper routine for serialize and deserialize to compute
248250
* metadata for the user-global and repo-local excludes files.

0 commit comments

Comments
 (0)