@@ -16,7 +16,6 @@ import (
16
16
sql "github.com/actiontech/dtle/driver/mysql/sql"
17
17
"github.com/actiontech/dtle/g"
18
18
gomysql "github.com/go-mysql-org/go-mysql/mysql"
19
- "github.com/hashicorp/go-hclog"
20
19
"github.com/pkg/errors"
21
20
uuid "github.com/satori/go.uuid"
22
21
)
@@ -62,6 +61,8 @@ type ApplierIncr struct {
62
61
63
62
wg sync.WaitGroup
64
63
SkipGtidExecutedTable bool
64
+ logTxCommit bool
65
+ noBigTxDMLPipe bool
65
66
66
67
mtsManager * MtsManager
67
68
wsManager * WritesetManager
@@ -71,8 +72,9 @@ type ApplierIncr struct {
71
72
sourceType string
72
73
tableSpecs []* common.TableSpec
73
74
74
- inBigTx bool
75
- logTxCommit bool
75
+ inBigTx bool
76
+ bigTxEventQueue chan * dmlExecItem
77
+ bigTxEventWg sync.WaitGroup
76
78
}
77
79
78
80
func NewApplierIncr (applier * Applier , sourcetype string ) (* ApplierIncr , error ) {
@@ -94,6 +96,7 @@ func NewApplierIncr(applier *Applier, sourcetype string) (*ApplierIncr, error) {
94
96
gtidSetLock : applier .gtidSetLock ,
95
97
tableItems : make (mapSchemaTableItems ),
96
98
sourceType : sourcetype ,
99
+ bigTxEventQueue : make (chan * dmlExecItem , 16 ),
97
100
}
98
101
99
102
if g .EnvIsTrue (g .ENV_SKIP_GTID_EXECUTED_TABLE ) {
@@ -103,6 +106,10 @@ func NewApplierIncr(applier *Applier, sourcetype string) (*ApplierIncr, error) {
103
106
if g .EnvIsTrue (g .ENV_DTLE_LOG_TX_COMMIT ) {
104
107
a .logTxCommit = true
105
108
}
109
+ if g .EnvIsTrue (g .ENV_DTLE_NO_BIG_TX_DML_PIPE ) {
110
+ a .logger .Info ("found DTLE_NO_BIG_TX_DML_PIPE" )
111
+ a .noBigTxDMLPipe = true
112
+ }
106
113
107
114
a .timestampCtx = NewTimestampContext (a .shutdownCh , a .logger , func () bool {
108
115
return len (a .binlogEntryQueue ) == 0 && len (a .applyBinlogMtsTxQueue ) == 0
@@ -186,11 +193,32 @@ func (a *ApplierIncr) Run() (err error) {
186
193
return nil
187
194
}
188
195
196
+ func (a * ApplierIncr ) bigTxQueueExecutor () {
197
+ for {
198
+ item := <- a .bigTxEventQueue
199
+ if item == nil {
200
+ break
201
+ }
202
+
203
+ if ! a .HasShutdown () {
204
+ err := a .prepareIfNilAndExecute (item , 0 )
205
+ if err != nil {
206
+ a .OnError (common .TaskStateDead , err )
207
+ }
208
+ }
209
+ a .bigTxEventWg .Done ()
210
+ }
211
+ }
212
+
189
213
func (a * ApplierIncr ) MtsWorker (workerIndex int ) {
190
214
keepLoop := true
191
215
192
216
logger := a .logger .With ("worker" , workerIndex )
193
217
218
+ if workerIndex == 0 {
219
+ go a .bigTxQueueExecutor ()
220
+ }
221
+
194
222
t := time .NewTicker (pingInterval )
195
223
defer t .Stop ()
196
224
hasEntry := false
@@ -445,6 +473,38 @@ func (a *ApplierIncr) HasShutdown() bool {
445
473
return false
446
474
}
447
475
}
476
+ func (a * ApplierIncr ) prepareIfNilAndExecute (item * dmlExecItem , workerIdx int ) (err error ) {
477
+ // hasUK bool, pstmt **gosql.Stmt, query string, args []interface{}
478
+ var r gosql.Result
479
+
480
+ if item .hasUK {
481
+ if * item .pstmt == nil {
482
+ a .logger .Debug ("buildDMLEventQuery prepare query" , "query" , item .query )
483
+ * item .pstmt , err = a .dbs [workerIdx ].Db .PrepareContext (a .ctx , item .query )
484
+ if err != nil {
485
+ a .logger .Error ("buildDMLEventQuery prepare query" , "query" , item .query , "err" , err )
486
+ return err
487
+ }
488
+ }
489
+
490
+ r , err = (* item .pstmt ).ExecContext (a .ctx , item .args ... )
491
+ } else {
492
+ r , err = a .dbs [workerIdx ].Db .ExecContext (a .ctx , item .query , item .args ... )
493
+ }
494
+
495
+ if err != nil {
496
+ a .logger .Error ("error at exec" , "gno" , item .gno , "err" , err )
497
+ return err
498
+ }
499
+
500
+ nr , err := r .RowsAffected ()
501
+ if err != nil {
502
+ a .logger .Error ("RowsAffected error" , "gno" , item .gno , "event" , 0 , "err" , err )
503
+ } else {
504
+ a .logger .Debug ("RowsAffected.after" , "gno" , item .gno , "event" , 0 , "nr" , nr )
505
+ }
506
+ return nil
507
+ }
448
508
449
509
// ApplyEventQueries applies multiple DML queries onto the dest table
450
510
func (a * ApplierIncr ) ApplyBinlogEvent (workerIdx int , binlogEntryCtx * common.EntryContext ) error {
@@ -455,7 +515,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
455
515
456
516
var err error
457
517
var timestamp uint32
458
- txSid := binlogEntry .Coordinates .GetSid ()
518
+ gno := binlogEntry .Coordinates .GetGNO ()
459
519
460
520
dbApplier .DbMutex .Lock ()
461
521
if dbApplier .Tx == nil {
@@ -469,79 +529,17 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
469
529
atomic .AddInt64 (a .memory2 , - int64 (binlogEntry .Size ()))
470
530
}()
471
531
472
- type execItem struct {
473
- hasUK bool
474
- pstmt * * gosql.Stmt
475
- query string
476
- args []interface {}
477
- }
478
- prepareIfNilAndExecute := func (hasUK bool , pstmt * * gosql.Stmt , query string , args []interface {}) (err error ) {
479
- var r gosql.Result
480
-
481
- if hasUK {
482
- if * pstmt == nil {
483
- a .logger .Debug ("buildDMLEventQuery prepare query" , "query" , query )
484
- * pstmt , err = a .dbs [workerIdx ].Db .PrepareContext (a .ctx , query )
485
- if err != nil {
486
- a .logger .Error ("buildDMLEventQuery prepare query" , "query" , query , "err" , err )
487
- return err
488
- }
489
- }
490
-
491
- r , err = (* pstmt ).ExecContext (a .ctx , args ... )
492
- } else {
493
- r , err = a .dbs [workerIdx ].Db .ExecContext (a .ctx , query , args ... )
494
- }
495
-
496
- if err != nil {
497
- logger .Error ("error at exec" , "gtid" , hclog .Fmt ("%s:%d" , txSid , binlogEntry .Coordinates .GetGNO ()),
498
- "err" , err )
499
- return err
500
- }
501
-
502
- nr , err := r .RowsAffected ()
503
- if err != nil {
504
- logger .Error ("RowsAffected error" , "gno" , binlogEntry .Coordinates .GetGNO (), "event" , 0 , "err" , err )
505
- } else {
506
- logger .Debug ("RowsAffected.after" , "gno" , binlogEntry .Coordinates .GetGNO (), "event" , 0 , "nr" , nr )
507
- }
508
- return nil
509
- }
510
-
511
- somequeue := make (chan * execItem , 16 )
512
- queueOrExec := func (item * execItem ) error {
513
- if a .inBigTx {
514
- somequeue <- item
532
+ queueOrExec := func (item * dmlExecItem ) error {
533
+ // TODO check if shutdown?
534
+ if ! a .noBigTxDMLPipe && a .inBigTx {
535
+ a .bigTxEventWg .Add (1 )
536
+ a .bigTxEventQueue <- item
515
537
return nil
516
538
} else {
517
- return prepareIfNilAndExecute (item . hasUK , item . pstmt , item . query , item . args )
539
+ return a . prepareIfNilAndExecute (item , workerIdx )
518
540
}
519
541
}
520
542
521
- executionLoopExitedCh := make (chan struct {})
522
- if a .inBigTx {
523
- go func () {
524
- defer close (executionLoopExitedCh )
525
- for {
526
- select {
527
- case item := <- somequeue :
528
- if item == nil {
529
- return
530
- }
531
-
532
- err := prepareIfNilAndExecute (item .hasUK , item .pstmt , item .query , item .args )
533
- if err != nil {
534
- a .OnError (common .TaskStateDead , err )
535
- }
536
- case <- a .shutdownCh :
537
- return
538
- }
539
- }
540
- }()
541
- } else {
542
- close (executionLoopExitedCh )
543
- }
544
-
545
543
for i , event := range binlogEntry .Events {
546
544
if a .HasShutdown () {
547
545
break
@@ -680,7 +678,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
680
678
}
681
679
a .logger .Debug ("BuildDMLInsertQuery" , "query" , query )
682
680
683
- err = queueOrExec (& execItem {true , pstmt , query , sharedArgs })
681
+ err = queueOrExec (& dmlExecItem {true , pstmt , query , sharedArgs , gno })
684
682
if err != nil {
685
683
return err
686
684
}
@@ -695,7 +693,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
695
693
}
696
694
a .logger .Debug ("BuildDMLDeleteQuery" , "query" , query )
697
695
698
- err = queueOrExec (& execItem {hasUK , pstmt , query , uniqueKeyArgs })
696
+ err = queueOrExec (& dmlExecItem {hasUK , pstmt , query , uniqueKeyArgs , gno })
699
697
if err != nil {
700
698
return err
701
699
}
@@ -722,7 +720,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
722
720
return err
723
721
}
724
722
725
- err = queueOrExec (& execItem {true , pstmt , query , sharedArgs })
723
+ err = queueOrExec (& dmlExecItem {true , pstmt , query , sharedArgs , gno })
726
724
if err != nil {
727
725
return err
728
726
}
@@ -735,7 +733,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
735
733
}
736
734
a .logger .Debug ("BuildDMLDeleteQuery" , "query" , query )
737
735
738
- err = queueOrExec (& execItem {hasUK , pstmt , query , uniqueKeyArgs })
736
+ err = queueOrExec (& dmlExecItem {hasUK , pstmt , query , uniqueKeyArgs , gno })
739
737
if err != nil {
740
738
return err
741
739
}
@@ -750,7 +748,7 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
750
748
args = append (args , sharedArgs ... )
751
749
args = append (args , uniqueKeyArgs ... )
752
750
753
- err = queueOrExec (& execItem {hasUK , pstmt , query , args })
751
+ err = queueOrExec (& dmlExecItem {hasUK , pstmt , query , args , gno })
754
752
if err != nil {
755
753
return err
756
754
}
@@ -769,8 +767,10 @@ func (a *ApplierIncr) ApplyBinlogEvent(workerIdx int, binlogEntryCtx *common.Ent
769
767
timestamp = event .Timestamp
770
768
atomic .AddUint64 (& a .appliedQueryCount , uint64 (1 ))
771
769
}
772
- close (somequeue )
773
- <- executionLoopExitedCh
770
+ a .bigTxEventWg .Wait ()
771
+ if a .HasShutdown () {
772
+ return fmt .Errorf ("ApplyBinlogEvent: applier has been shutdown. gno %v" , gno )
773
+ }
774
774
775
775
if binlogEntry .Final {
776
776
if ! a .SkipGtidExecutedTable && a .sourceType == "mysql" {
@@ -887,3 +887,17 @@ func (a *ApplierIncr) handleEntryOracle(entryCtx *common.EntryContext) (err erro
887
887
}
888
888
return nil
889
889
}
890
+
891
+ func (a * ApplierIncr ) Shutdown () {
892
+ close (a .bigTxEventQueue )
893
+ a .wg .Wait ()
894
+ a .logger .Debug ("Shutdown. ApplierIncr.wg.Wait. after" )
895
+ }
896
+
897
+ type dmlExecItem struct {
898
+ hasUK bool
899
+ pstmt * * gosql.Stmt
900
+ query string
901
+ args []interface {}
902
+ gno int64 // for log only
903
+ }
0 commit comments