feat: add an API to time out query executions
Currently, if a predicate is hard to match on the Rust side, a sizable query against a very large file can take forever, and ends up hanging. This commit adds an API function `ts_query_cursor_set_timeout_micros` to limit how long query execution is allowed to take, thereby negating the chance of a hang to occur.
This commit is contained in:
parent
a748488596
commit
3f424c0121
11 changed files with 132 additions and 8 deletions
|
|
@ -792,7 +792,8 @@ void ts_query_matches_wasm(
|
|||
uint32_t start_index,
|
||||
uint32_t end_index,
|
||||
uint32_t match_limit,
|
||||
uint32_t max_start_depth
|
||||
uint32_t max_start_depth,
|
||||
uint32_t timeout_micros
|
||||
) {
|
||||
if (!scratch_query_cursor) {
|
||||
scratch_query_cursor = ts_query_cursor_new();
|
||||
|
|
@ -810,6 +811,7 @@ void ts_query_matches_wasm(
|
|||
ts_query_cursor_set_byte_range(scratch_query_cursor, start_index, end_index);
|
||||
ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit);
|
||||
ts_query_cursor_set_max_start_depth(scratch_query_cursor, max_start_depth);
|
||||
ts_query_cursor_set_timeout_micros(scratch_query_cursor, timeout_micros);
|
||||
ts_query_cursor_exec(scratch_query_cursor, self, node);
|
||||
|
||||
uint32_t index = 0;
|
||||
|
|
@ -847,7 +849,8 @@ void ts_query_captures_wasm(
|
|||
uint32_t start_index,
|
||||
uint32_t end_index,
|
||||
uint32_t match_limit,
|
||||
uint32_t max_start_depth
|
||||
uint32_t max_start_depth,
|
||||
uint32_t timeout_micros
|
||||
) {
|
||||
if (!scratch_query_cursor) {
|
||||
scratch_query_cursor = ts_query_cursor_new();
|
||||
|
|
@ -862,6 +865,7 @@ void ts_query_captures_wasm(
|
|||
ts_query_cursor_set_byte_range(scratch_query_cursor, start_index, end_index);
|
||||
ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit);
|
||||
ts_query_cursor_set_max_start_depth(scratch_query_cursor, max_start_depth);
|
||||
ts_query_cursor_set_timeout_micros(scratch_query_cursor, timeout_micros);
|
||||
ts_query_cursor_exec(scratch_query_cursor, self, node);
|
||||
|
||||
unsigned index = 0;
|
||||
|
|
|
|||
|
|
@ -1279,6 +1279,7 @@ class Query {
|
|||
endIndex = 0,
|
||||
matchLimit = 0xFFFFFFFF,
|
||||
maxStartDepth = 0xFFFFFFFF,
|
||||
timeoutMicros = 0,
|
||||
} = {},
|
||||
) {
|
||||
if (typeof matchLimit !== 'number') {
|
||||
|
|
@ -1298,6 +1299,7 @@ class Query {
|
|||
endIndex,
|
||||
matchLimit,
|
||||
maxStartDepth,
|
||||
timeoutMicros,
|
||||
);
|
||||
|
||||
const rawCount = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
@ -1342,6 +1344,7 @@ class Query {
|
|||
endIndex = 0,
|
||||
matchLimit = 0xFFFFFFFF,
|
||||
maxStartDepth = 0xFFFFFFFF,
|
||||
timeoutMicros = 0,
|
||||
} = {},
|
||||
) {
|
||||
if (typeof matchLimit !== 'number') {
|
||||
|
|
@ -1361,6 +1364,7 @@ class Query {
|
|||
endIndex,
|
||||
matchLimit,
|
||||
maxStartDepth,
|
||||
timeoutMicros,
|
||||
);
|
||||
|
||||
const count = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
|
|||
|
|
@ -451,6 +451,17 @@ describe('Query', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Set a timeout', () =>
|
||||
it('returns less than the expected matches', () => {
|
||||
tree = parser.parse('function foo() while (true) { } }\n'.repeat(1000));
|
||||
query = JavaScript.query('(function_declaration name: (identifier) @function)');
|
||||
const matches = query.matches(tree.rootNode, { timeoutMicros: 1000 });
|
||||
assert.isBelow(matches.length, 1000);
|
||||
const matches2 = query.matches(tree.rootNode, { timeoutMicros: 0 });
|
||||
assert.equal(matches2.length, 1000);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
function formatMatches(matches) {
|
||||
|
|
|
|||
1
lib/binding_web/tree-sitter-web.d.ts
vendored
1
lib/binding_web/tree-sitter-web.d.ts
vendored
|
|
@ -179,6 +179,7 @@ declare module 'web-tree-sitter' {
|
|||
endIndex?: number;
|
||||
matchLimit?: number;
|
||||
maxStartDepth?: number;
|
||||
timeoutMicros?: number;
|
||||
};
|
||||
|
||||
export interface PredicateResult {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue