diff --git a/.golangci.yml b/.golangci.yml index 3a307d6d..40225cf1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -44,6 +44,9 @@ linters-settings: - name: empty-block - name: unreachable-code - name: redefines-builtin-id + govet: + enable: + - fieldalignment linters: disable-all: true diff --git a/internal/app/app.go b/internal/app/app.go index 33768f97..bc859f54 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -26,21 +26,21 @@ import ( // App is main application structure type App struct { - state appState - logger *log.Logger - config *config.Config + lostQuorumTime time.Time + externalReplication mysql.IExternalReplication + switchHelper mysql.ISwitchHelper dcs dcs.DCS - cluster *mysql.Cluster - filelock *flock.Flock nodeFailedAt map[string]time.Time + filelock *flock.Flock slaveReadPositions map[string]string streamFromFailedAt map[string]time.Time daemonState *DaemonState - daemonMutex sync.Mutex replRepairState map[string]*ReplicationRepairState - externalReplication mysql.IExternalReplication - switchHelper mysql.ISwitchHelper - lostQuorumTime time.Time + cluster *mysql.Cluster + config *config.Config + logger *log.Logger + state appState + daemonMutex sync.Mutex } // NewApp returns new App. Suddenly. @@ -2458,7 +2458,7 @@ func (app *App) getNodePositions(activeNodes []string) ([]nodePosition, error) { } positionsMutex.Lock() - positions = append(positions, nodePosition{host, gtidset, *lag, nc.Priority}) + positions = append(positions, nodePosition{gtidset, host, *lag, nc.Priority}) positionsMutex.Unlock() return nil }, activeNodes) diff --git a/internal/app/data.go b/internal/app/data.go index 65633dce..ae389848 100644 --- a/internal/app/data.go +++ b/internal/app/data.go @@ -81,25 +81,24 @@ var ( // NodeState contains status check performed by some mysync process type NodeState struct { - CheckBy string `json:"check_by"` CheckAt time.Time `json:"check_at"` - PingOk bool `json:"ping_ok"` - PingDubious bool `json:"ping_dubious"` + SemiSyncState *SemiSyncState `json:"semi_sync_state"` + SlaveState *SlaveState `json:"slave_state"` + MasterState *MasterState `json:"master_state"` + DaemonState *DaemonState `json:"daemon_state"` + DiskState *DiskState `json:"disk_state"` + Error string `json:"error"` + CheckBy string `json:"check_by"` IsMaster bool `json:"is_master"` - IsReadOnly bool `json:"is_readonly"` - IsSuperReadOnly bool `json:"is_super_readonly"` - IsOffline bool `json:"is_offline"` - IsCascade bool `json:"is_cascade"` IsFileSystemReadonly bool `json:"is_file_system_readonly"` IsLoadingBinlog bool `json:"is_loading_binlog"` - Error string `json:"error"` - DiskState *DiskState `json:"disk_state"` - DaemonState *DaemonState `json:"daemon_state"` - MasterState *MasterState `json:"master_state"` - SlaveState *SlaveState `json:"slave_state"` - SemiSyncState *SemiSyncState `json:"semi_sync_state"` - - ShowOnlyGTIDDiff bool + IsCascade bool `json:"is_cascade"` + IsOffline bool `json:"is_offline"` + IsSuperReadOnly bool `json:"is_super_readonly"` + IsReadOnly bool `json:"is_readonly"` + PingDubious bool `json:"ping_dubious"` + PingOk bool `json:"ping_ok"` + ShowOnlyGTIDDiff bool } // Last_SQL_Errno codes, that disallow to restart replication @@ -300,14 +299,14 @@ const ( // Switchover contains info about currently running or scheduled switchover/failover process type Switchover struct { + InitiatedAt time.Time `json:"initiated_at"` + StartedAt time.Time `json:"started_at"` + Result *SwitchoverResult `json:"result"` From string `json:"from"` To string `json:"to"` Cause string `json:"cause"` InitiatedBy string `json:"initiated_by"` - InitiatedAt time.Time `json:"initiated_at"` StartedBy string `json:"started_by"` - StartedAt time.Time `json:"started_at"` - Result *SwitchoverResult `json:"result"` RunCount int `json:"run_count,omitempty"` } @@ -337,15 +336,15 @@ func (sw *Switchover) String() string { // SwitchoverResult contains results of finished/failed switchover type SwitchoverResult struct { - Ok bool `json:"ok"` - Error string `json:"error"` FinishedAt time.Time `json:"finished_at"` + Error string `json:"error"` + Ok bool `json:"ok"` } // Maintenance struct presence means that cluster under manual control type Maintenance struct { - InitiatedBy string `json:"initiated_by"` InitiatedAt time.Time `json:"initiated_at"` + InitiatedBy string `json:"initiated_by"` MySyncPaused bool `json:"mysync_paused"` ShouldLeave bool `json:"should_leave"` } diff --git a/internal/app/util.go b/internal/app/util.go index cdb013c4..63e5a096 100644 --- a/internal/app/util.go +++ b/internal/app/util.go @@ -11,8 +11,8 @@ import ( ) type nodePosition struct { - host string gtidset gtids.GTIDSet + host string lag float64 priority int64 } @@ -194,15 +194,15 @@ func getDubiousHAHosts(clusterState map[string]*NodeState) []string { func getNodeStatesInParallel(hosts []string, getter func(string) (*NodeState, error), logger *log.Logger) (map[string]*NodeState, error) { type result struct { - name string - state *NodeState err error + state *NodeState + name string } results := make(chan result, len(hosts)) for _, host := range hosts { go func(host string) { state, err := getter(host) - results <- result{host, state, err} + results <- result{err, state, host} }(host) } clusterState := make(map[string]*NodeState) diff --git a/internal/app/util_test.go b/internal/app/util_test.go index 409ed0c2..8c72d7ba 100644 --- a/internal/app/util_test.go +++ b/internal/app/util_test.go @@ -28,82 +28,82 @@ func TestFindMostRecentNodeAndDetectSplitbrain(t *testing.T) { var splitbrain bool positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 5}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "C", 0, 5}, } host, _, splitbrain = findMostRecentNodeAndDetectSplitbrain(positions) require.Equal(t, "A", host) require.False(t, splitbrain) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + "09978591-5754-4710-BF67-062880ABE1B4:1-103," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), 0, -5}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), "B", 0, -5}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-102," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), "C", 0, 0}, } host, _, splitbrain = findMostRecentNodeAndDetectSplitbrain(positions) require.Equal(t, "B", host) require.False(t, splitbrain) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 0, 10}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 0, 10}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 42, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 42, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5.5, 0}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 5.5, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 135, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 135, 0}, } host, _, splitbrain = findMostRecentNodeAndDetectSplitbrain(positions) require.Equal(t, "C", host) require.False(t, splitbrain) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-101," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "C", 0, 0}, } host, _, splitbrain = findMostRecentNodeAndDetectSplitbrain(positions) require.Equal(t, "", host) require.True(t, splitbrain) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-000000000000:1-100"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-000000000000:1-100"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "C", 0, 0}, } host, _, splitbrain = findMostRecentNodeAndDetectSplitbrain(positions) require.Equal(t, "", host) @@ -117,50 +117,50 @@ func TestDesirableNodeWithZeroPriorityWorksAsFindMostRecentNode(t *testing.T) { logger := getLogger() positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "C", 0, 0}, } host, _ = getMostDesirableNode(logger, positions, 50*time.Second) require.Equal(t, "A", host) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + "09978591-5754-4710-BF67-062880ABE1B4:1-103," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-102," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), "C", 0, 0}, } host, _ = getMostDesirableNode(logger, positions, 50*time.Second) require.Equal(t, "B", host) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 42, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 42, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5.5, 0}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 5.5, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 135, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 135, 0}, } host, _ = getMostDesirableNode(logger, positions, 50*time.Second) require.Equal(t, "C", host) @@ -172,116 +172,116 @@ func TestFindMostDesirableNodeDependsOnPriority(t *testing.T) { logger := getLogger() positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "B", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 5}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "C", 0, 5}, } host, _ = getMostDesirableNode(logger, positions, 5*time.Second) require.Equal(t, "C", host) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), 0, 0}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100"), "A", 0, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-102," + "09978591-5754-4710-BF67-062880ABE1B4:1-103," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), 0, -5}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-104"), "B", 0, -5}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + "09978591-5754-4710-BF67-062880ABE1B4:1-102," + - "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), 0, 0}, + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-103"), "C", 0, 0}, } host, _ = getMostDesirableNode(logger, positions, 5*time.Second) require.Equal(t, "C", host) positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 0, 10}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 0, 10}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 42, 0}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 42, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5.5, 0}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 5.5, 0}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 135, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 135, 0}, } host, _ = getMostDesirableNode(logger, positions, 500*time.Second) require.Equal(t, "A", host) // Priority node has huge lag, other nodes +- inside maxLag radius positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 6000, 10}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 6000, 10}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 42, 7}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 42, 7}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5.5, 5}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 5.5, 5}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 135, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 135, 0}, } host, _ = getMostDesirableNode(logger, positions, 50*time.Second) require.Equal(t, "B", host) // Priority node has huge lag, other nodes are distributed, recurse works positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 6000, 10}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 6000, 10}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 42, 7}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 42, 7}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5.5, 5}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 5.5, 5}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 135, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 135, 0}, } host, _ = getMostDesirableNode(logger, positions, 5*time.Second) require.Equal(t, "C", host) // All nodes has huge lag, nodes are close to each other, choosing most prior positions = []nodePosition{ - {"A", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 6000, 10}, - {"B", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "A", 6000, 10}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 5990, 7}, - {"C", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "B", 5990, 7}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 6005, 5}, - {"D", mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "C", 6005, 5}, + {mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-333," + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + - "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), 6600, 0}, + "708D2D2F-87E6-11EB-AEDB-E18E21FD8FD5:1-100"), "D", 6600, 0}, } host, _ = getMostDesirableNode(logger, positions, 50*time.Second) require.Equal(t, "A", host) diff --git a/internal/config/config.go b/internal/config/config.go index 848fa8f6..9c488546 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,48 +15,48 @@ import ( // MySQLConfig contains MySQL cluster connection info type MySQLConfig struct { - User string `config:"user,required"` - Password string `config:"password,required"` - Port int `config:"port" yaml:"port"` + ReplicationPassword string `config:"replication_password,required" yaml:"replication_password"` + ExternalReplicationSslCA string `config:"external_replication_ssl_ca" yaml:"external_replication_ssl_ca"` + ErrorLog string `config:"error_log" yaml:"error_log"` SslCA string `config:"ssl_ca" yaml:"ssl_ca"` ReplicationUser string `config:"replication_user,required" yaml:"replication_user"` - ReplicationPort int `config:"replication_port" yaml:"replication_port"` - ReplicationPassword string `config:"replication_password,required" yaml:"replication_password"` + PidFile string `config:"pid_file" yaml:"pid_file"` + Password string `config:"password,required"` ReplicationSslCA string `config:"replication_ssl_ca" yaml:"replication_ssl_ca"` + User string `config:"user,required"` + DataDir string `config:"data_dir" yaml:"data_dir"` ReplicationRetryCount int `config:"replication_retry_count" yaml:"replication_retry_count"` - ReplicationConnectRetry int `config:"replication_connect_retry" yaml:"replication_connect_retry"` ReplicationHeartbeatPeriod int `config:"replication_heartbeat_period" yaml:"replication_heartbeat_period"` - ExternalReplicationSslCA string `config:"external_replication_ssl_ca" yaml:"external_replication_ssl_ca"` - DataDir string `config:"data_dir" yaml:"data_dir"` - PidFile string `config:"pid_file" yaml:"pid_file"` - ErrorLog string `config:"error_log" yaml:"error_log"` + ReplicationConnectRetry int `config:"replication_connect_retry" yaml:"replication_connect_retry"` + ReplicationPort int `config:"replication_port" yaml:"replication_port"` + Port int `config:"port" yaml:"port"` } // Config contains all mysync configuration type Config struct { - DevMode bool `config:"dev_mode" yaml:"dev_mode"` - SemiSync bool `config:"semi_sync" yaml:"semi_sync"` - SemiSyncEnableLag int64 `config:"semi_sync_enable_lag" yaml:"semi_sync_enable_lag"` - Failover bool `config:"failover" yaml:"failover"` - FailoverCooldown time.Duration `config:"failover_cooldown" yaml:"failover_cooldown"` - FailoverDelay time.Duration `config:"failover_delay" yaml:"failover_delay"` - InactivationDelay time.Duration `config:"inactivation_delay" yaml:"inactivation_delay"` - CriticalDiskUsage float64 `config:"critical_disk_usage" yaml:"critical_disk_usage"` - NotCriticalDiskUsage float64 `config:"not_critical_disk_usage" yaml:"not_critical_disk_usage"` - LogLevel string `config:"loglevel"` + Commands map[string]string `config:"commands"` + Queries map[string]string `config:"queries"` + MySQL MySQLConfig `config:"mysql"` Log string `config:"log"` - Hostname string `config:"hostname"` Lockfile string `config:"lockfile"` + ExternalReplicationChannel string `config:"external_replication_channel" yaml:"external_replication_channel"` + ReplicationChannel string `config:"replication_channel" yaml:"replication_channel"` + TestFilesystemReadonlyFile string `config:"test_filesystem_readonly_file" yaml:"test_filesystem_readonly_file"` + TestDiskUsageFile string `config:"test_disk_usage_file" yaml:"test_disk_usage_file"` + LogLevel string `config:"loglevel"` + DSNSettings string `config:"dsn_settings" yaml:"dsn_settings"` + Hostname string `config:"hostname"` + ExternalReplicationType util.ExternalReplicationType `config:"external_replication_type" yaml:"external_replication_type"` InfoFile string `config:"info_file" yaml:"info_file"` Emergefile string `config:"emergefile"` Resetupfile string `config:"resetupfile"` Maintenancefile string `config:"maintenancefile"` - MySQL MySQLConfig `config:"mysql"` - Queries map[string]string `config:"queries"` - Commands map[string]string `config:"commands"` + ReplMonSchemeName string `config:"repl_mon_scheme_name" yaml:"repl_mon_scheme_name"` + ReplMonTableName string `config:"repl_mon_table_name" yaml:"repl_mon_table_name"` + ExcludeUsers []string `config:"exclude_users" yaml:"exclude_users"` Zookeeper dcs.ZookeeperConfig `config:"zookeeper"` - DcsWaitTimeout time.Duration `config:"dcs_wait_timeout" yaml:"dcs_wait_timeout"` - DBTimeout time.Duration `config:"db_timeout" yaml:"db_timeout"` + MaxAcceptableLag float64 `config:"max_acceptable_lag" yaml:"max_acceptable_lag"` + StreamFromReasonableLag time.Duration `config:"stream_from_reasonable_lag" yaml:"stream_from_reasonable_lag"` DBLostCheckTimeout time.Duration `config:"db_lost_check_timeout" yaml:"db_lost_check_timeout"` DBSetRoTimeout time.Duration `config:"db_set_ro_timeout" yaml:"db_set_ro_timeout"` DBSetRoForceTimeout time.Duration `config:"db_set_ro_force_timeout" yaml:"db_set_ro_force_timeout"` @@ -68,40 +68,40 @@ type Config struct { ExternalCAFileCheckInterval time.Duration `config:"external_ca_file_check_interval" yaml:"external_ca_file_check_interval"` ManagerElectionDelayAfterQuorumLoss time.Duration `config:"manager_election_delay_after_quorum_loss" yaml:"manager_election_delay_after_quorum_loss"` ManagerLockAcquireDelayAfterQuorumLoss time.Duration `config:"manager_lock_acquire_delay_after_quorum_loss" yaml:"manager_lock_acquire_delay_after_quorum_loss"` - MaxAcceptableLag float64 `config:"max_acceptable_lag" yaml:"max_acceptable_lag"` + ReplMonSlaveWaitInterval time.Duration `config:"repl_mon_slave_wait_interval" yaml:"repl_mon_slave_wait_interval"` SlaveCatchUpTimeout time.Duration `config:"slave_catch_up_timeout" yaml:"slave_catch_up_timeout"` - DisableSemiSyncReplicationOnMaintenance bool `config:"disable_semi_sync_replication_on_maintenance" yaml:"disable_semi_sync_replication_on_maintenance"` - KeepSuperWritableOnCriticalDiskUsage bool `config:"keep_super_writable_on_critical_disk_usage" yaml:"keep_super_writable_on_critical_disk_usage"` - ExcludeUsers []string `config:"exclude_users" yaml:"exclude_users"` + ReplMonErrorWaitInterval time.Duration `config:"repl_mon_error_wait_interval" yaml:"repl_mon_error_wait_interval"` + ReplMonWriteInterval time.Duration `config:"repl_mon_write_interval" yaml:"repl_mon_write_interval"` + DcsWaitTimeout time.Duration `config:"dcs_wait_timeout" yaml:"dcs_wait_timeout"` OfflineModeEnableInterval time.Duration `config:"offline_mode_enable_interval" yaml:"offline_mode_enable_interval"` OfflineModeEnableLag time.Duration `config:"offline_mode_enable_lag" yaml:"offline_mode_enable_lag"` OfflineModeDisableLag time.Duration `config:"offline_mode_disable_lag" yaml:"offline_mode_disable_lag"` - DisableSetReadonlyOnLost bool `config:"disable_set_readonly_on_lost" yaml:"disable_set_readonly_on_lost"` - ResetupCrashedHosts bool `config:"resetup_crashed_hosts" yaml:"resetup_crashed_hosts"` - StreamFromReasonableLag time.Duration `config:"stream_from_reasonable_lag" yaml:"stream_from_reasonable_lag"` + SemiSyncEnableLag int64 `config:"semi_sync_enable_lag" yaml:"semi_sync_enable_lag"` + AsyncAllowedLag time.Duration `config:"async_allowed_lag" yaml:"async_allowed_lag"` + DBTimeout time.Duration `config:"db_timeout" yaml:"db_timeout"` PriorityChoiceMaxLag time.Duration `config:"priority_choice_max_lag" yaml:"priority_choice_max_lag"` - TestDiskUsageFile string `config:"test_disk_usage_file" yaml:"test_disk_usage_file"` + NotCriticalDiskUsage float64 `config:"not_critical_disk_usage" yaml:"not_critical_disk_usage"` RplSemiSyncMasterWaitForSlaveCount int `config:"rpl_semi_sync_master_wait_for_slave_count" yaml:"rpl_semi_sync_master_wait_for_slave_count"` WaitReplicationStartTimeout time.Duration `config:"wait_start_replication_timeout" yaml:"wait_start_replication_timeout"` - ReplicationRepairAggressiveMode bool `config:"replication_repair_aggressive_mode" yaml:"replication_repair_aggressive_mode"` + FailoverCooldown time.Duration `config:"failover_cooldown" yaml:"failover_cooldown"` ReplicationRepairCooldown time.Duration `config:"replication_repair_cooldown" yaml:"replication_repair_cooldown"` ReplicationRepairMaxAttempts int `config:"replication_repair_max_attempts" yaml:"replication_repair_max_attempts"` - TestFilesystemReadonlyFile string `config:"test_filesystem_readonly_file" yaml:"test_filesystem_readonly_file"` - ReplicationChannel string `config:"replication_channel" yaml:"replication_channel"` - ExternalReplicationChannel string `config:"external_replication_channel" yaml:"external_replication_channel"` - ExternalReplicationType util.ExternalReplicationType `config:"external_replication_type" yaml:"external_replication_type"` + CriticalDiskUsage float64 `config:"critical_disk_usage" yaml:"critical_disk_usage"` + InactivationDelay time.Duration `config:"inactivation_delay" yaml:"inactivation_delay"` + FailoverDelay time.Duration `config:"failover_delay" yaml:"failover_delay"` + KeepSuperWritableOnCriticalDiskUsage bool `config:"keep_super_writable_on_critical_disk_usage" yaml:"keep_super_writable_on_critical_disk_usage"` ASync bool `config:"async" yaml:"async"` - AsyncAllowedLag time.Duration `config:"async_allowed_lag" yaml:"async_allowed_lag"` + ResetupCrashedHosts bool `config:"resetup_crashed_hosts" yaml:"resetup_crashed_hosts"` ReplMon bool `config:"repl_mon" yaml:"repl_mon"` - ReplMonSchemeName string `config:"repl_mon_scheme_name" yaml:"repl_mon_scheme_name"` - ReplMonTableName string `config:"repl_mon_table_name" yaml:"repl_mon_table_name"` - ReplMonWriteInterval time.Duration `config:"repl_mon_write_interval" yaml:"repl_mon_write_interval"` - ReplMonErrorWaitInterval time.Duration `config:"repl_mon_error_wait_interval" yaml:"repl_mon_error_wait_interval"` - ReplMonSlaveWaitInterval time.Duration `config:"repl_mon_slave_wait_interval" yaml:"repl_mon_slave_wait_interval"` + Failover bool `config:"failover" yaml:"failover"` + DisableSetReadonlyOnLost bool `config:"disable_set_readonly_on_lost" yaml:"disable_set_readonly_on_lost"` + ReplicationRepairAggressiveMode bool `config:"replication_repair_aggressive_mode" yaml:"replication_repair_aggressive_mode"` + DisableSemiSyncReplicationOnMaintenance bool `config:"disable_semi_sync_replication_on_maintenance" yaml:"disable_semi_sync_replication_on_maintenance"` + DevMode bool `config:"dev_mode" yaml:"dev_mode"` ShowOnlyGTIDDiff bool `config:"show_only_gtid_diff" yaml:"show_only_gtid_diff"` ManagerSwitchover bool `config:"manager_switchover" yaml:"manager_switchover"` - ForceSwitchover bool `config:"force_switchover" yaml:"force_switchover"` // TODO: Remove when we will be sure it's right way to do switchover - DSNSettings string `config:"dsn_settings" yaml:"dsn_settings"` + ForceSwitchover bool `config:"force_switchover" yaml:"force_switchover"` + SemiSync bool `config:"semi_sync" yaml:"semi_sync"` } // DefaultConfig returns default configuration for MySync diff --git a/internal/dcs/config.go b/internal/dcs/config.go index 6eff2e66..e440f694 100644 --- a/internal/dcs/config.go +++ b/internal/dcs/config.go @@ -9,24 +9,24 @@ import ( // ZookeeperConfig contains Zookeeper connection info type ZookeeperConfig struct { - Hostname string `config:"hostname" yaml:"hostname"` - SessionTimeout time.Duration `config:"session_timeout" yaml:"session_timeout"` + CACert string `config:"ca_cert" yaml:"ca_cert"` Namespace string `config:"namespace,required"` + Hostname string `config:"hostname" yaml:"hostname"` + CertFile string `config:"certfile" yaml:"certfile"` + KeyFile string `config:"keyfile" yaml:"keyfile"` + Password string `config:"password" yaml:"password"` + Username string `config:"username" yaml:"username"` Hosts []string `config:"hosts,required"` + RandomHostProvider RandomHostProviderConfig `config:"random_host_provider" yaml:"random_host_provider"` BackoffInterval time.Duration `config:"backoff_interval" yaml:"backoff_interval"` - BackoffRandFactor float64 `config:"backoff_rand_factor" yaml:"backoff_rand_factor"` - BackoffMultiplier float64 `config:"backoff_multiplier" yaml:"backoff_multiplier"` - BackoffMaxInterval time.Duration `config:"backoff_max_interval" yaml:"backoff_max_interval"` - BackoffMaxElapsedTime time.Duration `config:"backoff_max_elapsed_time" yaml:"backoff_max_elapsed_time"` BackoffMaxRetries uint64 `config:"backoff_max_retries" yaml:"backoff_max_retries"` - RandomHostProvider RandomHostProviderConfig `config:"random_host_provider" yaml:"random_host_provider"` + BackoffMaxElapsedTime time.Duration `config:"backoff_max_elapsed_time" yaml:"backoff_max_elapsed_time"` + BackoffMaxInterval time.Duration `config:"backoff_max_interval" yaml:"backoff_max_interval"` + BackoffMultiplier float64 `config:"backoff_multiplier" yaml:"backoff_multiplier"` + BackoffRandFactor float64 `config:"backoff_rand_factor" yaml:"backoff_rand_factor"` + SessionTimeout time.Duration `config:"session_timeout" yaml:"session_timeout"` Auth bool `config:"auth" yaml:"auth"` - Username string `config:"username" yaml:"username"` - Password string `config:"password" yaml:"password"` UseSSL bool `config:"use_ssl" yaml:"use_ssl"` - KeyFile string `config:"keyfile" yaml:"keyfile"` - CertFile string `config:"certfile" yaml:"certfile"` - CACert string `config:"ca_cert" yaml:"ca_cert"` VerifyCerts bool `config:"verify_certs" yaml:"verify_certs"` } diff --git a/internal/dcs/zk.go b/internal/dcs/zk.go index 3148326b..e41e6584 100644 --- a/internal/dcs/zk.go +++ b/internal/dcs/zk.go @@ -23,11 +23,11 @@ type zkDCS struct { conn *zk.Conn eventsChan <-chan zk.Event disconnectCallback func() error - isConnected bool - connectedChans []chan struct{} - connectedLock sync.Mutex closeTimer *time.Timer + connectedChans []chan struct{} acl []zk.ACL + connectedLock sync.Mutex + isConnected bool } type zkLoggerProxy struct{ *log.Logger } diff --git a/internal/dcs/zk_host_provider.go b/internal/dcs/zk_host_provider.go index 1a2d3d7d..c244771f 100644 --- a/internal/dcs/zk_host_provider.go +++ b/internal/dcs/zk_host_provider.go @@ -12,21 +12,21 @@ import ( ) type zkhost struct { - resolved []string lastLookup time.Time + resolved []string } type RandomHostProvider struct { ctx context.Context - hosts sync.Map - useAddrs bool - hostsKeys []string tried map[string]struct{} logger *log.Logger + resolver *net.Resolver + hosts sync.Map + hostsKeys []string lookupTTL time.Duration lookupTimeout time.Duration lookupTickInterval time.Duration - resolver *net.Resolver + useAddrs bool } func NewRandomHostProvider(ctx context.Context, config *RandomHostProviderConfig, useAddrs bool, logger *log.Logger) *RandomHostProvider { diff --git a/internal/log/log.go b/internal/log/log.go index 7630efd4..23077b64 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -62,10 +62,10 @@ func (lvl Level) String() string { } type Logger struct { - path string fh *os.File - m sync.Mutex + path string lvl Level + m sync.Mutex } func Open(path, level string) (*Logger, error) { diff --git a/internal/mysql/cluster.go b/internal/mysql/cluster.go index 9c6f25b8..89dc242b 100644 --- a/internal/mysql/cluster.go +++ b/internal/mysql/cluster.go @@ -14,13 +14,13 @@ import ( // Cluster is a simple collection, containing set of MySQL ha_nodes type Cluster struct { - sync.Mutex + dcs dcs.DCS config *config.Config logger *log.Logger local *Node - dcs dcs.DCS haNodes map[string]*Node cascadeNodes map[string]*Node + sync.Mutex } func (c *Cluster) IsHAHost(hostname string) bool { diff --git a/internal/mysql/data.go b/internal/mysql/data.go index c4a4c9ce..7efb6607 100644 --- a/internal/mysql/data.go +++ b/internal/mysql/data.go @@ -54,44 +54,44 @@ type replicationSettings struct { SourceHost string `db:"SourceHost"` SourceUser string `db:"SourceUser"` SourcePassword string `db:"SourcePassword"` - SourcePort int `db:"SourcePort"` SourceSslCa string `db:"SourceSslCa"` - SourceDelay int `db:"SourceDelay"` ReplicationStatus sql.NullString `db:"ReplicationStatus"` + SourcePort int `db:"SourcePort"` + SourceDelay int `db:"SourceDelay"` } // SlaveStatusStruct contains SHOW SLAVE STATUS response type SlaveStatusStruct struct { - MasterHost string `db:"Master_Host"` - MasterPort int `db:"Master_Port"` + LastIOError string `db:"Last_IO_Error"` MasterLogFile string `db:"Master_Log_File"` - ReadMasterLogPos int64 `db:"Read_Master_Log_Pos"` + MasterHost string `db:"Master_Host"` SlaveIORunning string `db:"Slave_IO_Running"` SlaveSQLRunning string `db:"Slave_SQL_Running"` LastError string `db:"Last_Error"` RetrievedGtidSet string `db:"Retrieved_Gtid_Set"` ExecutedGtidSet string `db:"Executed_Gtid_Set"` + Lag sql.NullFloat64 `db:"Seconds_Behind_Master"` + ReadMasterLogPos int64 `db:"Read_Master_Log_Pos"` LastIOErrno int `db:"Last_IO_Errno"` - LastIOError string `db:"Last_IO_Error"` LastSQLErrno int `db:"Last_SQL_Errno"` - Lag sql.NullFloat64 `db:"Seconds_Behind_Master"` + MasterPort int `db:"Master_Port"` } // ReplicaStatusStruct contains SHOW REPLICA STATUS response type ReplicaStatusStruct struct { - SourceHost string `db:"Source_Host"` - SourcePort int `db:"Source_Port"` + LastIOError string `db:"Last_IO_Error"` SourceLogFile string `db:"Source_Log_File"` - ReadSourceLogPos int64 `db:"Read_Source_Log_Pos"` + SourceHost string `db:"Source_Host"` ReplicaIORunning string `db:"Replica_IO_Running"` ReplicaSQLRunning string `db:"Replica_SQL_Running"` LastError string `db:"Last_Error"` RetrievedGtidSet string `db:"Retrieved_Gtid_Set"` ExecutedGtidSet string `db:"Executed_Gtid_Set"` + Lag sql.NullFloat64 `db:"Seconds_Behind_Source"` + ReadSourceLogPos int64 `db:"Read_Source_Log_Pos"` LastIOErrno int `db:"Last_IO_Errno"` - LastIOError string `db:"Last_IO_Error"` LastSQLErrno int `db:"Last_SQL_Errno"` - Lag sql.NullFloat64 `db:"Seconds_Behind_Source"` + SourcePort int `db:"Source_Port"` } type ReplicaStatus interface { diff --git a/internal/util/util.go b/internal/util/util.go index a39aef5f..8881f015 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -46,13 +46,13 @@ func TouchFile(fname string) error { func RunParallel(f func(string) error, arguments []string) map[string]error { type pair struct { - key string err error + key string } errs := make(chan pair, len(arguments)) for _, argValue := range arguments { go func(dbname string) { - errs <- pair{dbname, f(dbname)} + errs <- pair{f(dbname), dbname} }(argValue) } result := make(map[string]error) diff --git a/tests/mysync_test.go b/tests/mysync_test.go index fc188b0a..4a125029 100644 --- a/tests/mysync_test.go +++ b/tests/mysync_test.go @@ -68,18 +68,18 @@ func (noLogger) Printf(string, ...interface{}) {} func (noLogger) Print(...interface{}) {} type testContext struct { - variables map[string]interface{} templateErr error composer testutil.Composer - composerEnv []string + variables map[string]interface{} zk *zk.Conn dbs map[string]*sqlx.DB + sqlUserQueryError sync.Map zkQueryResult string - sqlQueryResult []map[string]interface{} - sqlUserQueryError sync.Map // host -> error - commandRetcode int commandOutput string + composerEnv []string + sqlQueryResult []map[string]interface{} acl []zk.ACL + commandRetcode int } func newTestContext() (*testContext, error) { diff --git a/tests/testutil/docker_composer.go b/tests/testutil/docker_composer.go index 89113884..78d08db8 100644 --- a/tests/testutil/docker_composer.go +++ b/tests/testutil/docker_composer.go @@ -61,11 +61,11 @@ type Composer interface { // DockerComposer is a Composer implementation based on docker and docker compose type DockerComposer struct { - projectName string - config string api *client.Client containers map[string]container.Summary stopped map[string]bool + projectName string + config string } // NewDockerComposer returns DockerComposer instance for specified compose file