Skip to content

Commit e684c63

Browse files
committed
check system.clusters during restore engine=Distributed and is not exists and if not macros use CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER config parameter as cluster value, fix #1252
Signed-off-by: Slach <[email protected]>
1 parent aa33df3 commit e684c63

File tree

5 files changed

+102
-4
lines changed

5 files changed

+102
-4
lines changed

ChangeLog.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
# v2.6.38
2+
BUG FIXES
3+
- check `system.clusters` during restore `engine=Distributed` and is not exists and if not macros use `CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER` config parameter as cluster value, fix [1252](https://github.com/Altinity/clickhouse-backup/issues/1252)
4+
15
# v2.6.37
26
BUG FIXES
37
- fix slowdown and corner cases, for incremental backup creation, affected 2.6.30+, fix https://github.com/Altinity/clickhouse-backup/issues/1249
48

59
# v2.6.36
610
IMPROVEMENTS
7-
- add `GCS_SA_EMAIL` option to support service account authorization, fix [1246](https://github.com/Altinity/clickhouse-backup/pull/1246) thanks @kamushadenes
11+
- add `GCS_SA_EMAIL` option to support service account authorization, fix [1173](https://github.com/Altinity/clickhouse-backup/issues/1173) thanks @kamushadenes
812
- improve `--hardlink-exists-files` behavior, will look to exists local backups for the same part to avoid download unnecessary, fix [1244](https://github.com/Altinity/clickhouse-backup/issues/1244)
913
- add `S3_CHUNK_SIZE` option to allow more flexible workload for S3-compatible remote storage, fix [1248](https://github.com/Altinity/clickhouse-backup/pull/1248) thanks @KimDoKy
1014

ReadMe.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ clickhouse:
215215
embedded_backup_disk: "" # CLICKHOUSE_EMBEDDED_BACKUP_DISK - disk from system.disks which will use when `use_embedded_backup_restore: true`
216216
backup_mutations: true # CLICKHOUSE_BACKUP_MUTATIONS, allow backup mutations from system.mutations WHERE is_done=0 and apply it during restore
217217
restore_as_attach: false # CLICKHOUSE_RESTORE_AS_ATTACH, allow restore tables which have inconsistent data parts structure and mutations in progress
218+
restore_distributed_cluster: "" # CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER, cluster name (can use macros) which will use during restore `engine=Distributed` tables, when cluster defined in backup table definition not exists in `system.clusters`
218219
check_parts_columns: true # CLICKHOUSE_CHECK_PARTS_COLUMNS, check data types from system.parts_columns during create backup to guarantee mutation is complete
219220
max_connections: 0 # CLICKHOUSE_MAX_CONNECTIONS, how many parallel connections could be opened during operations
220221
azblob:

pkg/clickhouse/clickhouse.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,7 @@ var attachViewRe = regexp.MustCompile(`(?im)^(ATTACH[\s\w]+VIEW[^(]+)(\s+AS\s+.+
972972
var createObjRe = regexp.MustCompile(`(?is)^(CREATE [^(]+)(\(.+)`)
973973
var onClusterRe = regexp.MustCompile(`(?im)\s+ON\s+CLUSTER\s+`)
974974
var distributedRE = regexp.MustCompile(`(Distributed)\(([^,]+),([^)]+)\)`)
975+
var macroRE = regexp.MustCompile(`(?i){[a-z0-9-_]+}`)
975976

976977
// CreateTable - create ClickHouse table
977978
func (ch *ClickHouse) CreateTable(table Table, query string, dropTable, ignoreDependencies bool, onCluster string, version int, defaultDataPath string, asAttach bool, databaseEngine string) error {
@@ -1019,11 +1020,22 @@ func (ch *ClickHouse) CreateTable(table Table, query string, dropTable, ignoreDe
10191020
}
10201021

10211022
// https://github.com/Altinity/clickhouse-backup/issues/574, replace ENGINE=Distributed to new cluster name
1022-
if onCluster != "" && distributedRE.MatchString(query) {
1023+
// https://github.com/Altinity/clickhouse-backup/issues/1252, check exists
1024+
if distributedRE.MatchString(query) {
10231025
matches := distributedRE.FindAllStringSubmatch(query, -1)
1024-
newCluster := onCluster
10251026
oldCluster := strings.Trim(matches[0][2], "'\" ")
1026-
if newCluster != oldCluster && !strings.Contains(oldCluster, "{cluster}") {
1027+
newCluster := onCluster
1028+
var existCluster string
1029+
if newCluster == "" && !macroRE.MatchString(oldCluster) {
1030+
if err = ch.SelectSingleRowNoCtx(&existCluster, "SELECT cluster FROM system.clusters WHERE cluster=?", oldCluster); err != nil {
1031+
return fmt.Errorf("check system.clusters for %s return error: %v", oldCluster, err)
1032+
}
1033+
if existCluster == "" {
1034+
newCluster = strings.Trim(ch.Config.RestoreDistributedCluster, "'\" ")
1035+
}
1036+
}
1037+
if newCluster != "" && existCluster == "" && newCluster != oldCluster && !macroRE.MatchString(oldCluster) {
1038+
newCluster = "'" + strings.Trim(ch.Config.RestoreDistributedCluster, "'\" ") + "'"
10271039
log.Warn().Msgf("will replace cluster ENGINE=Distributed %s -> %s", matches[0][2], newCluster)
10281040
query = distributedRE.ReplaceAllString(query, fmt.Sprintf("${1}(%s,${3})", newCluster))
10291041
}

pkg/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ type ClickHouseConfig struct {
233233
EmbeddedBackupDisk string `yaml:"embedded_backup_disk" envconfig:"CLICKHOUSE_EMBEDDED_BACKUP_DISK"`
234234
BackupMutations bool `yaml:"backup_mutations" envconfig:"CLICKHOUSE_BACKUP_MUTATIONS"`
235235
RestoreAsAttach bool `yaml:"restore_as_attach" envconfig:"CLICKHOUSE_RESTORE_AS_ATTACH"`
236+
RestoreDistributedCluster string `yaml:"restore_distributed_cluster" envconfig:"CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER"`
236237
CheckPartsColumns bool `yaml:"check_parts_columns" envconfig:"CLICKHOUSE_CHECK_PARTS_COLUMNS"`
237238
Secure bool `yaml:"secure" envconfig:"CLICKHOUSE_SECURE"`
238239
SkipVerify bool `yaml:"skip_verify" envconfig:"CLICKHOUSE_SKIP_VERIFY"`

test/integration/integration_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,86 @@ func TestRestoreAsAttach(t *testing.T) {
28662866
env.Cleanup(t, r)
28672867
}
28682868

2869+
func TestRestoreDistributedCluster(t *testing.T) {
2870+
env, r := NewTestEnvironment(t)
2871+
env.connectWithWait(t, r, 0*time.Second, 1*time.Second, 1*time.Minute)
2872+
xml := `
2873+
<yandex>
2874+
<remote_servers>
2875+
<new_cluster>
2876+
<shard>
2877+
<internal_replication>true</internal_replication>
2878+
<replica>
2879+
<host>127.0.0.1</host>
2880+
<port>9000</port>
2881+
</replica>
2882+
</shard>
2883+
</new_cluster>
2884+
</remote_servers>
2885+
</yandex>
2886+
`
2887+
2888+
env.DockerExecNoError(r, "clickhouse", "bash", "-c", fmt.Sprintf("echo -n '%s' > /etc/clickhouse-server/config.d/new-cluster.xml", xml))
2889+
var clusterExists string
2890+
for i := 0; i < 10 && clusterExists == ""; i++ {
2891+
r.NoError(env.ch.SelectSingleRowNoCtx(&clusterExists, "SELECT cluster FROM system.clusters WHERE cluster='new_cluster'"))
2892+
if clusterExists == "new_cluster" {
2893+
break
2894+
}
2895+
time.Sleep(1 * time.Second)
2896+
}
2897+
r.Equal("new_cluster", clusterExists)
2898+
2899+
// Create test database and table
2900+
dbName := "test_restore_distributed_cluster"
2901+
tableName := "test_table"
2902+
env.queryWithNoError(r, "CREATE DATABASE IF NOT EXISTS "+dbName)
2903+
env.queryWithNoError(r, "CREATE TABLE "+dbName+"."+tableName+" (id UInt64, value String) ENGINE=MergeTree() ORDER BY id")
2904+
env.queryWithNoError(r, "CREATE TABLE "+dbName+"."+tableName+"_dist (id UInt64, value String) ENGINE=Distributed('new_cluster',"+dbName+","+tableName+")")
2905+
env.queryWithNoError(r, "INSERT INTO "+dbName+"."+tableName+"_dist SELECT number, toString(number) FROM numbers(100)")
2906+
2907+
// Create backup
2908+
backupName := "test_restore_distributed_cluster"
2909+
env.DockerExecNoError(r, "clickhouse-backup", "clickhouse-backup", "create", "-c", "/etc/clickhouse-backup/config-s3.yml", "--tables="+dbName+".*", backupName)
2910+
2911+
// Get row count before dropping
2912+
var rowCount uint64
2913+
r.NoError(env.ch.SelectSingleRowNoCtx(&rowCount, "SELECT count() FROM "+dbName+"."+tableName+"_dist"))
2914+
r.Equal(uint64(100), rowCount)
2915+
2916+
// Drop table and database
2917+
r.NoError(env.dropDatabase(dbName, false))
2918+
2919+
// remove cluster and wait configuration reload
2920+
env.DockerExecNoError(r, "clickhouse", "bash", "-c", "rm -rfv /etc/clickhouse-server/config.d/new-cluster.xml")
2921+
newClusterExists := uint64(1)
2922+
for i := 0; i < 10 && newClusterExists == 1; i++ {
2923+
r.NoError(env.ch.SelectSingleRowNoCtx(&newClusterExists, "SELECT count() FROM system.clusters WHERE cluster='new_cluster'"))
2924+
if newClusterExists == 0 {
2925+
break
2926+
}
2927+
time.Sleep(1 * time.Second)
2928+
}
2929+
r.Equal(uint64(0), newClusterExists)
2930+
2931+
// Restore using CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER
2932+
env.DockerExecNoError(r, "clickhouse-backup", "bash", "-c", "RESTORE_SCHEMA_ON_CLUSTER='' CLICKHOUSE_RESTORE_DISTRIBUTED_CLUSTER={cluster} clickhouse-backup -c /etc/clickhouse-backup/config-s3.yml restore "+backupName)
2933+
2934+
// Verify data was restored correctly
2935+
r.NoError(env.ch.SelectSingleRowNoCtx(&rowCount, "SELECT count() FROM "+dbName+"."+tableName+"_dist"))
2936+
r.Equal(uint64(100), rowCount)
2937+
var tableDDL string
2938+
r.NoError(env.ch.SelectSingleRowNoCtx(&tableDDL, "SHOW CREATE TABLE "+dbName+"."+tableName+"_dist"))
2939+
r.NotContains(tableDDL, "new_cluster")
2940+
r.Contains(tableDDL, "Distributed('{cluster}'")
2941+
2942+
// Clean up
2943+
r.NoError(env.dropDatabase(dbName, false))
2944+
env.DockerExecNoError(r, "clickhouse-backup", "clickhouse-backup", "-c", "/etc/clickhouse-backup/config-s3.yml", "delete", "local", backupName)
2945+
2946+
env.Cleanup(t, r)
2947+
}
2948+
28692949
func TestReplicatedCopyToDetached(t *testing.T) {
28702950
env, r := NewTestEnvironment(t)
28712951
env.connectWithWait(t, r, 0*time.Second, 1*time.Second, 1*time.Minute)

0 commit comments

Comments
 (0)