github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/checker/real_checker.go (about) 1 // Copyright 2021 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package checker 15 16 import ( 17 "context" 18 "fmt" 19 "sync" 20 ) 21 22 // RealChecker is interface that defines RealChecker to check configurations of system. 23 // It is mainly used for configuration checking of data synchronization between database systems. 24 type RealChecker interface { 25 Name() string 26 Check(ctx context.Context) *Result 27 } 28 29 // State is state of check. 30 type State string 31 32 const ( 33 // StateSuccess indicates that the check was successful. 34 StateSuccess State = "success" 35 // StateFailure indicates that the check was failed. 36 StateFailure State = "fail" 37 // StateWarning indicates that the check had warnings. 38 StateWarning State = "warn" 39 ) 40 41 type Error struct { 42 Severity State `json:"severity"` 43 ShortErr string `json:"short_error"` 44 Self string `json:"self,omitempty"` 45 Other string `json:"other,omitempty"` 46 Instruction string `json:"instruction,omitempty"` 47 } 48 49 // NewError creates a pointer to Error, the parameters could be used as in Sprintf. 50 func NewError(description string, args ...interface{}) *Error { 51 return &Error{Severity: StateFailure, ShortErr: fmt.Sprintf(description, args...)} 52 } 53 54 // NewWarn creates a pointer to Error, the parameters could be used as in Sprintf. 55 func NewWarn(description string, args ...interface{}) *Error { 56 return &Error{Severity: StateWarning, ShortErr: fmt.Sprintf(description, args...)} 57 } 58 59 // Result is result of check. 60 type Result struct { 61 ID uint64 `json:"id"` 62 Name string `json:"name"` 63 Desc string `json:"desc"` 64 State State `json:"state"` 65 Errors []*Error `json:"errors,omitempty"` 66 Instruction string `json:"instruction,omitempty"` 67 Extra string `json:"extra,omitempty"` 68 } 69 70 // ResultSummary is summary of all check results. 71 type ResultSummary struct { 72 Passed bool `json:"passed"` 73 Total int64 `json:"total"` 74 Successful int64 `json:"successful"` 75 Failed int64 `json:"failed"` 76 Warning int64 `json:"warning"` 77 } 78 79 // Results contains all check results and summary. 80 type Results struct { 81 Results []*Result `json:"results"` 82 Summary *ResultSummary `json:"summary"` 83 } 84 85 // Do executes several RealCheckers. 86 func Do(ctx context.Context, checkers []RealChecker) (*Results, error) { 87 results := &Results{ 88 Results: make([]*Result, 0, len(checkers)), 89 } 90 if len(checkers) == 0 { 91 results.Summary = &ResultSummary{Passed: true} 92 return results, nil 93 } 94 95 var ( 96 wg sync.WaitGroup 97 finished bool 98 total int64 99 successful int64 100 failed int64 101 warning int64 102 ) 103 total = int64(len(checkers)) 104 105 resultCh := make(chan *Result) 106 107 wg.Add(1) 108 go func() { 109 defer wg.Done() 110 for { 111 result := <-resultCh 112 switch result.State { 113 case StateSuccess: 114 successful++ 115 case StateFailure: 116 failed++ 117 case StateWarning: 118 warning++ 119 } 120 121 // if total == successful + warning + failed, it's finished 122 finished = total == successful+warning+failed 123 results.Results = append(results.Results, result) 124 125 if finished { 126 return 127 } 128 } 129 }() 130 131 for i, checker := range checkers { 132 wg.Add(1) 133 go func(i int, checker RealChecker) { 134 defer wg.Done() 135 result := checker.Check(ctx) 136 result.ID = uint64(i) 137 resultCh <- result 138 }(i, checker) 139 } 140 wg.Wait() 141 142 passed := finished && (failed == 0) 143 results.Summary = &ResultSummary{ 144 Passed: passed, 145 Total: total, 146 Successful: successful, 147 Failed: failed, 148 Warning: warning, 149 } 150 151 return results, nil 152 }