github.com/aergoio/aergo@v1.3.1/chain/debugger.go (about) 1 package chain 2 3 import ( 4 "fmt" 5 "os" 6 "strconv" 7 "sync" 8 "time" 9 ) 10 11 type ErrDebug struct { 12 cond StopCond 13 value int 14 } 15 16 type StopCond int 17 18 // stop before swap chain 19 const ( 20 DEBUG_CHAIN_STOP StopCond = 0 + iota 21 DEBUG_CHAIN_RANDOM_STOP 22 DEBUG_CHAIN_BP_SLEEP 23 DEBUG_CHAIN_OTHER_SLEEP 24 DEBUG_SYNCER_CRASH 25 DEBUG_RAFT_SNAP_FREQ // change snap frequency after first snapshot 26 ) 27 28 const ( 29 DEBUG_CHAIN_STOP_INF = DEBUG_RAFT_SNAP_FREQ 30 ) 31 32 var ( 33 EnvNameStaticCrash = "DEBUG_CHAIN_CRASH" // 1 ~ 4 34 EnvNameRandomCrashTime = "DEBUG_RANDOM_CRASH_TIME" // 1 ~ 600000(=10min) ms 35 EnvNameChainBPSleep = "DEBUG_CHAIN_BP_SLEEP" // bp node sleeps before connecting block for each block (ms). used 36 EnvNameChainOtherSleep = "DEBUG_CHAIN_OTHER_SLEEP" // non bp node sleeps before connecting block for each block (ms). 37 EnvNameSyncCrash = "DEBUG_SYNCER_CRASH" // case 1 38 EnvNameRaftSnapFreq = "DEBUG_RAFT_SNAP_FREQ" // case 1 39 ) 40 41 var stopConds = [...]string{ 42 EnvNameStaticCrash, 43 EnvNameRandomCrashTime, 44 EnvNameChainBPSleep, 45 EnvNameChainOtherSleep, 46 EnvNameSyncCrash, 47 EnvNameRaftSnapFreq, 48 } 49 50 type DebugHandler func(value int) error 51 52 func (c StopCond) String() string { return stopConds[c] } 53 54 func (ec *ErrDebug) Error() string { 55 return fmt.Sprintf("stopped by debugger cond[%s]=%d", ec.cond.String(), ec.value) 56 } 57 58 type Debugger struct { 59 sync.RWMutex 60 condMap map[StopCond]int 61 isEnv map[StopCond]bool 62 } 63 64 func newDebugger() *Debugger { 65 dbg := &Debugger{condMap: make(map[StopCond]int), isEnv: make(map[StopCond]bool)} 66 67 checkEnv := func(condName StopCond) { 68 envName := stopConds[condName] 69 70 envStr := os.Getenv(envName) 71 if len(envStr) > 0 { 72 val, err := strconv.Atoi(envStr) 73 if err != nil { 74 logger.Error().Err(err).Msgf("%s environment varialble must be integer", envName) 75 return 76 } 77 logger.Debug().Int("value", val).Msgf("env variable[%s] is set", envName) 78 79 dbg.Set(condName, val, true) 80 } 81 } 82 83 checkEnv(DEBUG_CHAIN_STOP) 84 checkEnv(DEBUG_CHAIN_RANDOM_STOP) 85 checkEnv(DEBUG_CHAIN_BP_SLEEP) 86 checkEnv(DEBUG_CHAIN_OTHER_SLEEP) 87 checkEnv(DEBUG_SYNCER_CRASH) 88 checkEnv(DEBUG_RAFT_SNAP_FREQ) 89 90 return dbg 91 } 92 93 func (debug *Debugger) Set(cond StopCond, value int, env bool) { 94 if debug == nil { 95 return 96 } 97 98 debug.Lock() 99 defer debug.Unlock() 100 101 logger.Debug().Int("cond", int(cond)).Str("name", stopConds[cond]).Int("val", value).Msg("set debug condition") 102 103 debug.condMap[cond] = value 104 debug.isEnv[cond] = env 105 } 106 107 func (debug *Debugger) Unset(cond StopCond) { 108 if debug == nil { 109 return 110 } 111 112 debug.Lock() 113 defer debug.Unlock() 114 115 logger.Debug().Str("cond", cond.String()).Msg("deubugger condition is unset") 116 delete(debug.condMap, cond) 117 } 118 119 func (debug *Debugger) clear() { 120 if debug == nil { 121 return 122 } 123 124 debug.Lock() 125 defer debug.Unlock() 126 127 debug.condMap = make(map[StopCond]int) 128 debug.isEnv = make(map[StopCond]bool) 129 } 130 131 func (debug *Debugger) Check(cond StopCond, value int, handler DebugHandler) error { 132 if debug == nil { 133 return nil 134 } 135 136 debug.Lock() 137 defer debug.Unlock() 138 139 if setVal, ok := debug.condMap[cond]; ok { 140 logger.Debug().Str("cond", stopConds[cond]).Int("val", setVal).Msg("check debug condition") 141 142 switch cond { 143 case DEBUG_CHAIN_STOP: 144 if setVal == value { 145 if debug.isEnv[cond] { 146 logger.Fatal().Str("cond", stopConds[cond]).Msg("shutdown by DEBUG_CHAIN_CRASH") 147 } else { 148 return &ErrDebug{cond: cond, value: value} 149 } 150 } 151 152 case DEBUG_CHAIN_RANDOM_STOP: 153 go crashRandom(setVal) 154 handleCrashRandom(setVal) 155 156 case DEBUG_CHAIN_OTHER_SLEEP, DEBUG_CHAIN_BP_SLEEP: 157 handleChainSleep(setVal) 158 159 case DEBUG_SYNCER_CRASH: 160 if setVal == value { 161 return handleSyncerCrash(setVal, cond) 162 } 163 case DEBUG_RAFT_SNAP_FREQ: 164 handler(setVal) 165 } 166 } 167 168 return nil 169 } 170 171 func handleChainSleep(sleepMils int) { 172 logger.Debug().Int("sleep(ms)", sleepMils).Msg("before chain sleep") 173 174 time.Sleep(time.Millisecond * time.Duration(sleepMils)) 175 176 logger.Debug().Msg("after chain sleep") 177 } 178 179 func handleCrashRandom(waitMils int) { 180 logger.Debug().Int("after(ms)", waitMils).Msg("before random crash") 181 182 go crashRandom(waitMils) 183 } 184 185 func handleSyncerCrash(val int, cond StopCond) error { 186 if val >= 1 { 187 logger.Fatal().Int("val", val).Msg("sync crash by DEBUG_SYNC_CRASH") 188 return nil 189 } else { 190 return &ErrDebug{cond: cond, value: val} 191 } 192 } 193 194 func crashRandom(waitMils int) { 195 if waitMils <= 0 { 196 return 197 } 198 199 time.Sleep(time.Millisecond * time.Duration(waitMils)) 200 201 logger.Debug().Msg("shutdown by DEBUG_RANDOM_CRASH_TIME") 202 203 os.Exit(100) 204 }