11package handle
22
33import (
4+ "fmt"
5+ "regexp"
46 "strings"
57
68 "github.com/selectdb/ccr_syncer/pkg/ccr"
@@ -18,6 +20,70 @@ type CreateTableHandle struct {
1820 IdempotentJobHandle [* record.CreateTable ]
1921}
2022
23+ // Check if error message indicates storage medium or capacity related issues
24+ func isStorageMediumError (errMsg string ) bool {
25+ // Doris returns "Failed to find enough backend" for storage/capacity issues
26+ return strings .Contains (strings .ToLower (errMsg ), "failed to find enough backend" )
27+ }
28+
29+ // Set specific property in CREATE TABLE SQL
30+ func setPropertyInCreateTableSql (createSql string , key string , value string ) string {
31+ // Add property to PROPERTIES clause
32+ pattern := `(?i)(PROPERTIES\s*\(\s*)`
33+ replacement := fmt .Sprintf (`${1}"%s" = "%s", ` , key , value )
34+ createSql = regexp .MustCompile (pattern ).ReplaceAllString (createSql , replacement )
35+
36+ // Clean up trailing comma if PROPERTIES was empty
37+ return ccr .FilterTailingCommaFromCreateTableSql (createSql )
38+ }
39+
40+ // Set specific storage_medium in CREATE TABLE SQL
41+ func setStorageMediumInCreateTableSql (createSql string , medium string ) string {
42+ // Remove existing storage_medium first
43+ createSql = ccr .FilterStorageMediumFromCreateTableSql (createSql )
44+ return setPropertyInCreateTableSql (createSql , "storage_medium" , medium )
45+ }
46+
47+ // Set specific medium_allocation_mode in CREATE TABLE SQL
48+ func setMediumAllocationModeInCreateTableSql (createSql string , mode string ) string {
49+ // Remove existing medium_allocation_mode first
50+ createSql = ccr .FilterMediumAllocationModeFromCreateTableSql (createSql )
51+ return setPropertyInCreateTableSql (createSql , "medium_allocation_mode" , mode )
52+ }
53+
54+ // Process CREATE TABLE SQL according to storage medium policy
55+ func processCreateTableSqlByMediumPolicy (j * ccr.Job , createTable * record.CreateTable ) {
56+ storageMedium := j .StorageMedium
57+ mediumAllocationMode := j .MediumAllocationMode
58+
59+ // Process storage_medium
60+ switch storageMedium {
61+ case ccr .StorageMediumSameWithUpstream :
62+ // Keep upstream storage_medium unchanged
63+ log .Infof ("using same_with_upstream storage medium, keeping original storage_medium" )
64+
65+ case ccr .StorageMediumHDD :
66+ log .Infof ("using hdd storage medium, setting storage_medium to hdd" )
67+ createTable .Sql = setStorageMediumInCreateTableSql (createTable .Sql , "hdd" )
68+
69+ case ccr .StorageMediumSSD :
70+ log .Infof ("using ssd storage medium, setting storage_medium to ssd" )
71+ createTable .Sql = setStorageMediumInCreateTableSql (createTable .Sql , "ssd" )
72+
73+ default :
74+ log .Warnf ("unknown storage medium: %s, falling back to filter storage_medium" , storageMedium )
75+ if ccr .FeatureFilterStorageMedium {
76+ createTable .Sql = ccr .FilterStorageMediumFromCreateTableSql (createTable .Sql )
77+ }
78+ }
79+
80+ // Process medium_allocation_mode from CCR job parameter
81+ if mediumAllocationMode != "" {
82+ log .Infof ("setting medium_allocation_mode to %s" , mediumAllocationMode )
83+ createTable .Sql = setMediumAllocationModeInCreateTableSql (createTable .Sql , mediumAllocationMode )
84+ }
85+ }
86+
2187func (h * CreateTableHandle ) Handle (j * ccr.Job , commitSeq int64 , createTable * record.CreateTable ) error {
2288 if j .SyncType != ccr .DBSync {
2389 return xerror .Errorf (xerror .Normal , "invalid sync type: %v" , j .SyncType )
@@ -68,9 +134,8 @@ func (h *CreateTableHandle) Handle(j *ccr.Job, commitSeq int64, createTable *rec
68134 }
69135 }
70136
71- if ccr .FeatureFilterStorageMedium {
72- createTable .Sql = ccr .FilterStorageMediumFromCreateTableSql (createTable .Sql )
73- }
137+ // Process SQL according to storage medium policy
138+ processCreateTableSqlByMediumPolicy (j , createTable )
74139 createTable .Sql = ccr .FilterDynamicPartitionStoragePolicyFromCreateTableSql (createTable .Sql )
75140
76141 if ccr .FeatureOverrideReplicationNum () && j .ReplicationNum > 0 {
@@ -79,26 +144,49 @@ func (h *CreateTableHandle) Handle(j *ccr.Job, commitSeq int64, createTable *rec
79144
80145 if err := j .IDest .CreateTableOrView (createTable , j .Src .Database ); err != nil {
81146 errMsg := err .Error ()
147+
148+ // Skip unsupported features
82149 if strings .Contains (errMsg , "Can not found function" ) {
83150 log .Warnf ("skip creating table/view because the UDF function is not supported yet: %s" , errMsg )
84151 return nil
85- } else if strings .Contains (errMsg , "Can not find resource" ) {
152+ }
153+ if strings .Contains (errMsg , "Can not find resource" ) {
86154 log .Warnf ("skip creating table/view for the resource is not supported yet: %s" , errMsg )
87155 return nil
88- } else if createTable .IsCreateView () && strings .Contains (errMsg , "Unknown column" ) {
156+ }
157+
158+ // Trigger partial snapshot for recoverable errors
159+ if createTable .IsCreateView () && strings .Contains (errMsg , "Unknown column" ) {
89160 log .Warnf ("create view but the column is not found, trigger partial snapshot, commit seq: %d, msg: %s" ,
90161 commitSeq , errMsg )
91162 replace := false // new view no need to replace
92163 isView := true
93164 return j .NewPartialSnapshot (createTable .TableId , createTable .TableName , nil , replace , isView )
94165 }
95- if len (createTable .TableName ) > 0 && ccr .IsSessionVariableRequired (errMsg ) { // ignore doris 2.0.3
166+ if len (createTable .TableName ) > 0 && ccr .IsSessionVariableRequired (errMsg ) {
96167 log .Infof ("a session variable is required to create table %s, force partial snapshot, commit seq: %d, msg: %s" ,
97168 createTable .TableName , commitSeq , errMsg )
98169 replace := false // new table no need to replace
99170 isView := false
100171 return j .NewPartialSnapshot (createTable .TableId , createTable .TableName , nil , replace , isView )
101172 }
173+
174+ // Storage medium related error: pause job and require manual intervention
175+ if isStorageMediumError (errMsg ) {
176+ log .Errorf ("create table %s failed due to storage medium issue, job will be paused. " +
177+ "Current storage_medium=%s. Please check target cluster resources or update storage_medium via API. Error: %s" ,
178+ createTable .TableName , j .StorageMedium , errMsg )
179+ return xerror .Panicf (xerror .Normal ,
180+ "Create table failed: storage medium issue for table %s. " +
181+ "Current storage_medium=%s. Possible causes:\n " +
182+ "1. Storage medium (%s) not available on target cluster\n " +
183+ "2. Insufficient disk capacity\n " +
184+ "3. Replication number exceeds available BE nodes\n " +
185+ "Please check target cluster configuration or update storage_medium via /update_storage_medium API. " +
186+ "Original error: %s" ,
187+ createTable .TableName , j .StorageMedium , j .StorageMedium , errMsg )
188+ }
189+
102190 return xerror .Wrapf (err , xerror .Normal , "create table %d" , createTable .TableId )
103191 }
104192
0 commit comments