@@ -838,10 +838,12 @@ func doOneImport(task *SplitFileImportTask, connPool *tgtdb.ConnectionPool) {
838
838
839
839
// copyCommand is empty when there are no rows for that table
840
840
if copyCommand != "" {
841
- var rowsCount int64
841
+ copyCommand = fmt .Sprintf (copyCommand , (task .OffsetEnd - task .OffsetStart ))
842
+ log .Infof ("COPY command: %s" , copyCommand )
843
+ var rowsAffected int64
842
844
var copyErr error
843
845
// if retry=n, total try call will be n+1
844
- copyRetryCount := COPY_MAX_RETRY_COUNT + 1
846
+ remainingRetries := COPY_MAX_RETRY_COUNT + 1
845
847
846
848
copyErr = connPool .WithConn (func (conn * pgx.Conn ) (bool , error ) {
847
849
// reset the reader to begin for every call
@@ -855,39 +857,44 @@ func doOneImport(task *SplitFileImportTask, connPool *tgtdb.ConnectionPool) {
855
857
}
856
858
}
857
859
res , err := conn .PgConn ().CopyFrom (context .Background (), reader , copyCommand )
858
- rowsCount = res .RowsAffected ()
860
+ rowsAffected = res .RowsAffected ()
859
861
862
+ if err != nil && utils .InsensitiveSliceContains (NonRetryCopyErrors , err .Error ()) {
863
+ return false , err
864
+ }
865
+
866
+ /*
867
+ Note: If a user retries after deleting some row(s) from a batch,
868
+ yb-voyager will never be able to mark the batch as completed
869
+ github issue: https://github.com/yugabyte/yb-voyager/issues/223
870
+ */
860
871
if err != nil {
861
872
log .Warnf ("COPY FROM file %q: %s" , inProgressFilePath , err )
862
- if ! strings .Contains (err .Error (), "violates unique constraint" ) {
863
- log .Errorf ("RETRYING.. COPY %q FROM file %q due to encountered error: %v " , task .TableName , inProgressFilePath , err )
864
- duration := time .Duration (math .Min (MAX_SLEEP_SECOND , math .Pow (2 , float64 (COPY_MAX_RETRY_COUNT + 1 - copyRetryCount ))))
865
- log .Infof ("sleep for duration %d before retrying..." , duration )
866
- time .Sleep (time .Second * duration ) // delay for 1 sec before retrying
867
- copyRetryCount --
868
- return copyRetryCount > 0 , err
873
+ log .Errorf ("RETRYING.. COPY %q FROM file %q due to encountered error: %v " , task .TableName , inProgressFilePath , err )
874
+
875
+ remainingRetries --
876
+ if remainingRetries > 0 {
877
+ retryNum := COPY_MAX_RETRY_COUNT + 1 - remainingRetries
878
+ duration := time .Duration (math .Min (MAX_SLEEP_SECOND , 10 * float64 (retryNum )))
879
+ log .Infof ("sleep for duration %d before retrying the file %s for %d time..." ,
880
+ duration , inProgressFilePath , retryNum )
881
+ time .Sleep (time .Second * duration )
869
882
}
883
+ return remainingRetries > 0 , err
870
884
}
871
885
872
886
return false , err
873
887
})
874
888
875
- log .Infof ("%q => %d rows affected" , copyCommand , rowsCount )
889
+ log .Infof ("%q => %d rows affected" , copyCommand , rowsAffected )
876
890
if copyErr != nil {
877
- log .Warnf ("COPY FROM file %q: %s" , inProgressFilePath , copyErr )
878
- if ! strings .Contains (copyErr .Error (), "violates unique constraint" ) {
891
+ if ! disableTransactionalWrites && strings .Contains (copyErr .Error (), "violates unique constraint" ) {
892
+ log .Infof ("Ignoring encountered Error: %v, Assuming batch is already imported due to transactional mode" , copyErr )
893
+ } else {
879
894
utils .ErrExit ("COPY %q FROM file %q: %s" , task .TableName , inProgressFilePath , copyErr )
880
- } else { //in case of unique key violation error take row count from the split task
881
- rowsCount = task .OffsetEnd - task .OffsetStart
882
- log .Infof ("got error:%v, assuming affected rows count %v for %q" , copyErr , rowsCount , task .TableName )
883
895
}
884
896
}
885
897
886
- if rowsCount != task .OffsetEnd - task .OffsetStart {
887
- // TODO: print info/details about missed rows on the screen after progress bar is complete
888
- log .Warnf ("Expected to import %v records from %s. Imported %v." ,
889
- task .OffsetEnd - task .OffsetStart , inProgressFilePath , rowsCount )
890
- }
891
898
incrementImportProgressBar (task .TableName , inProgressFilePath )
892
899
}
893
900
doneFilePath := getDoneFilePath (task )
@@ -1001,6 +1008,7 @@ func extractCopyStmtForTable(table string, fileToSearchIn string) {
1001
1008
utils .ErrExit ("error while readline for extraction of copy stmt from file %q: %v" , fileToSearchIn , err )
1002
1009
}
1003
1010
if copyCommandRegex .MatchString (line ) {
1011
+ line = strings .Trim (line , ";" ) + ` WITH (ROWS_PER_TRANSACTION %v)`
1004
1012
copyTableFromCommands [table ] = line
1005
1013
log .Infof ("copyTableFromCommand for table %q is %q" , table , line )
1006
1014
return
@@ -1038,43 +1046,75 @@ func getProgressAmount(filePath string) int64 {
1038
1046
}
1039
1047
1040
1048
func getYBSessionInitScript () []string {
1041
- sessionVarsPath := "/etc/yb-voyager/ybSessionVariables.sql"
1042
1049
var sessionVars []string
1043
- disableTransactionalWritesCmd := fmt .Sprintf ("SET yb_disable_transactional_writes to %v" , disableTransactionalWrites )
1044
- enableUpsertCmd := fmt .Sprintf ("SET yb_enable_upsert_mode to %v" , enableUpsert )
1045
- defaultSessionVars := []string {
1046
- "SET client_encoding to 'UTF-8'" ,
1047
- "SET session_replication_role to replica" ,
1048
- disableTransactionalWritesCmd ,
1049
- enableUpsertCmd ,
1050
+ if checkSessionVariableSupport (SET_CLIENT_ENCODING_TO_UTF8 ) {
1051
+ sessionVars = append (sessionVars , SET_CLIENT_ENCODING_TO_UTF8 )
1052
+ }
1053
+ if checkSessionVariableSupport (SET_SESSION_REPLICATE_ROLE_TO_REPLICA ) {
1054
+ sessionVars = append (sessionVars , SET_SESSION_REPLICATE_ROLE_TO_REPLICA )
1050
1055
}
1051
1056
1057
+ if enableUpsert {
1058
+ // upsert_mode parameters was introduced later than yb_disable_transactional writes in yb releases
1059
+ // hence if upsert_mode is supported then its safe to assume yb_disable_transactional_writes is already there
1060
+ if checkSessionVariableSupport (SET_YB_ENABLE_UPSERT_MODE ) {
1061
+ sessionVars = append (sessionVars , SET_YB_ENABLE_UPSERT_MODE )
1062
+ // SET_YB_DISABLE_TRANSACTIONAL_WRITES is used only with & if upsert_mode is supported
1063
+ if disableTransactionalWrites {
1064
+ if checkSessionVariableSupport (SET_YB_DISABLE_TRANSACTIONAL_WRITES ) {
1065
+ sessionVars = append (sessionVars , SET_YB_DISABLE_TRANSACTIONAL_WRITES )
1066
+ } else {
1067
+ disableTransactionalWrites = false
1068
+ }
1069
+ }
1070
+ } else {
1071
+ log .Infof ("Falling back to transactional inserts of batches during data import" )
1072
+ }
1073
+ }
1074
+
1075
+ sessionVarsPath := "/etc/yb-voyager/ybSessionVariables.sql"
1052
1076
if ! utils .FileOrFolderExists (sessionVarsPath ) {
1053
- return defaultSessionVars
1077
+ log .Infof ("YBSessionInitScript: %v\n " , sessionVars )
1078
+ return sessionVars
1054
1079
}
1055
1080
1056
1081
varsFile , err := os .Open (sessionVarsPath )
1057
1082
if err != nil {
1058
1083
utils .PrintAndLog ("Unable to open %s : %v. Using default values." , sessionVarsPath , err )
1059
- return defaultSessionVars
1084
+ log .Infof ("YBSessionInitScript: %v\n " , sessionVars )
1085
+ return sessionVars
1060
1086
}
1061
1087
defer varsFile .Close ()
1062
1088
fileScanner := bufio .NewScanner (varsFile )
1063
1089
1064
1090
var curLine string
1065
1091
for fileScanner .Scan () {
1066
1092
curLine = strings .TrimSpace (fileScanner .Text ())
1067
- sessionVars = append (sessionVars , curLine )
1093
+ if curLine != "" && checkSessionVariableSupport (curLine ) {
1094
+ sessionVars = append (sessionVars , curLine )
1095
+ }
1068
1096
}
1097
+ log .Infof ("YBSessionInitScript: %v\n " , sessionVars )
1098
+ return sessionVars
1099
+ }
1069
1100
1070
- //Only override the file if the flags are explicitly true (default false)
1071
- if enableUpsert {
1072
- sessionVars = append (sessionVars , enableUpsertCmd )
1101
+ func checkSessionVariableSupport (sqlStmt string ) bool {
1102
+ conn , err := pgx .Connect (context .Background (), target .GetConnectionUri ())
1103
+ if err != nil {
1104
+ utils .ErrExit ("error while creating connection for checking session parameter(%q) support: %v" , sqlStmt , err )
1073
1105
}
1074
- if disableTransactionalWrites {
1075
- sessionVars = append (sessionVars , disableTransactionalWritesCmd )
1106
+ defer conn .Close (context .Background ())
1107
+
1108
+ _ , err = conn .Exec (context .Background (), sqlStmt )
1109
+ if err != nil {
1110
+ if ! strings .Contains (err .Error (), "unrecognized configuration parameter" ) {
1111
+ utils .ErrExit ("error while executing sqlStatement=%q: %v" , sqlStmt , err )
1112
+ } else {
1113
+ log .Warnf ("Warning: %q is not supported: %v" , sqlStmt , err )
1114
+ }
1076
1115
}
1077
- return sessionVars
1116
+
1117
+ return err == nil
1078
1118
}
1079
1119
1080
1120
func removeExcludeTables (tableList []string , excludeTableList []string ) []string {
0 commit comments