|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Tags: zookeeper, no-parallel, no-replicated-database |
| 3 | +# Tag no-parallel: enables a REGULAR failpoint that affects the whole server process. |
| 4 | +# Tag no-replicated-database: the test creates its own Replicated database and the |
| 5 | +# failpoint is enabled only on one server node. |
| 6 | + |
| 7 | +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) |
| 8 | +# shellcheck source=../shell_config.sh |
| 9 | +. "$CURDIR"/../shell_config.sh |
| 10 | + |
| 11 | +DB="${CLICKHOUSE_DATABASE}_repl" |
| 12 | +ZK_PATH="/test/timeseries_rename_digest/${CLICKHOUSE_TEST_UNIQUE_NAME}" |
| 13 | + |
| 14 | +${CLICKHOUSE_CLIENT} -q " |
| 15 | + CREATE DATABASE ${DB} |
| 16 | + ENGINE = Replicated('${ZK_PATH}', 's1', 'r1') |
| 17 | +" |
| 18 | + |
| 19 | +${CLICKHOUSE_CLIENT} --distributed_ddl_output_mode=none --allow_experimental_time_series_table=1 \ |
| 20 | + -q "CREATE TABLE ${DB}.ts ENGINE = TimeSeries" |
| 21 | + |
| 22 | +# Force the metadata digest assertion to always run (skip the 1/16 probability gate), so any |
| 23 | +# divergence between the in-memory tables map and ZooKeeper is caught immediately. In release |
| 24 | +# builds assertDigestWithProbability is compiled out, so this is a no-op there. |
| 25 | +${CLICKHOUSE_CLIENT} -q "SYSTEM ENABLE FAILPOINT database_replicated_force_metadata_digest_check" |
| 26 | + |
| 27 | +# RENAME TABLE must succeed and the table must keep working. Before the fix it was rejected from |
| 28 | +# renameInMemory() only after DatabaseAtomic::renameTable() had detached the table and committed |
| 29 | +# the ZooKeeper transaction, leaving it counted in tables_metadata_digest but missing locally, so |
| 30 | +# the next forced digest assertion aborted the server with "Digest does not match". |
| 31 | +${CLICKHOUSE_CLIENT} --distributed_ddl_output_mode=none -q "RENAME TABLE ${DB}.ts TO ${DB}.ts2" |
| 32 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${DB}.ts" |
| 33 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${DB}.ts2" |
| 34 | + |
| 35 | +# RENAME DATABASE must succeed too (it renames every contained table in place). |
| 36 | +${CLICKHOUSE_CLIENT} --distributed_ddl_output_mode=none -q "RENAME DATABASE ${DB} TO ${DB}_renamed" |
| 37 | +${CLICKHOUSE_CLIENT} -q "EXISTS DATABASE ${DB}" |
| 38 | +${CLICKHOUSE_CLIENT} -q "EXISTS DATABASE ${DB}_renamed" |
| 39 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${DB}_renamed.ts2" |
| 40 | + |
| 41 | +# CREATE OR REPLACE creates a temporary table and renames it onto the target name; that internal |
| 42 | +# rename is the path the original report tripped over. With the target absent it must create the |
| 43 | +# table cleanly. |
| 44 | +${CLICKHOUSE_CLIENT} --distributed_ddl_output_mode=none --allow_experimental_time_series_table=1 \ |
| 45 | + -q "CREATE OR REPLACE TABLE ${DB}_renamed.cor ENGINE = TimeSeries" |
| 46 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${DB}_renamed.cor" |
| 47 | + |
| 48 | +# With the forced digest check still on, an unrelated DDL must SUCCEED, proving the digest stayed |
| 49 | +# consistent through every rename above. Run it without grep so a crash, lost connection, or any |
| 50 | +# other failure fails the test instead of being masked. |
| 51 | +${CLICKHOUSE_CLIENT} --distributed_ddl_output_mode=none \ |
| 52 | + -q "CREATE TABLE ${DB}_renamed.probe (id UInt64) ENGINE = ReplicatedMergeTree ORDER BY id" |
| 53 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${DB}_renamed.probe" |
| 54 | + |
| 55 | +${CLICKHOUSE_CLIENT} -q "SYSTEM DISABLE FAILPOINT database_replicated_force_metadata_digest_check" |
| 56 | + |
| 57 | +${CLICKHOUSE_CLIENT} -q "DROP DATABASE ${DB}_renamed SYNC" 2>/dev/null || true |
| 58 | + |
| 59 | +# In a non-UUID (Ordinary) database the inner tables embed the outer table name, so renaming a |
| 60 | +# TimeSeries table renames each inner table too. Those inner renames are not transactional, so if |
| 61 | +# one destination name is already taken the rename must be rejected up front, before any inner |
| 62 | +# table is moved -- otherwise the table would be left half-renamed with an orphaned inner table. |
| 63 | +ORD="${CLICKHOUSE_DATABASE}_ord" |
| 64 | +${CLICKHOUSE_CLIENT} -q "DROP DATABASE IF EXISTS ${ORD} SYNC" |
| 65 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal --allow_deprecated_database_ordinary=1 -q "CREATE DATABASE ${ORD} ENGINE = Ordinary" |
| 66 | +${CLICKHOUSE_CLIENT} --allow_experimental_time_series_table=1 -q "CREATE TABLE ${ORD}.ts ENGINE = TimeSeries" |
| 67 | +# Occupy one of the destination inner-table names so the rename cannot complete. |
| 68 | +${CLICKHOUSE_CLIENT} -q "CREATE TABLE ${ORD}.\`.inner.tags.ts2\` (x UInt8) ENGINE = MergeTree ORDER BY x" |
| 69 | +# The rename is rejected before any inner table is moved. |
| 70 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal -q "RENAME TABLE ${ORD}.ts TO ${ORD}.ts2" 2>&1 | grep -q -F "TABLE_ALREADY_EXISTS" && echo "rejected" |
| 71 | +# Every source inner table is still present (none orphaned), so the table keeps working. |
| 72 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${ORD}.\`.inner.samples.ts\`" |
| 73 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${ORD}.\`.inner.tags.ts\`" |
| 74 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${ORD}.\`.inner.metrics.ts\`" |
| 75 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${ORD}.ts" |
| 76 | + |
| 77 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal -q "DROP DATABASE ${ORD} SYNC" 2>/dev/null || true |
| 78 | + |
| 79 | +# With lazy_load_tables=1 a reloaded TimeSeries table is materialized as a StorageTableProxy. The |
| 80 | +# proxy must not hide the TimeSeries type from the cross-database move guard -- otherwise a |
| 81 | +# cross-database RENAME would move only the outer table and orphan its inner tables in the old |
| 82 | +# database. The outer TimeSeries table is loaded eagerly so the guard sees it. |
| 83 | +LZ="${CLICKHOUSE_DATABASE}_lazy" |
| 84 | +LZ2="${CLICKHOUSE_DATABASE}_lazy2" |
| 85 | +${CLICKHOUSE_CLIENT} -q "DROP DATABASE IF EXISTS ${LZ} SYNC; DROP DATABASE IF EXISTS ${LZ2} SYNC" |
| 86 | +${CLICKHOUSE_CLIENT} -q "CREATE DATABASE ${LZ} ENGINE = Atomic SETTINGS lazy_load_tables = 1" |
| 87 | +${CLICKHOUSE_CLIENT} -q "CREATE DATABASE ${LZ2} ENGINE = Atomic" |
| 88 | +${CLICKHOUSE_CLIENT} --allow_experimental_time_series_table=1 -q "CREATE TABLE ${LZ}.ts ENGINE = TimeSeries" |
| 89 | +# Reattach so the table is recreated as a lazy proxy. |
| 90 | +${CLICKHOUSE_CLIENT} -q "DETACH DATABASE ${LZ}; ATTACH DATABASE ${LZ}" |
| 91 | +# The cross-database move is rejected before any inner table is moved. |
| 92 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal -q "RENAME TABLE ${LZ}.ts TO ${LZ2}.ts" 2>&1 | grep -q -F "Cannot move TimeSeries table with inner tables" && echo "rejected" |
| 93 | +# Every inner table stayed in the source database (none orphaned in the target). |
| 94 | +${CLICKHOUSE_CLIENT} -q "SELECT count() FROM system.tables WHERE database = '${LZ}' AND name LIKE '.inner_id.%'" |
| 95 | +${CLICKHOUSE_CLIENT} -q "SELECT count() FROM system.tables WHERE database = '${LZ2}' AND name LIKE '.inner_id.%'" |
| 96 | +${CLICKHOUSE_CLIENT} -q "EXISTS TABLE ${LZ}.ts" |
| 97 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal -q "DROP DATABASE ${LZ} SYNC" 2>/dev/null || true |
| 98 | +${CLICKHOUSE_CLIENT} --send_logs_level=fatal -q "DROP DATABASE ${LZ2} SYNC" 2>/dev/null || true |
0 commit comments