Merge pull request #4258 from LuttyYang/tikv

Fix staking bug in elastic rpc mode
pull/4264/head
Leo Chen 2 years ago committed by GitHub
commit 4dfeb83704
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      core/blockchain_impl.go
  2. 42
      internal/tikv/redis_helper/lock.go

@ -3186,7 +3186,13 @@ func (bc *BlockChainImpl) isInitTiKV() bool {
func (bc *BlockChainImpl) tikvPreemptMaster(fromBlock, toBlock uint64) bool {
for {
// preempt master
if ok, _ := bc.redisPreempt.TryLock(60); ok {
lockType, _ := bc.redisPreempt.TryLock(60)
switch lockType {
case redis_helper.LockResultRenewalSuccess:
return true
case redis_helper.LockResultSuccess:
// first to master
bc.validatorListByDelegatorCache.Purge()
return true
}

@ -4,10 +4,20 @@ import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"github.com/go-redis/redis/v8"
)
type LockResult int
const (
_ LockResult = iota
LockResultSuccess
LockResultRenewalSuccess
LockResultFail
)
type RedisPreempt struct {
key string
password string
@ -31,10 +41,15 @@ func (p *RedisPreempt) init() {
_, _ = rand.Read(byt)
p.password = base64.StdEncoding.EncodeToString(byt)
p.lockScript = redis.NewScript(`
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('expire', KEYS[1], ARGV[2])
local val = redis.call('get', KEYS[1])
if (val==nil or (type(val) == "boolean" and not val)) then
redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2])
return 'LockResultSuccess'
elseif (val == ARGV[1]) then
redis.call('expire', KEYS[1], ARGV[2])
return 'LockResultRenewalSuccess'
else
return redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2], 'nx')
return 'LockResultFail'
end
`)
p.unlockScript = redis.NewScript(`
@ -47,10 +62,23 @@ func (p *RedisPreempt) init() {
}
// TryLock attempt to lock the master for ttlSecond
func (p *RedisPreempt) TryLock(ttlSecond int) (ok bool, err error) {
ok, err = p.lockScript.Run(context.Background(), redisInstance, []string{p.key}, p.password, ttlSecond).Bool()
p.lastLockStatus = ok
return
func (p *RedisPreempt) TryLock(ttlSecond int) (result LockResult, err error) {
ret, err := p.lockScript.Run(context.Background(), redisInstance, []string{p.key}, p.password, ttlSecond).Text()
if err != nil {
return LockResultFail, err
}
switch ret {
case "LockResultRenewalSuccess":
p.lastLockStatus = true
return LockResultRenewalSuccess, nil
case "LockResultSuccess":
p.lastLockStatus = true
return LockResultSuccess, nil
case "LockResultFail":
return LockResultFail, nil
default:
return LockResultFail, errors.New("fixme: unknown return")
}
}
// Unlock try to release the master permission

Loading…
Cancel
Save