1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| package lock
import ( "github.com/garyburd/redigo/redis" "errors" "github.com/satori/go.uuid" "crypto/md5" "fmt" )
const ( PREFIX = "lock->" script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
) type RedisLock struct { pool *redis.Pool expireTime int key string value string }
func NewLock(name string, pool *redis.Pool, expireSeconds int) (*RedisLock, error) { if name == "" { return nil, errors.New("illegal argument: name") } key := PREFIX + name valueContent := uuid.NewV1().String() + key md5sum := md5.New() md5sum.Write([]byte(valueContent))
lock := RedisLock{ key: key, value: fmt.Sprintf("%x", md5sum.Sum(nil)), pool: pool, expireTime:expireSeconds} return &lock, nil }
func (redisLock *RedisLock) TryLock() (bool, error) { dbConn := redisLock.pool.Get() rep, err := dbConn.Do("SET", redisLock.key, redisLock.value, "NX", "EX", redisLock.ExpireTime()) if err != nil { return false, err }
if rep == nil { return false, nil } result, err := redis.String(rep, err) if result == "OK" { return true, nil } return false, err }
func (redisLock *RedisLock) Unlock() error { dbConn := redisLock.pool.Get() _, err := dbConn.Do("EVAL", script, 1, redisLock.key, redisLock.value) return err }
func (redisLock *RedisLock) ExpireTime() int { if redisLock.expireTime == 0 { return 60 * 60 * 24 } return redisLock.expireTime }
func (redisLock *RedisLock) SetExpireTime(expireTime int) { redisLock.expireTime = expireTime }
|