gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/sync/lock/memory/memory.go (about) 1 // Package memory provides a sync.Mutex implementation of the lock for local use 2 package memory 3 4 import ( 5 "sync" 6 "time" 7 8 lock "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/lock" 9 ) 10 11 type memoryLock struct { 12 sync.RWMutex 13 locks map[string]*mlock 14 } 15 16 type mlock struct { 17 id string 18 time time.Time 19 ttl time.Duration 20 release chan bool 21 } 22 23 func (m *memoryLock) Acquire(id string, opts ...lock.AcquireOption) error { 24 // lock our access 25 m.Lock() 26 27 var options lock.AcquireOptions 28 for _, o := range opts { 29 o(&options) 30 } 31 32 lk, ok := m.locks[id] 33 if !ok { 34 m.locks[id] = &mlock{ 35 id: id, 36 time: time.Now(), 37 ttl: options.TTL, 38 release: make(chan bool), 39 } 40 // unlock 41 m.Unlock() 42 return nil 43 } 44 45 m.Unlock() 46 47 // set wait time 48 var wait <-chan time.Time 49 var ttl <-chan time.Time 50 51 // decide if we should wait 52 if options.Wait > time.Duration(0) { 53 wait = time.After(options.Wait) 54 } 55 56 // check the ttl of the lock 57 if lk.ttl > time.Duration(0) { 58 // time lived for the lock 59 live := time.Since(lk.time) 60 61 // set a timer for the leftover ttl 62 if live > lk.ttl { 63 // release the lock if it expired 64 _ = m.Release(id) 65 } else { 66 ttl = time.After(live) 67 } 68 } 69 70 lockLoop: 71 for { 72 // wait for the lock to be released 73 select { 74 case <-lk.release: 75 m.Lock() 76 77 // someone locked before us 78 lk, ok = m.locks[id] 79 if ok { 80 m.Unlock() 81 continue 82 } 83 84 // got chance to lock 85 m.locks[id] = &mlock{ 86 id: id, 87 time: time.Now(), 88 ttl: options.TTL, 89 release: make(chan bool), 90 } 91 92 m.Unlock() 93 94 break lockLoop 95 case <-ttl: 96 // ttl exceeded 97 _ = m.Release(id) 98 // TODO: check the ttl again above 99 ttl = nil 100 // try acquire 101 continue 102 case <-wait: 103 return lock.ErrLockTimeout 104 } 105 } 106 107 return nil 108 } 109 110 func (m *memoryLock) Release(id string) error { 111 m.Lock() 112 defer m.Unlock() 113 114 lk, ok := m.locks[id] 115 // no lock exists 116 if !ok { 117 return nil 118 } 119 120 // delete the lock 121 delete(m.locks, id) 122 123 select { 124 case <-lk.release: 125 return nil 126 default: 127 close(lk.release) 128 } 129 130 return nil 131 } 132 133 func NewLock(opts ...lock.Option) lock.Lock { 134 var options lock.Options 135 for _, o := range opts { 136 o(&options) 137 } 138 139 return &memoryLock{ 140 locks: make(map[string]*mlock), 141 } 142 }