Skip to content

Commit 597d83b

Browse files
kewillfordderrickstolee
authored andcommitted
Merge pull request #212 fsmonitor updates for improved performance
fsmonitor updates for improved performance
2 parents ef0f7c9 + 9e5815c commit 597d83b

File tree

4 files changed

+137
-26
lines changed

4 files changed

+137
-26
lines changed

cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static inline unsigned create_ce_flags(unsigned stage)
239239
#define ce_namelen(ce) ((ce)->ce_namelen)
240240
#define ce_size(ce) cache_entry_size(ce_namelen(ce))
241241
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
242-
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
242+
#define ce_uptodate(ce) (((ce)->ce_flags & CE_UPTODATE) || ((ce)->ce_flags & CE_FSMONITOR_VALID))
243243
#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
244244
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
245245
#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD)

fsmonitor.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,13 @@ void refresh_fsmonitor(struct index_state *istate)
261261
if (istate->untracked)
262262
istate->untracked->use_fsmonitor = 1;
263263
} else {
264-
265-
/* We only want to run the post index changed hook if we've actually changed entries, so keep track
266-
* if we actually changed entries or not */
264+
/*
265+
* We only want to run the post index changed hook if we've
266+
* actually changed entries, so keep track if we actually
267+
* changed entries or not
268+
*/
267269
int is_cache_changed = 0;
270+
268271
/* Mark all entries invalid */
269272
for (i = 0; i < istate->cache_nr; i++) {
270273
if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID) {
@@ -273,7 +276,7 @@ void refresh_fsmonitor(struct index_state *istate)
273276
}
274277
}
275278

276-
/* If we're going to check every file, ensure we save the results */
279+
/* If we're going to check every file, ensure we save results */
277280
if (is_cache_changed)
278281
istate->cache_changed |= FSMONITOR_CHANGED;
279282

t/t7519/fsmonitor-watchman

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use IPC::Open2;
1717
# 'git config core.fsmonitor .git/hooks/query-watchman'
1818
#
1919
my ($version, $time) = @ARGV;
20-
#print STDERR "$0 $version $time\n";
2120

2221
# Check the hook interface version
2322

@@ -44,7 +43,7 @@ launch_watchman();
4443

4544
sub launch_watchman {
4645

47-
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j')
46+
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
4847
or die "open2() failed: $!\n" .
4948
"Falling back to scanning...\n";
5049

@@ -62,19 +61,11 @@ sub launch_watchman {
6261
"fields": ["name"]
6362
}]
6463
END
65-
66-
open (my $fh, ">", ".git/watchman-query.json");
67-
print $fh $query;
68-
close $fh;
6964

7065
print CHLD_IN $query;
7166
close CHLD_IN;
7267
my $response = do {local $/; <CHLD_OUT>};
7368

74-
open ($fh, ">", ".git/watchman-response.json");
75-
print $fh $response;
76-
close $fh;
77-
7869
die "Watchman: command returned no output.\n" .
7970
"Falling back to scanning...\n" if $response eq "";
8071
die "Watchman: command returned invalid output: $response\n" .
@@ -93,7 +84,6 @@ sub launch_watchman {
9384
my $o = $json_pkg->new->utf8->decode($response);
9485

9586
if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
96-
print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
9787
$retry--;
9888
qx/watchman watch "$git_work_tree"/;
9989
die "Failed to make watchman watch '$git_work_tree'.\n" .
@@ -103,11 +93,6 @@ sub launch_watchman {
10393
# return the fast "everything is dirty" flag to git and do the
10494
# Watchman query just to get it over with now so we won't pay
10595
# the cost in git to look up each individual file.
106-
107-
open ($fh, ">", ".git/watchman-output.out");
108-
print "/\0";
109-
close $fh;
110-
11196
print "/\0";
11297
eval { launch_watchman() };
11398
exit 0;
@@ -116,11 +101,6 @@ sub launch_watchman {
116101
die "Watchman: $o->{error}.\n" .
117102
"Falling back to scanning...\n" if $o->{error};
118103

119-
open ($fh, ">", ".git/watchman-output.out");
120-
binmode $fh, ":utf8";
121-
print $fh @{$o->{files}};
122-
close $fh;
123-
124104
binmode STDOUT, ":utf8";
125105
local $, = "\0";
126106
print @{$o->{files}};

t/t7519/fsmonitor-watchman-debug

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/perl
2+
3+
use strict;
4+
use warnings;
5+
use IPC::Open2;
6+
7+
# An example hook script to integrate Watchman
8+
# (https://facebook.github.io/watchman/) with git to speed up detecting
9+
# new and modified files.
10+
#
11+
# The hook is passed a version (currently 1) and a time in nanoseconds
12+
# formatted as a string and outputs to stdout all files that have been
13+
# modified since the given time. Paths must be relative to the root of
14+
# the working tree and separated by a single NUL.
15+
#
16+
# To enable this hook, rename this file to "query-watchman" and set
17+
# 'git config core.fsmonitor .git/hooks/query-watchman'
18+
#
19+
my ($version, $time) = @ARGV;
20+
#print STDERR "$0 $version $time\n";
21+
22+
# Check the hook interface version
23+
24+
if ($version == 1) {
25+
# convert nanoseconds to seconds
26+
# subtract one second to make sure watchman will return all changes
27+
$time = int ($time / 1000000000) - 1;
28+
} else {
29+
die "Unsupported query-fsmonitor hook version '$version'.\n" .
30+
"Falling back to scanning...\n";
31+
}
32+
33+
my $git_work_tree;
34+
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
35+
$git_work_tree = Win32::GetCwd();
36+
$git_work_tree =~ tr/\\/\//;
37+
} else {
38+
require Cwd;
39+
$git_work_tree = Cwd::cwd();
40+
}
41+
42+
my $retry = 1;
43+
44+
launch_watchman();
45+
46+
sub launch_watchman {
47+
48+
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j')
49+
or die "open2() failed: $!\n" .
50+
"Falling back to scanning...\n";
51+
52+
# In the query expression below we're asking for names of files that
53+
# changed since $time but were not transient (ie created after
54+
# $time but no longer exist).
55+
#
56+
# To accomplish this, we're using the "since" generator to use the
57+
# recency index to select candidate nodes and "fields" to limit the
58+
# output to file names only.
59+
60+
my $query = <<" END";
61+
["query", "$git_work_tree", {
62+
"since": $time,
63+
"fields": ["name"]
64+
}]
65+
END
66+
67+
open (my $fh, ">", ".git/watchman-query.json");
68+
print $fh $query;
69+
close $fh;
70+
71+
print CHLD_IN $query;
72+
close CHLD_IN;
73+
my $response = do {local $/; <CHLD_OUT>};
74+
75+
open ($fh, ">", ".git/watchman-response.json");
76+
print $fh $response;
77+
close $fh;
78+
79+
die "Watchman: command returned no output.\n" .
80+
"Falling back to scanning...\n" if $response eq "";
81+
die "Watchman: command returned invalid output: $response\n" .
82+
"Falling back to scanning...\n" unless $response =~ /^\{/;
83+
84+
my $json_pkg;
85+
eval {
86+
require JSON::XS;
87+
$json_pkg = "JSON::XS";
88+
1;
89+
} or do {
90+
require JSON::PP;
91+
$json_pkg = "JSON::PP";
92+
};
93+
94+
my $o = $json_pkg->new->utf8->decode($response);
95+
96+
if ($retry > 0 and $o->{error} and $o->{error} =~ m/unable to resolve root .* directory (.*) is not watched/) {
97+
print STDERR "Adding '$git_work_tree' to watchman's watch list.\n";
98+
$retry--;
99+
qx/watchman watch "$git_work_tree"/;
100+
die "Failed to make watchman watch '$git_work_tree'.\n" .
101+
"Falling back to scanning...\n" if $? != 0;
102+
103+
# Watchman will always return all files on the first query so
104+
# return the fast "everything is dirty" flag to git and do the
105+
# Watchman query just to get it over with now so we won't pay
106+
# the cost in git to look up each individual file.
107+
108+
open ($fh, ">", ".git/watchman-output.out");
109+
print "/\0";
110+
close $fh;
111+
112+
print "/\0";
113+
eval { launch_watchman() };
114+
exit 0;
115+
}
116+
117+
die "Watchman: $o->{error}.\n" .
118+
"Falling back to scanning...\n" if $o->{error};
119+
120+
open ($fh, ">", ".git/watchman-output.out");
121+
binmode $fh, ":utf8";
122+
print $fh @{$o->{files}};
123+
close $fh;
124+
125+
binmode STDOUT, ":utf8";
126+
local $, = "\0";
127+
print @{$o->{files}};
128+
}

0 commit comments

Comments
 (0)