Files
Alexey MilovidovandClaude Opus 4.8 295ced78d1 Enable more Ruff checks (F401/F403/F405/F541/F841) and clean up tests
Follow-up to #105171, which added `ruff` with a deliberately narrow,
bug-class-only rule set and left the unused-name and star-import rules
off pending a dedicated cleanup pass. This enables that second batch in
`pyproject.toml` and fixes every violation across the tree (the bulk in
integration tests):

- `F401` unused-import and `F841` unused-variable: removed, preserving
  any side-effecting right-hand side (e.g. `result = node.query(...)`
  becomes `node.query(...)`). Two `try: import ...` feature probes are
  kept with `# noqa: F401`.
- `F541` f-string-missing-placeholders: dropped the redundant `f` prefix.
- `F403`/`F405` star imports: every `from module import *` is expanded
  into explicit imports of the names actually used, taken from each
  name's real origin, so stdlib/third-party names import from their real
  source rather than through a test "convenience bundle". The now-empty
  `tests/integration/helpers/kafka/common_direct.py` bundle is removed and
  its three remaining consumers import `_VarintBytes`/`KafkaAdminClient`
  directly.

Eliminating the star imports surfaced a real bug the wildcard had masked
from `F821`: `generate_presets.py` in `test_prometheus_protocols` called
an undefined `execute_instant_query_with_http_api`; fixed to the existing
`execute_query_via_http_api`.

No `black`/`isort` reformatting was applied (neither is enforced in the
style check), so the diff is limited to the lint fixes themselves.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-18 23:22:25 +00:00

196 lines
6.4 KiB
Python

import time
import pytest
from helpers.cluster import ClickHouseCluster
cluster = ClickHouseCluster(__file__)
node = cluster.add_instance(
"node",
main_configs=["configs/config.d/split_cache.xml", "configs/config.d/test_logger.xml"],
stay_alive=True,
with_minio=True,
)
def wait_for_cache_initialized(node, cache_name, max_attempts=50):
initialized = False
attempts = 0
while not initialized:
initialized = bool(
node.query(
f"SELECT is_initialized FROM system.filesystem_cache_settings WHERE is_initialized and cache_name='{cache_name}'"
)
)
if initialized:
break
time.sleep(0.1)
attempts += 1
if attempts >= max_attempts:
raise Exception("Stopped waiting for cache to be initialized")
@pytest.fixture(scope="module")
def started_cluster():
try:
cluster.start()
yield cluster
finally:
cluster.shutdown()
def test_split_cache_silly_test(started_cluster):
node.query("DROP TABLE IF EXISTS t0")
node.query(
"""CREATE TABLE t0 (
key UInt64,
value UInt64
)
ENGINE = MergeTree
PRIMARY KEY key
SETTINGS storage_policy = 'split_cache_slru'
"""
)
node.query("INSERT INTO t0 SELECT rand()%1000, rand()%1000 FROM numbers(10000)")
node.query("SELECT * FROM t0;")
node.query("DROP TABLE t0")
def test_split_cache_restart(started_cluster):
node.query("DROP TABLE IF EXISTS t0")
node.query(
"""CREATE TABLE t0 (
key UInt64,
value UInt64
)
ENGINE = MergeTree
PRIMARY KEY key
SETTINGS storage_policy = 'split_cache_slru'
"""
)
node.query("INSERT INTO t0 SELECT rand()%1000, rand()%1000 FROM numbers(10000)")
node.query("OPTIMIZE TABLE t0")
node.query("SYSTEM STOP MERGES t0")
node.query("SYSTEM CLEAR FILESYSTEM CACHE 'split_cache_slru'")
node.restart_clickhouse()
wait_for_cache_initialized(node, "split_cache_slru")
cache_state = node.query(
"SELECT key, file_segment_range_begin, size FROM system.filesystem_cache WHERE size > 0 ORDER BY key, file_segment_range_begin, size"
)
cache_count = int(
node.query("SELECT count() FROM system.filesystem_cache WHERE cache_name = 'split_cache_slru' AND size > 0")
)
node.restart_clickhouse()
wait_for_cache_initialized(node, "split_cache_slru")
cache_state_after_restart = node.query(
"SELECT key, file_segment_range_begin, size FROM system.filesystem_cache WHERE size > 0 ORDER BY key, file_segment_range_begin, size"
)
new_cache_count = int(
node.query("SELECT count() FROM system.filesystem_cache WHERE cache_name = 'split_cache_slru' AND size > 0")
)
print(f"Cache state before restart:\n{cache_state}")
print(f"Cache state after restart:\n{cache_state_after_restart}")
# Background operations (outdated parts loading, background downloads, cleanup)
# may change cache state slightly between restarts, so use tolerance.
if cache_count > 0:
fraction = abs(new_cache_count - cache_count) / cache_count
assert fraction <= 0.5, f"Cache count changed too much: {cache_count} -> {new_cache_count}"
node.query("DROP TABLE t0")
@pytest.mark.parametrize("storage_policy", [("split_cache_slru"), ("split_cache_lru")])
def test_split_cache_system_files_no_eviction(started_cluster, storage_policy):
"""
Note: Check that after full scan of the table files that are needed for restart will be still presented in cache.
Total size of system fiels in this case is about 350 KiB; data files is 17 MiB;
Size of system segment of cache is 1 MiB; Data segment of cache is 4 MiB.
WITH parts AS
(
SELECT replaceAll(path, system.disks.path, '')
FROM system.parts
LEFT JOIN system.disks ON system.parts.disk_name = system.disks.name
WHERE active AND (`table` = 't0')
)
SELECT
splitByChar('.', local_path)[-1] AS ext,
formatReadableSize(sum(size))
FROM system.remote_data_paths
WHERE substring(local_path, 1, (length(local_path) - position(reverse(local_path), '/')) + 1) IN (parts)
GROUP BY ext
┌─ext───┬─formatReadab⋯(sum(size))─┐
1. │ bin │ 16.67 MiB │
2. │ cmrk2 │ 126.19 KiB │
3. │ txt │ 95.70 KiB │
4. │ json │ 32.83 KiB │
5. │ cidx │ 47.27 KiB │
└───────┴──────────────────────────┘
"""
# Generaly they should be different, but for simplicity they are equal.
filesystem_cache_name = storage_policy
node.query("DROP TABLE IF EXISTS t0")
node.query(
f"""CREATE TABLE t0 (
key UInt64,
value UInt64
)
ENGINE = MergeTree
PRIMARY KEY key
SETTINGS storage_policy = '{storage_policy}',
min_bytes_for_wide_part = 0
"""
)
for _ in range(100):
node.query(
"""
INSERT INTO t0 SELECT rand()%1000, rand()%1000 FROM numbers(1000000)
"""
)
node.query("SYSTEM STOP MERGES t0")
node.query(f"SYSTEM CLEAR FILESYSTEM CACHE '{filesystem_cache_name}'")
node.restart_clickhouse()
wait_for_cache_initialized(node, storage_policy)
count = int(
node.query(
f"SELECT count(*) FROM system.filesystem_cache WHERE cache_name = '{filesystem_cache_name}' AND segment_type='System'"
)
)
assert count > 0
def assert_cache_state():
"""
The state of cache can change with background processes, so make sure that the state does not change dramatically.
"""
current_count = int(
node.query(
f"SELECT count(*) FROM system.filesystem_cache WHERE cache_name = '{filesystem_cache_name}' AND segment_type='System'"
)
)
fraction = abs(current_count - count) / count
assert fraction <= 0.5, f"System cache count changed too much: {count} -> {current_count}"
node.query("SELECT * FROM t0 FORMAT NULL")
assert_cache_state()
node.restart_clickhouse()
wait_for_cache_initialized(node, storage_policy)
assert_cache_state()
node.query("DROP TABLE t0 SYNC")