Skip to content

Commit

Permalink
query: do not kill unpaged queries when they reach the tombstone-limit
Browse files Browse the repository at this point in the history
The reason we introduced the tombstone-limit
(query_tombstone_page_limit), was to allow paged queries to return
incomplete/empty pages in the face of large tombstone spans. This works
by cutting the page after the tombstone-limit amount of tombstones were
processed. If the read is unpaged, it is killed instead. This was a
mistake. First, it doesn't really make sense, the reason we introduced
the tombstone limit, was to allow paged queries to process large
tombstone-spans without timing out. It does not help unpaged queries.
Furthermore, the tombstone-limit can kill internal queries done on
behalf of user queries, because all our internal queries are unpaged.
This can cause denial of service.

So in this patch we disable the tombstone-limit for unpaged queries
altogether, they are allowed to continue even after having processed the
configured limit of tombstones.

Fixes: scylladb#17241

Closes scylladb#17242
  • Loading branch information
denesb authored and dgarcia360 committed Apr 30, 2024
1 parent 8a08968 commit d8c2e64
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 3 deletions.
6 changes: 3 additions & 3 deletions query-result-writer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ public:
return stop_iteration::no;
}
if (!_slice.options.contains<partition_slice::option::allow_short_read>()) {
throw std::runtime_error(fmt::format(
"Tombstones processed by unpaged query exceeds limit of {} (configured via query_tombstone_page_limit)",
_tombstone_limit));
// The read is unpaged, we cannot interrupt it early without failing it.
// Better let it continue.
return stop_iteration::no;
}
return stop_iteration::yes;
}
Expand Down
20 changes: 20 additions & 0 deletions test/cql-pytest/test_tombstone_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,23 @@ def test_empty_table(cql, test_keyspace, lowered_tombstone_limit, driver_bug_1):
assert list(cql.execute(f"SELECT * FROM {table}")) == []
assert list(cql.execute(f"SELECT * FROM {table} WHERE pk = 0")) == []
assert list(cql.execute(f"SELECT * FROM {table} WHERE v = 0 ALLOW FILTERING")) == []


# Unpaged query should be not affected
def test_unpaged_query(cql, table, lowered_tombstone_limit, driver_bug_1):
# Use update to avoid creating a row-marker ...
upsert_row_id = cql.prepare(f"UPDATE {table} SET v = ? WHERE pk = ? AND ck = ?")
# ... so deleting the only live cell in the row makes it empty.
delete_row_id = cql.prepare(f"DELETE v FROM {table} WHERE pk = ? AND ck = ?")

pk = unique_key_int()

for ck in range(0, 20):
cql.execute(upsert_row_id, (0, pk, ck))

for ck in range(0, 16):
cql.execute(delete_row_id, (pk, ck))

statement = SimpleStatement(f"SELECT * FROM {table} WHERE pk = {pk}", fetch_size=None)
rows = list(cql.execute(statement))
assert len(rows) == 4

0 comments on commit d8c2e64

Please sign in to comment.