query: do not kill unpaged queries when they reach the tombstone-limit
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: #17241 Closes scylladb/scylladb#17242
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user