@@ -12,6 +12,7 @@ import (
1212 "regexp"
1313 "strconv"
1414 "strings"
15+ "sync"
1516 "time"
1617
1718 "github.com/Altinity/clickhouse-backup/v2/pkg/common"
@@ -31,13 +32,24 @@ import (
3132type ClickHouse struct {
3233 Config * config.ClickHouseConfig
3334 conn driver.Conn
35+ ConnMutex * sync.Mutex
3436 version int
3537 IsOpen bool
3638 BreakConnectOnError bool
3739}
3840
41+ func NewClickHouse (cfg * config.ClickHouseConfig ) * ClickHouse {
42+ return & ClickHouse {
43+ Config : cfg ,
44+ ConnMutex : & sync.Mutex {},
45+ }
46+ }
47+
3948// Connect - establish connection to ClickHouse
4049func (ch * ClickHouse ) Connect () error {
50+ ch .ConnMutex .Lock ()
51+ defer ch .ConnMutex .Unlock ()
52+
4153 if ch .IsOpen {
4254 if err := ch .conn .Close (); err != nil {
4355 log .Error ().Msgf ("close previous connection error: %v" , err )
@@ -121,20 +133,19 @@ func (ch *ClickHouse) Connect() error {
121133 break
122134 }
123135 if ch .BreakConnectOnError {
124- return err
136+ return errors . WithStack ( err )
125137 }
126138 log .Warn ().Msgf ("clickhouse connection: %s, sql.Open return error: %v, will wait 5 second to reconnect" , fmt .Sprintf ("tcp://%v:%v" , ch .Config .Host , ch .Config .Port ), err )
127139 time .Sleep (5 * time .Second )
128140 }
129- log .WithLevel (logLevel ).Msgf ("clickhouse connection prepared: %s run ping" , fmt .Sprintf ("tcp://%v:%v" , ch .Config .Host , ch .Config .Port ))
130141 err = ch .conn .Ping (context .Background ())
131142 if err == nil {
132143 log .WithLevel (logLevel ).Msgf ("clickhouse connection success: %s" , fmt .Sprintf ("tcp://%v:%v" , ch .Config .Host , ch .Config .Port ))
133144 ch .IsOpen = true
134145 break
135146 }
136147 if ch .BreakConnectOnError {
137- return err
148+ return errors . WithStack ( err )
138149 }
139150 log .Warn ().Msgf ("clickhouse connection ping: %s return error: %v, will wait 5 second to reconnect" , fmt .Sprintf ("tcp://%v:%v" , ch .Config .Host , ch .Config .Port ), err )
140151 time .Sleep (5 * time .Second )
@@ -551,22 +562,19 @@ func (ch *ClickHouse) GetDatabases(ctx context.Context, cfg *config.Config, tabl
551562 if tablePattern != "" {
552563 bypassTablesPatterns = append (bypassTablesPatterns , strings .Split (tablePattern , "," )... )
553564 }
554- for _ , pattern := range skipTablesPatterns {
555- pattern = strings .Trim (pattern , " \r \t \n " )
556- if strings .HasSuffix (pattern , ".*" ) {
557- skipDatabases = common .AddStringToSliceIfNotExists (skipDatabases , strings .Trim (strings .TrimSuffix (pattern , ".*" ), "\" ` " ))
558- } else {
559- skipDatabases = common .AddStringToSliceIfNotExists (skipDatabases , strings .Trim (tableNameSuffixRE .ReplaceAllString (pattern , "" ), "\" ` " ))
560- }
561- }
562- for _ , pattern := range bypassTablesPatterns {
563- pattern = strings .Trim (pattern , " \r \t \n " )
564- if strings .HasSuffix (pattern , ".*" ) {
565- bypassDatabases = common .AddStringToSliceIfNotExists (bypassDatabases , strings .Trim (strings .TrimSuffix (pattern , ".*" ), "\" ` " ))
566- } else {
567- bypassDatabases = common .AddStringToSliceIfNotExists (bypassDatabases , strings .Trim (tableNameSuffixRE .ReplaceAllString (pattern , "" ), "\" ` " ))
565+ processDbPatterns := func (databases []string , patterns []string ) []string {
566+ for _ , pattern := range patterns {
567+ pattern = strings .Trim (pattern , " \r \t \n " )
568+ if strings .HasSuffix (pattern , ".*" ) {
569+ databases = common .AddStringToSliceIfNotExists (databases , strings .Trim (strings .TrimSuffix (pattern , ".*" ), "\" ` " ))
570+ } else {
571+ databases = common .AddStringToSliceIfNotExists (databases , strings .Trim (tableNameSuffixRE .ReplaceAllString (pattern , "" ), "\" ` " ))
572+ }
568573 }
574+ return databases
569575 }
576+ skipDatabases = processDbPatterns (skipDatabases , skipTablesPatterns )
577+ bypassDatabases = processDbPatterns (bypassDatabases , bypassTablesPatterns )
570578 metadataPath , err := ch .getMetadataPath (ctx )
571579 if err != nil {
572580 return nil , err
@@ -608,12 +616,14 @@ func (ch *ClickHouse) GetDatabases(ctx context.Context, cfg *config.Config, tabl
608616 } else {
609617 // 23.3+ masked secrets https://github.com/Altinity/clickhouse-backup/issues/640
610618 if strings .Contains (result , "'[HIDDEN]'" ) {
611- if attachSQL , err := os .ReadFile (path .Join (metadataPath , common .TablePathEncode (db .Name )+ ".sql" )); err != nil {
612- return nil , err
613- } else {
614- result = strings .Replace (string (attachSQL ), "ATTACH" , "CREATE" , 1 )
615- result = strings .Replace (result , " _ " , " `" + db .Name + "` " , 1 )
619+ var attachSQL []byte
620+ var readErr error
621+ if attachSQL , readErr = os .ReadFile (path .Join (metadataPath , common .TablePathEncode (db .Name )+ ".sql" )); readErr != nil {
622+ return nil , errors .WithStack (readErr )
616623 }
624+
625+ result = strings .Replace (string (attachSQL ), "ATTACH" , "CREATE" , 1 )
626+ result = strings .Replace (result , " _ " , " `" + db .Name + "` " , 1 )
617627 }
618628 allDatabases [i ].Query = result
619629 }
@@ -951,9 +961,12 @@ func (ch *ClickHouse) DropOrDetachTable(table Table, query, onCluster string, ig
951961 dropQuery += " SETTINGS check_table_dependencies=0"
952962 }
953963 if defaultDataPath != "" && ! useDetach {
954- if _ , err = os .Create (path .Join (defaultDataPath , "/flags/force_drop_table" )); err != nil {
955- return err
964+ var f * os.File
965+ var createErr error
966+ if f , createErr = os .Create (path .Join (defaultDataPath , "/flags/force_drop_table" )); createErr != nil {
967+ return errors .WithStack (createErr )
956968 }
969+ _ = f .Close ()
957970 }
958971 if err = ch .Query (dropQuery ); err != nil {
959972 return err
@@ -1371,10 +1384,9 @@ func (ch *ClickHouse) CheckReplicationInProgress(table metadata.TableMetadata) (
13711384 }
13721385 // https://github.com/Altinity/clickhouse-backup/issues/967
13731386 if existsReplicas [0 ].LogPointer > 2 || existsReplicas [0 ].LogMaxIndex > 1 || existsReplicas [0 ].AbsoluteDelay > 0 || existsReplicas [0 ].QueueSize > 0 {
1374- return false , fmt .Errorf ("%s.%s can't restore cause system.replicas entries already exists and replication in progress from another replica, log_pointer=%d, log_max_index=%d, absolute_delay=%d, queue_size=%d" , table .Database , table .Table , existsReplicas [0 ].LogPointer , existsReplicas [0 ].LogMaxIndex , existsReplicas [0 ].AbsoluteDelay , existsReplicas [0 ].QueueSize )
1375- } else {
1376- log .Info ().Msgf ("replication_in_progress status = %+v" , existsReplicas )
1387+ return false , errors .WithStack (fmt .Errorf ("%s.%s can't restore cause system.replicas entries already exists and replication in progress from another replica, log_pointer=%d, log_max_index=%d, absolute_delay=%d, queue_size=%d" , table .Database , table .Table , existsReplicas [0 ].LogPointer , existsReplicas [0 ].LogMaxIndex , existsReplicas [0 ].AbsoluteDelay , existsReplicas [0 ].QueueSize ))
13771388 }
1389+ log .Info ().Msgf ("replication_in_progress status = %+v" , existsReplicas )
13781390 }
13791391 return true , nil
13801392}
0 commit comments