github.com/annwntech/go-micro/v2@v2.9.5/sync/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 gosync "sync" 6 "time" 7 8 "github.com/annwntech/go-micro/v2/sync" 9 ) 10 11 type memorySync struct { 12 options sync.Options 13 14 mtx gosync.RWMutex 15 locks map[string]*memoryLock 16 } 17 18 type memoryLock struct { 19 id string 20 time time.Time 21 ttl time.Duration 22 release chan bool 23 } 24 25 type memoryLeader struct { 26 opts sync.LeaderOptions 27 id string 28 resign func(id string) error 29 status chan bool 30 } 31 32 func (m *memoryLeader) Resign() error { 33 return m.resign(m.id) 34 } 35 36 func (m *memoryLeader) Status() chan bool { 37 return m.status 38 } 39 40 func (m *memorySync) Leader(id string, opts ...sync.LeaderOption) (sync.Leader, error) { 41 var once gosync.Once 42 var options sync.LeaderOptions 43 for _, o := range opts { 44 o(&options) 45 } 46 47 // acquire a lock for the id 48 if err := m.Lock(id); err != nil { 49 return nil, err 50 } 51 52 // return the leader 53 return &memoryLeader{ 54 opts: options, 55 id: id, 56 resign: func(id string) error { 57 once.Do(func() { 58 m.Unlock(id) 59 }) 60 return nil 61 }, 62 // TODO: signal when Unlock is called 63 status: make(chan bool, 1), 64 }, nil 65 } 66 67 func (m *memorySync) Init(opts ...sync.Option) error { 68 for _, o := range opts { 69 o(&m.options) 70 } 71 return nil 72 } 73 74 func (m *memorySync) Options() sync.Options { 75 return m.options 76 } 77 78 func (m *memorySync) Lock(id string, opts ...sync.LockOption) error { 79 // lock our access 80 m.mtx.Lock() 81 82 var options sync.LockOptions 83 for _, o := range opts { 84 o(&options) 85 } 86 87 lk, ok := m.locks[id] 88 if !ok { 89 m.locks[id] = &memoryLock{ 90 id: id, 91 time: time.Now(), 92 ttl: options.TTL, 93 release: make(chan bool), 94 } 95 // unlock 96 m.mtx.Unlock() 97 return nil 98 } 99 100 m.mtx.Unlock() 101 102 // set wait time 103 var wait <-chan time.Time 104 var ttl <-chan time.Time 105 106 // decide if we should wait 107 if options.Wait > time.Duration(0) { 108 wait = time.After(options.Wait) 109 } 110 111 // check the ttl of the lock 112 if lk.ttl > time.Duration(0) { 113 // time lived for the lock 114 live := time.Since(lk.time) 115 116 // set a timer for the leftover ttl 117 if live > lk.ttl { 118 // release the lock if it expired 119 _ = m.Unlock(id) 120 } else { 121 ttl = time.After(live) 122 } 123 } 124 125 lockLoop: 126 for { 127 // wait for the lock to be released 128 select { 129 case <-lk.release: 130 m.mtx.Lock() 131 132 // someone locked before us 133 lk, ok = m.locks[id] 134 if ok { 135 m.mtx.Unlock() 136 continue 137 } 138 139 // got chance to lock 140 m.locks[id] = &memoryLock{ 141 id: id, 142 time: time.Now(), 143 ttl: options.TTL, 144 release: make(chan bool), 145 } 146 147 m.mtx.Unlock() 148 149 break lockLoop 150 case <-ttl: 151 // ttl exceeded 152 _ = m.Unlock(id) 153 // TODO: check the ttl again above 154 ttl = nil 155 // try acquire 156 continue 157 case <-wait: 158 return sync.ErrLockTimeout 159 } 160 } 161 162 return nil 163 } 164 165 func (m *memorySync) Unlock(id string) error { 166 m.mtx.Lock() 167 defer m.mtx.Unlock() 168 169 lk, ok := m.locks[id] 170 // no lock exists 171 if !ok { 172 return nil 173 } 174 175 // delete the lock 176 delete(m.locks, id) 177 178 select { 179 case <-lk.release: 180 return nil 181 default: 182 close(lk.release) 183 } 184 185 return nil 186 } 187 188 func (m *memorySync) String() string { 189 return "memory" 190 } 191 192 func NewSync(opts ...sync.Option) sync.Sync { 193 var options sync.Options 194 for _, o := range opts { 195 o(&options) 196 } 197 198 return &memorySync{ 199 options: options, 200 locks: make(map[string]*memoryLock), 201 } 202 }