|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- package publock
-
- import (
- "context"
- "fmt"
- "sync"
- "time"
-
- "gitlink.org.cn/cloudream/common/pkgs/future"
- "gitlink.org.cn/cloudream/common/pkgs/logger"
- "gitlink.org.cn/cloudream/jcs-pub/client/internal/publock/types"
- clirpc "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/rpc/client"
- )
-
- type AcquireOptionFn func(opt *types.AcquireOption)
-
- func WithTimeout(timeout time.Duration) AcquireOptionFn {
- return func(opt *types.AcquireOption) {
- opt.Timeout = timeout
- }
- }
-
- func WithReason(reason string) AcquireOptionFn {
- return func(opt *types.AcquireOption) {
- opt.Reason = reason
- }
- }
-
- type PubLock struct {
- core *Core
- cliCli *clirpc.Client
- pubChan clirpc.PubLockMessageChan
- lock sync.Mutex
- acquirings map[string]*acquireInfo
- releasing map[string]*releaseInfo
- nextCtxID int64
- }
-
- func NewMaster() *PubLock {
- core := NewCore()
- return &PubLock{
- core: core,
- }
- }
-
- func NewSlave(cli *clirpc.Client) *PubLock {
- return &PubLock{
- cliCli: cli,
- acquirings: make(map[string]*acquireInfo),
- releasing: make(map[string]*releaseInfo),
- }
- }
-
- func (s *PubLock) BeginReentrant() *Reentrant {
- r := &Reentrant{
- p: s,
- }
- r.T = r
- return r
- }
-
- func (p *PubLock) BeginMutex() *MutexBuilder {
- m := &MutexBuilder{
- pub: p,
- }
- m.T = m
- return m
- }
-
- func (p *PubLock) Start() {
- if p.core != nil {
- p.core.Start()
- return
- }
- }
-
- func (p *PubLock) Stop() {
- p.lock.Lock()
- defer p.lock.Unlock()
-
- if p.core != nil {
- p.core.Stop()
- return
- }
-
- if p.pubChan != nil {
- p.pubChan.Close()
- p.pubChan = nil
- }
-
- p.cliCli.Release()
- p.cliCli = nil
- }
-
- func (p *PubLock) Acquire(req types.LockRequest, opt types.AcquireOption) (LockedRequest, error) {
- p.lock.Lock()
-
- if p.core != nil {
- p.lock.Unlock()
- return p.core.Acquire(req, opt)
- }
-
- if p.pubChan == nil {
- p.pubChan = p.cliCli.PubLockChannel(context.Background())
- go p.receivingChan()
- }
-
- acqID := fmt.Sprintf("%v", p.nextCtxID)
- p.nextCtxID++
-
- cerr := p.pubChan.Send(&types.AcquireMsg{ContextID: acqID, Request: req, Option: opt})
- if cerr != nil {
- p.lock.Unlock()
- return LockedRequest{}, cerr.ToError()
- }
-
- callback := future.NewSetValue[types.RequestID]()
- info := &acquireInfo{
- Request: req,
- Callback: callback,
- }
- p.acquirings[acqID] = info
- p.lock.Unlock()
-
- reqID, err := callback.Wait(context.Background())
- if err != nil {
- return LockedRequest{}, err
- }
-
- return LockedRequest{
- Req: req,
- ReqID: reqID,
- }, nil
- }
-
- func (p *PubLock) Release(reqID types.RequestID) {
- log := logger.WithField("Mod", "PubLock")
-
- p.lock.Lock()
-
- if p.core != nil {
- p.lock.Unlock()
- p.core.release(reqID)
- return
- }
-
- if p.pubChan == nil {
- p.pubChan = p.cliCli.PubLockChannel(context.Background())
- go p.receivingChan()
- }
-
- relID := fmt.Sprintf("%v", p.nextCtxID)
- p.nextCtxID++
-
- cerr := p.pubChan.Send(&types.ReleaseMsg{ContextID: relID, RequestID: reqID})
- if cerr != nil {
- p.lock.Unlock()
- log.Warnf("unlock %v: %v", reqID, cerr.ToError())
- return
- }
-
- callback := future.NewSetVoid()
- info := &releaseInfo{
- RequestID: reqID,
- Callback: callback,
- }
- p.releasing[relID] = info
- p.lock.Unlock()
-
- err := callback.Wait(context.Background())
- if err != nil {
- log.Warnf("unlock %v: %v", reqID, err)
- return
- }
-
- log.Tracef("unlock %v", reqID)
- }
-
- func (p *PubLock) receivingChan() {
- log := logger.WithField("Mod", "PubLock")
- for {
- msg, cerr := p.pubChan.Receive()
- if cerr != nil {
- p.lock.Lock()
- for _, info := range p.acquirings {
- info.Callback.SetError(cerr.ToError())
- }
- p.acquirings = make(map[string]*acquireInfo)
-
- for _, info := range p.releasing {
- info.Callback.SetError(cerr.ToError())
- }
- p.releasing = make(map[string]*releaseInfo)
- p.lock.Unlock()
-
- log.Warnf("receive channel error: %v", cerr.ToError())
- return
- }
-
- p.lock.Lock()
-
- switch msg := msg.(type) {
- case *types.AcquireResultMsg:
- info, ok := p.acquirings[msg.ContextID]
- if !ok {
- continue
- }
-
- if msg.Success {
- info.Callback.SetValue(msg.RequestID)
- } else {
- info.Callback.SetError(fmt.Errorf(msg.Error))
- }
- delete(p.acquirings, msg.ContextID)
-
- case *types.ReleaseResultMsg:
- info, ok := p.releasing[msg.ContextID]
- if !ok {
- continue
- }
-
- info.Callback.SetVoid()
- delete(p.releasing, msg.ContextID)
- }
-
- p.lock.Unlock()
- }
- }
-
- type releaseInfo struct {
- RequestID types.RequestID
- Callback *future.SetVoidFuture
- }
|