Skip to content

Commit 13f8336

Browse files
jeffhostetlerdscho
authored andcommitted
fsmonitor: optimize processing of directory events
Teach Git to perform binary search over the cache-entries for a directory notification and then linearly scan forward to find the immediate children. Previously, when the FSMonitor reported a modified directory Git would perform a linear search on the entire cache-entry array for all entries matching that directory prefix and invalidate them. Since the cache-entry array is already sorted, we can use a binary search to find the first matching entry and then only linearly walk forward and invalidate entries until the prefix changes. Also, the original code would invalidate anything having the same directory prefix. Since a directory event should only be received for items that are immediately within the directory (and not within sub-directories of it), only invalidate those entries and not the whole subtree. Signed-off-by: Jeff Hostetler <[email protected]>
1 parent edb45f0 commit 13f8336

File tree

1 file changed

+11
-12
lines changed

1 file changed

+11
-12
lines changed

fsmonitor.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -199,25 +199,24 @@ static void fsmonitor_refresh_callback(struct index_state *istate, char *name)
199199
{
200200
int i, len = strlen(name);
201201
if (name[len - 1] == '/') {
202-
203-
/*
204-
* TODO We should binary search to find the first path with
205-
* TODO this directory prefix. Then linearly update entries
206-
* TODO while the prefix matches. Taking care to search without
207-
* TODO the trailing slash -- because '/' sorts after a few
208-
* TODO interesting special chars, like '.' and ' '.
209-
*/
202+
const char *rel;
203+
int pos = index_name_pos(istate, name, len);
204+
if (pos < 0)
205+
pos = -pos - 1;
210206

211207
/* Mark all entries for the folder invalid */
212-
for (i = 0; i < istate->cache_nr; i++) {
213-
if (istate->cache[i]->ce_flags & CE_FSMONITOR_VALID &&
214-
starts_with(istate->cache[i]->name, name))
208+
for (i = pos; i < istate->cache_nr; i++) {
209+
if (!starts_with(istate->cache[i]->name, name))
210+
break;
211+
/* Only mark the immediate children in the folder */
212+
rel = istate->cache[i]->name + len;
213+
if (!strchr(rel, '/'))
215214
istate->cache[i]->ce_flags &= ~CE_FSMONITOR_VALID;
216215
}
217216
/* Need to remove the / from the path for the untracked cache */
218217
name[len - 1] = '\0';
219218
} else {
220-
int pos = index_name_pos(istate, name, strlen(name));
219+
int pos = index_name_pos(istate, name, len);
221220

222221
if (pos >= 0) {
223222
struct cache_entry *ce = istate->cache[pos];

0 commit comments

Comments
 (0)