Skip to content

Commit 8ba178c

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 2d038cc commit 8ba178c

File tree

3 files changed

+82
-5
lines changed

3 files changed

+82
-5
lines changed

builtin/commit.c

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

166+
static int reject_implicit = 0;
166167
static int do_implicit_deserialize = 0;
167168
static int do_explicit_deserialize = 0;
168169
static char *deserialize_path = NULL;
@@ -226,7 +227,7 @@ static int opt_parse_deserialize(const struct option *opt, const char *arg, int
226227
}
227228
if (!deserialize_path || !*deserialize_path)
228229
do_explicit_deserialize = 1; /* read stdin */
229-
else if (access(deserialize_path, R_OK) == 0)
230+
else if (wt_status_deserialize_access(deserialize_path, R_OK) == 0)
230231
do_explicit_deserialize = 1; /* can read from this file */
231232
else {
232233
/*
@@ -1564,6 +1565,8 @@ static int git_status_config(const char *k, const char *v, void *cb)
15641565
if (v && *v && access(v, R_OK) == 0) {
15651566
do_implicit_deserialize = 1;
15661567
deserialize_path = xstrdup(v);
1568+
} else {
1569+
reject_implicit = 1;
15671570
}
15681571
return 0;
15691572
}
@@ -1718,6 +1721,17 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17181721

17191722
if (try_deserialize)
17201723
goto skip_init;
1724+
/*
1725+
* If we implicitly received a status cache pathname from the config
1726+
* and the file does not exist, we silently reject it and do the normal
1727+
* status "collect". Fake up some trace2 messages to reflect this and
1728+
* assist post-processors know this case is different.
1729+
*/
1730+
if (!do_serialize && reject_implicit) {
1731+
trace2_cmd_mode("implicit-deserialize");
1732+
trace2_data_string("status", the_repository, "deserialize/reject",
1733+
"status-cache/access");
1734+
}
17211735

17221736
enable_fscache(0);
17231737
if (status_format != STATUS_FORMAT_PORCELAIN &&
@@ -1761,6 +1775,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17611775
if (s.relative_paths)
17621776
s.prefix = prefix;
17631777

1778+
trace2_cmd_mode("deserialize");
17641779
result = wt_status_deserialize(&s, deserialize_path, dw);
17651780
if (result == DESERIALIZE_OK)
17661781
return 0;
@@ -1778,6 +1793,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17781793
fd = -1;
17791794
}
17801795

1796+
trace2_cmd_mode("collect");
17811797
wt_status_collect(&s);
17821798

17831799
if (0 <= fd)
@@ -1792,6 +1808,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
17921808
if (fd_serialize < 0)
17931809
die_errno(_("could not serialize to '%s'"),
17941810
serialize_path);
1811+
trace2_cmd_mode("serialize");
17951812
wt_status_serialize_v1(fd_serialize, &s);
17961813
close(fd_serialize);
17971814
}

wt-status-deserialize.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
33
#include "pkt-line.h"
44
#include "trace.h"
55

6+
static void set_deserialize_reject_reason(const char *reason)
7+
{
8+
trace2_data_string("status", the_repository, "deserialize/reject",
9+
reason);
10+
}
11+
12+
int wt_status_deserialize_access(const char *path, int mode)
13+
{
14+
int a = access(path, mode);
15+
16+
if (a != 0)
17+
set_deserialize_reject_reason("status-cache/access");
18+
19+
return a;
20+
}
21+
622
static struct trace_key trace_deserialize = TRACE_KEY_INIT(DESERIALIZE);
723

824
enum deserialize_parse_strategy {
@@ -49,13 +65,15 @@ static int my_validate_index(const struct cache_time *mtime_reported)
4965
struct cache_time mtime_observed_on_disk;
5066

5167
if (lstat(path, &st)) {
68+
set_deserialize_reject_reason("index/not-found");
5269
trace_printf_key(&trace_deserialize, "could not stat index");
5370
return DESERIALIZE_ERR;
5471
}
5572
mtime_observed_on_disk.sec = st.st_mtime;
5673
mtime_observed_on_disk.nsec = ST_MTIME_NSEC(st);
5774
if ((mtime_observed_on_disk.sec != mtime_reported->sec) ||
5875
(mtime_observed_on_disk.nsec != mtime_reported->nsec)) {
76+
set_deserialize_reject_reason("index/mtime-changed");
5977
trace_printf_key(&trace_deserialize,
6078
"index mtime changed [des %d %d][obs %d %d]",
6179
mtime_reported->sec, mtime_reported->nsec,
@@ -81,10 +99,12 @@ static int my_validate_excludes(const char *path, const char *key, const char *l
8199

82100
r = (strcmp(line, sb.buf) ? DESERIALIZE_ERR : DESERIALIZE_OK);
83101

84-
if (r == DESERIALIZE_ERR)
102+
if (r == DESERIALIZE_ERR) {
103+
set_deserialize_reject_reason("excludes/changed");
85104
trace_printf_key(&trace_deserialize,
86105
"%s changed [cached '%s'][observed '%s']",
87106
key, line, sb.buf);
107+
}
88108

89109
strbuf_release(&sb);
90110
return r;
@@ -140,6 +160,7 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
140160
&index_mtime.sec,
141161
&index_mtime.nsec);
142162
if (nr_fields != 2) {
163+
set_deserialize_reject_reason("v1-header/invalid-index-mtime");
143164
trace_printf_key(&trace_deserialize, "invalid index_mtime (%d) '%s'",
144165
nr_fields, line);
145166
return DESERIALIZE_ERR;
@@ -223,6 +244,7 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
223244
/* status_format */
224245
if (skip_prefix(line, "sha1_commit ", &arg)) {
225246
if (get_oid_hex(arg, &s->oid_commit)) {
247+
set_deserialize_reject_reason("v1-header/invalid-commit-sha");
226248
trace_printf_key(&trace_deserialize, "invalid sha1_commit");
227249
return DESERIALIZE_ERR;
228250
}
@@ -238,19 +260,23 @@ static int wt_deserialize_v1_header(struct wt_status *s, int fd)
238260
}
239261
/* prefix */
240262

263+
set_deserialize_reject_reason("v1-header/unexpected-line");
241264
trace_printf_key(&trace_deserialize, "unexpected line '%s'", line);
242265
return DESERIALIZE_ERR;
243266
}
244267

245268
if (!have_required_index_mtime) {
269+
set_deserialize_reject_reason("v1-header/missing-index-mtime");
246270
trace_printf_key(&trace_deserialize, "missing '%s'", "index_mtime");
247271
return DESERIALIZE_ERR;
248272
}
249273
if (!have_required_core_excludes) {
274+
set_deserialize_reject_reason("v1-header/missing-core-excludes");
250275
trace_printf_key(&trace_deserialize, "missing '%s'", "core_excludes");
251276
return DESERIALIZE_ERR;
252277
}
253278
if (!have_required_repo_excludes) {
279+
set_deserialize_reject_reason("v1-header/missing-repo-excludes");
254280
trace_printf_key(&trace_deserialize, "missing '%s'", "repo_excludes");
255281
return DESERIALIZE_ERR;
256282
}
@@ -337,6 +363,7 @@ static int wt_deserialize_v1_changed_items(const struct wt_status *cmd_s,
337363
* So we reject the status cache and let the fallback
338364
* code run.
339365
*/
366+
set_deserialize_reject_reason("v1-data/unmerged");
340367
trace_printf_key(
341368
&trace_deserialize,
342369
"reject: V2 format and umerged file: %s",
@@ -478,13 +505,15 @@ static int wt_deserialize_v1(const struct wt_status *cmd_s, struct wt_status *s,
478505
* the serialized data
479506
*/
480507
if (validate_untracked_files_arg(cmd_s->show_untracked_files, &s->show_untracked_files, &untracked_strategy)) {
508+
set_deserialize_reject_reason("args/untracked-files");
481509
trace_printf_key(&trace_deserialize, "reject: show_untracked_file: command: %d, serialized : %d",
482510
cmd_s->show_untracked_files,
483511
s->show_untracked_files);
484512
return DESERIALIZE_ERR;
485513
}
486514

487515
if (validate_ignored_files_arg(cmd_s->show_ignored_mode, s->show_ignored_mode, &ignored_strategy)) {
516+
set_deserialize_reject_reason("args/ignored-mode");
488517
trace_printf_key(&trace_deserialize, "reject: show_ignored_mode: command: %d, serialized: %d",
489518
cmd_s->show_ignored_mode,
490519
s->show_ignored_mode);
@@ -518,6 +547,7 @@ static int wt_deserialize_v1(const struct wt_status *cmd_s, struct wt_status *s,
518547
return DESERIALIZE_ERR;
519548
continue;
520549
}
550+
set_deserialize_reject_reason("v1-data/unexpected-line");
521551
trace_printf_key(&trace_deserialize, "unexpected line '%s'", line);
522552
return DESERIALIZE_ERR;
523553
}
@@ -539,6 +569,7 @@ static int wt_deserialize_parse(const struct wt_status *cmd_s, struct wt_status
539569
if (version == 1)
540570
return wt_deserialize_v1(cmd_s, s, fd);
541571
}
572+
set_deserialize_reject_reason("status-cache/unsupported-version");
542573
trace_printf_key(&trace_deserialize, "missing/unsupported version");
543574
return DESERIALIZE_ERR;
544575
}
@@ -559,6 +590,7 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
559590
* Check the path spec on the current command
560591
*/
561592
if (cmd_s->pathspec.nr > 1) {
593+
set_deserialize_reject_reason("args/multiple-pathspecs");
562594
trace_printf_key(&trace_deserialize, "reject: multiple pathspecs");
563595
return DESERIALIZE_ERR;
564596
}
@@ -569,6 +601,7 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
569601
*/
570602
if (cmd_s->pathspec.nr == 1 &&
571603
my_strcmp_null(cmd_s->pathspec.items[0].match, "")) {
604+
set_deserialize_reject_reason("args/root-pathspec");
572605
trace_printf_key(&trace_deserialize, "reject: pathspec");
573606
return DESERIALIZE_ERR;
574607
}
@@ -585,20 +618,24 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
585618
* or "--ignored" settings).
586619
*/
587620
if (cmd_s->is_initial != des_s->is_initial) {
621+
set_deserialize_reject_reason("args/is-initial-changed");
588622
trace_printf_key(&trace_deserialize, "reject: is_initial");
589623
return DESERIALIZE_ERR;
590624
}
591625
if (my_strcmp_null(cmd_s->branch, des_s->branch)) {
626+
set_deserialize_reject_reason("args/branch-changed");
592627
trace_printf_key(&trace_deserialize, "reject: branch");
593628
return DESERIALIZE_ERR;
594629
}
595630
if (my_strcmp_null(cmd_s->reference, des_s->reference)) {
631+
set_deserialize_reject_reason("args/reference-changed");
596632
trace_printf_key(&trace_deserialize, "reject: reference");
597633
return DESERIALIZE_ERR;
598634
}
599635
/* verbose */
600636
/* amend */
601637
if (cmd_s->whence != des_s->whence) {
638+
set_deserialize_reject_reason("args/whence-changed");
602639
trace_printf_key(&trace_deserialize, "reject: whence");
603640
return DESERIALIZE_ERR;
604641
}
@@ -632,19 +669,23 @@ static int wt_deserialize_fd(const struct wt_status *cmd_s, struct wt_status *de
632669
/* hints */
633670
/* ahead_behind_flags */
634671
if (cmd_s->detect_rename != des_s->detect_rename) {
672+
set_deserialize_reject_reason("args/detect-rename-changed");
635673
trace_printf_key(&trace_deserialize, "reject: detect_rename");
636674
return DESERIALIZE_ERR;
637675
}
638676
if (cmd_s->rename_score != des_s->rename_score) {
677+
set_deserialize_reject_reason("args/rename-score-changed");
639678
trace_printf_key(&trace_deserialize, "reject: rename_score");
640679
return DESERIALIZE_ERR;
641680
}
642681
if (cmd_s->rename_limit != des_s->rename_limit) {
682+
set_deserialize_reject_reason("args/rename-limit-changed");
643683
trace_printf_key(&trace_deserialize, "reject: rename_limit");
644684
return DESERIALIZE_ERR;
645685
}
646686
/* status_format */
647687
if (!oideq(&cmd_s->oid_commit, &des_s->oid_commit)) {
688+
set_deserialize_reject_reason("args/commit-changed");
648689
trace_printf_key(&trace_deserialize, "reject: sha1_commit");
649690
return DESERIALIZE_ERR;
650691
}
@@ -733,15 +774,18 @@ static int try_deserialize_read_from_file(const struct wt_status *cmd_s,
733774
enum wt_status_deserialize_wait dw,
734775
struct wt_status *des_s)
735776
{
736-
int k, limit;
777+
int k = 0;
778+
int limit;
737779
int result = DESERIALIZE_ERR;
738780

739781
/*
740782
* For "fail" or "no", try exactly once to read the status cache.
741783
* Return an error if the file is stale.
742784
*/
743-
if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO)
744-
return try_deserialize_read_from_file_1(cmd_s, path, des_s);
785+
if (dw == DESERIALIZE_WAIT__FAIL || dw == DESERIALIZE_WAIT__NO) {
786+
result = try_deserialize_read_from_file_1(cmd_s, path, des_s);
787+
goto done;
788+
}
745789

746790
/*
747791
* Wait for the status cache file to refresh. Wait duration can
@@ -766,6 +810,12 @@ static int try_deserialize_read_from_file(const struct wt_status *cmd_s,
766810
sleep_millisec(100);
767811
}
768812

813+
done:
814+
trace2_data_string("status", the_repository, "deserialize/path", path);
815+
trace2_data_intmax("status", the_repository, "deserialize/polled", k);
816+
trace2_data_string("status", the_repository, "deserialize/result",
817+
((result == DESERIALIZE_OK) ? "ok" : "reject"));
818+
769819
trace_printf_key(&trace_deserialize,
770820
"wait polled=%d result=%d '%s'",
771821
k, result, path);
@@ -791,6 +841,8 @@ int wt_status_deserialize(const struct wt_status *cmd_s,
791841
struct wt_status des_s;
792842
int result;
793843

844+
trace2_region_enter("status", "deserialize", the_repository);
845+
794846
if (path && *path && strcmp(path, "0")) {
795847
result = try_deserialize_read_from_file(cmd_s, path, dw, &des_s);
796848
} else {
@@ -801,8 +853,14 @@ int wt_status_deserialize(const struct wt_status *cmd_s,
801853
* term, since we cannot read stdin multiple times.
802854
*/
803855
result = wt_deserialize_fd(cmd_s, &des_s, 0);
856+
857+
trace2_data_string("status", the_repository, "deserialize/path", "STDIN");
858+
trace2_data_string("status", the_repository, "deserialize/result",
859+
((result == DESERIALIZE_OK) ? "ok" : "reject"));
804860
}
805861

862+
trace2_region_leave("status", "deserialize", the_repository);
863+
806864
if (result == DESERIALIZE_OK) {
807865
wt_status_get_state(cmd_s->repo, &des_s.state, des_s.branch &&
808866
!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)