pull/4258/head
Lutty 2 years ago
parent 3cdd9cfab3
commit 03593f1061
  1. 8
      core/blockchain_impl.go
  2. 43
      internal/tikv/redis_helper/lock.go

@ -3186,7 +3186,13 @@ func (bc *BlockChainImpl) isInitTiKV() bool {
func (bc *BlockChainImpl) tikvPreemptMaster(fromBlock, toBlock uint64) bool { func (bc *BlockChainImpl) tikvPreemptMaster(fromBlock, toBlock uint64) bool {
for { for {
// preempt master // 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 return true
} }

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

Loading…
Cancel
Save