bilibili-backup/app/service/main/tv/internal/dao/lock.go

73 lines
1.6 KiB
Go
Raw Normal View History

2019-04-22 10:59:20 +08:00
package dao
import (
"context"
"fmt"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
func (d *Dao) Lock(c context.Context, key string, val string) (err error) {
if val == "" {
return
}
conn := d.mc.Get(c)
defer conn.Close()
obj := &struct {
Value string
}{
Value: val,
}
item := &memcache.Item{Key: key, Object: obj, Expiration: d.cacheTTL.LockTTL, Flags: memcache.FlagJSON}
if err = conn.Add(item); err != nil {
prom.BusinessErrCount.Incr("mc:Lock")
log.Errorv(c, log.KV("Lock", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// no thread-safe, but it's works.
// bad case of unlocking
// 1, process-a gets lock
// 2, lock expires
// 3, process-b gets lock
// 4, process-a releases lock
func (d *Dao) Unlock(c context.Context, key string, val string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:Unlock")
log.Errorv(c, log.KV("Unlock", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res := &struct {
Value string
}{}
err = conn.Scan(reply, &res)
if err != nil {
prom.BusinessErrCount.Incr("mc:Unlock")
log.Errorv(c, log.KV("Unlock", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
if res.Value != val {
return nil
}
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:Unlock")
log.Errorv(c, log.KV("Unlock", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}