Skip to content

Commit

Permalink
Add support for eden flag listOnlyFiles
Browse files Browse the repository at this point in the history
Summary:
This diff lets watchman deduce whether or not to use the listOnlyFiles flag when using eden.

The system works as follows
 - ["type", "d"] means listOnlyFiles is false
 - all other type fields means it is true
 - ["not"] inverts the subexpression
 - Any value in an ["allof"] being true results in the whole expression being true
 - Each value in an ["anyof"] must be true for the expression to be true
 - All other expressions result in false

Reviewed By: kmancini

Differential Revision: D58469180

fbshipit-source-id: e775441ca7f38e1ec4de0c048714cb7361fc912b
  • Loading branch information
Chris Dinh authored and facebook-github-bot committed Jul 8, 2024
1 parent 0b68c37 commit 7ad330d
Show file tree
Hide file tree
Showing 13 changed files with 336 additions and 2 deletions.
9 changes: 9 additions & 0 deletions watchman/query/QueryExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ class QueryExpr {
*/
virtual std::optional<std::vector<std::string>> computeGlobUpperBound(
CaseSensitivity) const = 0;

enum ReturnOnlyFiles { No, Yes, Unrelated };

/**
* Returns whether this expression only returns files.
* Used to determine if Eden can use the faster server-based
* method to handle this query.
*/
virtual ReturnOnlyFiles listOnlyFiles() const = 0;
};

} // namespace watchman
75 changes: 75 additions & 0 deletions watchman/query/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ class NotExpr : public QueryExpr {
// the inner expression is.
return std::nullopt;
}

/**
* Inverts the result of the subexpression.
* Expressions that are unrelated stay unrelated.
*/
ReturnOnlyFiles listOnlyFiles() const override {
auto subExprValue = expr->listOnlyFiles();
if (subExprValue == ReturnOnlyFiles::Yes) {
return ReturnOnlyFiles::No;
} else if (subExprValue == ReturnOnlyFiles::No) {
return ReturnOnlyFiles::Yes;
}
return ReturnOnlyFiles::Unrelated;
}
};

W_TERM_PARSER(not, NotExpr::parse);
Expand All @@ -69,6 +83,10 @@ class TrueExpr : public QueryExpr {
// We will match every path --> unbounded.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};

W_TERM_PARSER(true, TrueExpr::parse);
Expand All @@ -88,6 +106,10 @@ class FalseExpr : public QueryExpr {
// We will not match any path --> bounded by an empty list of globs.
return std::vector<std::string>{};
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};

W_TERM_PARSER(false, FalseExpr::parse);
Expand Down Expand Up @@ -237,6 +259,59 @@ class ListExpr : public QueryExpr {
return std::vector<std::string>(
unionOfUpperBounds.begin(), unionOfUpperBounds.end());
}
/**
* Combines the results of the subexpressions.
* For allof, the result needs to satisfy each subexpression.
* - If any subexpression requests non-file data, the whole expression must
* also contain non-file data. Therefore we return No if any subexpression
* requests non-file data.
* - If any subexpression requests only file data, the whole expression must
* also contain only file data. Therefore we return Yes if one subexpression
* requests only file data. and there is no subexpression requesting
* non-file data.
* - We return No if there are both Yes and No subexpressions because
* we want expressions that exclude groups of types like
* ["not", ["allof", ["type", "l"], ["type", "d"]]]
* to return Yes if we are excluding directories.
* For anyof, the result can satisfy any subexpression.
* - If any subexpression requests non-file data, the whole expression could
* also contain non-file data. Therefore we return No if any subexpression
* requests non-file data.
* - The only way for the whole expression to contain only file data is if
* each subexpression contains only file data. Therefore we return Yes only
* if each subexpression is Yes.
*/
ReturnOnlyFiles listOnlyFiles() const override {
ReturnOnlyFiles result = ReturnOnlyFiles::Unrelated;
if (allof) {
for (auto& subExpr : exprs) {
auto value = subExpr->listOnlyFiles();
if (value == ReturnOnlyFiles::Yes) {
result = ReturnOnlyFiles::Yes;
} else if (value == ReturnOnlyFiles::No) {
return ReturnOnlyFiles::No;
}
}
} else {
bool allYes = exprs.empty()
? false
: exprs[0]->listOnlyFiles() == ReturnOnlyFiles::Yes;
for (auto& subExpr : exprs) {
auto value = subExpr->listOnlyFiles();
if (value == ReturnOnlyFiles::Yes) {
// Keep checking the remaining subexprs
} else if (value == ReturnOnlyFiles::No) {
return ReturnOnlyFiles::No;
} else {
allYes = false;
}
}
if (allYes) {
return ReturnOnlyFiles::Yes;
}
}
return result;
}
};

W_TERM_PARSER(anyof, ListExpr::parseAnyOf);
Expand Down
4 changes: 4 additions & 0 deletions watchman/query/dirname.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ class DirNameExpr : public QueryExpr {

return std::vector<std::string>{outputPattern.string() + "/**"};
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};

W_TERM_PARSER(dirname, DirNameExpr::parseDirName);
Expand Down
8 changes: 8 additions & 0 deletions watchman/query/empty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ class ExistsExpr : public QueryExpr {
// `exists` doesn't constrain the path.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(exists, ExistsExpr::parse);

Expand Down Expand Up @@ -71,6 +75,10 @@ class EmptyExpr : public QueryExpr {
// `empty` doesn't constrain the path.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(empty, EmptyExpr::parse);

Expand Down
4 changes: 4 additions & 0 deletions watchman/query/intcompare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ class SizeExpr : public QueryExpr {
// `size` doesn't constrain the path.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(size, SizeExpr::parse);

Expand Down
4 changes: 4 additions & 0 deletions watchman/query/match.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ class WildMatchExpr : public QueryExpr {
return std::vector<std::string>{
trimGlobAfterDoubleStar(outputPattern).string()};
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(match, WildMatchExpr::parseMatch);
W_TERM_PARSER(imatch, WildMatchExpr::parseIMatch);
Expand Down
4 changes: 4 additions & 0 deletions watchman/query/name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ class NameExpr : public QueryExpr {
return std::vector<std::string>(
globUpperBound.begin(), globUpperBound.end());
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};

W_TERM_PARSER(name, NameExpr::parseName);
Expand Down
4 changes: 4 additions & 0 deletions watchman/query/pcre.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ class PcreExpr : public QueryExpr {

return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(pcre, PcreExpr::parsePcre);
W_TERM_PARSER(ipcre, PcreExpr::parseIPcre);
Expand Down
4 changes: 4 additions & 0 deletions watchman/query/since.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ class SinceExpr : public QueryExpr {
// `since` doesn't constrain the path.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(since, SinceExpr::parse);

Expand Down
4 changes: 4 additions & 0 deletions watchman/query/suffix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ class SuffixExpr : public QueryExpr {
// it as unbounded.
return std::nullopt;
}

ReturnOnlyFiles listOnlyFiles() const override {
return ReturnOnlyFiles::Unrelated;
}
};
W_TERM_PARSER(suffix, SuffixExpr::parse);
W_CAP_REG("suffix-set")
Expand Down
11 changes: 11 additions & 0 deletions watchman/query/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ class TypeExpr : public QueryExpr {
// `type` doesn't constrain the path.
return std::nullopt;
}

/**
* Determines if this expression will return only files.
* An expression returns files if is not type 'd', for directories.
*/
ReturnOnlyFiles listOnlyFiles() const override {
if (arg == 'd') {
return ReturnOnlyFiles::No;
}
return ReturnOnlyFiles::Yes;
}
};
W_TERM_PARSER(type, TypeExpr::parse);

Expand Down
Loading

0 comments on commit 7ad330d

Please sign in to comment.