73 lines
1.6 KiB
Go
73 lines
1.6 KiB
Go
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
|
||
}
|