@@ -70,24 +70,36 @@ func (lock *EtcdRWLock) RLock(ctx context.Context) error {
7070 ctxNc := context .WithoutCancel (ctx )
7171
7272 if err := lock .m3 .Lock (ctx ); err != nil {
73- return err // could be context.Canceled
73+ if err == context .Canceled {
74+ return nil // Never went out of the equilibrium state
75+ }
76+ return err
7477 }
7578 defer unlock (ctxNc , lock .m3 )
7679
7780 if err := lock .r .Lock (ctx ); err != nil {
78- return err // could be context.Canceled
81+ if err == context .Canceled {
82+ return nil // Equilibrium state is reached by previous defered operations
83+ }
84+ return err
7985 }
8086 defer unlock (ctxNc , lock .r )
8187
8288 if err := lock .m1 .Lock (ctx ); err != nil {
83- return err // could be context.Canceled
89+ if err == context .Canceled {
90+ return nil // Equilibrium state is reached by previous defered operations
91+ }
92+ return err
8493 }
8594 defer unlock (ctxNc , lock .m1 )
8695
8796 k := fmt .Sprintf ("/chall-manager/%s/readCounter" , lock .key )
8897 res , err := etcdCli .Get (ctx , k )
8998 if err != nil {
90- return err // could be context.Canceled
99+ if err == context .Canceled {
100+ return nil // Equilibrium state is reached by previous defered operations
101+ }
102+ return err
91103 }
92104 var readCounter int
93105 switch len (res .Kvs ) {
@@ -105,14 +117,20 @@ func (lock *EtcdRWLock) RLock(ctx context.Context) error {
105117 readCounter ++
106118 _ , err = etcdCli .Put (ctx , k , strconv .Itoa (readCounter ))
107119 if err != nil {
108- // Commited no value to etcd so it's fine.
109- // Defered functions will reach the equilibrium state
120+ // Committed no value to etcd so it's fine.
121+ if err == context .Canceled {
122+ return nil // Equilibrium state is reached by previous defered operations
123+ }
110124 return err
111125 }
112126
127+ // From now on, we cannot go back and need to finish the job, else way deadlock
128+
113129 if readCounter == 1 {
114- // Now that we wrote the readcounter, we can't skip the lock else deadlock
115130 if err := lock .w .Lock (ctxNc ); err != nil {
131+ if err == context .Canceled {
132+ return nil
133+ }
116134 return err
117135 }
118136 }
@@ -125,38 +143,49 @@ func (lock *EtcdRWLock) RUnlock(ctx context.Context) error {
125143 ctxNc := context .WithoutCancel (ctx )
126144
127145 if err := lock .m1 .Lock (ctx ); err != nil {
128- return err // could be context.Canceled
146+ if err == context .Canceled {
147+ return nil // Never went out of the equilibrium state
148+ }
149+ return err
129150 }
130151 defer unlock (ctxNc , lock .m1 )
131152
132153 k := fmt .Sprintf ("/chall-manager/%s/readCounter" , lock .key )
133154 res , err := etcdCli .Get (ctx , k )
134155 if err != nil {
135- return err // could be context.Canceled
156+ if err == context .Canceled {
157+ return nil // Equilibrium state is reached by previous defered operations
158+ }
159+ return err
136160 }
137161 var readCounter int
138162 switch len (res .Kvs ) {
139163 case 1 :
140164 str := string (res .Kvs [0 ].Value )
141165 readCounter , err = strconv .Atoi (str )
142166 if err != nil {
167+ // Equilibrium state is natievly reached by previous defered operations
143168 return errors .New ("invalid format for " + k + ", got " + str )
144169 }
145170 default :
171+ // Equilibrium state is natievly reached by previous defered operations
146172 return errors .New ("invalid etcd filter for " + k )
147173 }
148174 readCounter --
149175 _ , err = etcdCli .Put (ctx , k , strconv .Itoa (readCounter ))
150176 if err != nil {
151- // Commited no value to etcd so it's fine.
177+ // Committed no value to etcd so it's fine.
152178 // Defered functions will reach the equilibrium state
179+ if err == context .Canceled {
180+ return nil
181+ }
153182 return err
154183 }
155184
156185 if readCounter == 0 {
157186 // Now that we wrote the readcounter, we can't skip the unlock else deadlock
158187 if err := lock .w .Unlock (ctxNc ); err != nil {
159- return err
188+ return err // can't be a context.Canceled as context is uncancelable
160189 }
161190 }
162191
@@ -168,14 +197,18 @@ func (lock *EtcdRWLock) RWLock(ctx context.Context) error {
168197 ctxNc := context .WithoutCancel (ctx )
169198
170199 if err := lock .m2 .Lock (ctx ); err != nil {
171- return err // could be context.Canceled
200+ if err == context .Canceled {
201+ return nil // Never went out of the equilibrium state
202+ }
203+ return err
172204 }
173205
174206 k := fmt .Sprintf ("/chall-manager/%s/writeCounter" , lock .key )
175207 res , err := etcdCli .Get (ctx , k )
176208 if err != nil {
209+ // Manually reach equilibrium state
177210 if err == context .Canceled {
178- return lock .m2 .Unlock (ctxNc ) // stop there, request simply don't need to go further
211+ return lock .m2 .Unlock (ctxNc )
179212 }
180213 return multierr .Combine (err , lock .m2 .Unlock (ctxNc ))
181214 }
@@ -189,23 +222,23 @@ func (lock *EtcdRWLock) RWLock(ctx context.Context) error {
189222 if err != nil {
190223 return multierr .Combine (
191224 errors .New ("invalid format for " + k + ", got " + str ),
192- lock .m2 .Unlock (ctxNc ),
225+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
193226 )
194227 }
195228 default :
196229 return multierr .Combine (
197230 errors .New ("invalid etcd filter for " + k ),
198- lock .m2 .Unlock (ctxNc ),
231+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
199232 )
200233 }
201234 writeCounter ++
202235 _ , perr := etcdCli .Put (ctx , k , strconv .Itoa (writeCounter ))
203236 if perr != nil {
204- // Commited no value to etcd so it's fine.
237+ // Committed no value to etcd so it's fine.
205238 // Defered functions will reach the equilibrium state
206239 return multierr .Combine (
207240 err ,
208- lock .m2 .Unlock (ctxNc ),
241+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
209242 )
210243 }
211244
@@ -214,8 +247,8 @@ func (lock *EtcdRWLock) RWLock(ctx context.Context) error {
214247 if err := lock .r .Lock (ctxNc ); err != nil {
215248 return multierr .Combine (
216249 err ,
217- lock .m2 .Unlock (ctxNc ),
218- lock .w .Lock (ctxNc ), // don't forget we need to lock W to avoid deadlock and keep the equilibrium state
250+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
251+ lock .w .Lock (ctxNc ), // And don't forget we need to lock W to avoid deadlock
219252 )
220253 }
221254 }
@@ -242,16 +275,20 @@ func (lock *EtcdRWLock) RWUnlock(ctx context.Context) error {
242275 // time to profit recoverability.
243276
244277 if err := lock .m2 .Lock (ctx ); err != nil {
245- return err // could be context.Canceled
278+ if err == context .Canceled {
279+ return nil // Never went out of the equilibrium state
280+ }
281+ return err
246282 }
247283
248284 k := fmt .Sprintf ("/chall-manager/%s/writeCounter" , lock .key )
249285 res , err := etcdCli .Get (ctx , k )
250286 if err != nil {
251- return multierr .Combine (
252- err , // Could be context.Canceled
253- lock .m2 .Unlock (ctxNc ),
254- )
287+ // Manually reach equilibrium state
288+ if err == context .Canceled {
289+ return lock .m2 .Unlock (ctxNc )
290+ }
291+ return multierr .Combine (err , lock .m2 .Unlock (ctxNc ))
255292 }
256293 var writeCounter int
257294 switch len (res .Kvs ) {
@@ -261,19 +298,23 @@ func (lock *EtcdRWLock) RWUnlock(ctx context.Context) error {
261298 if err != nil {
262299 return multierr .Combine (
263300 errors .New ("invalid format for " + k + ", got " + str ),
264- lock .m2 .Unlock (ctxNc ),
301+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
265302 )
266303 }
267304 default :
268305 return multierr .Combine (
269306 errors .New ("invalid etcd filter for " + k ),
270- lock .m2 .Unlock (ctxNc ),
307+ lock .m2 .Unlock (ctxNc ), // Manually reach equilibrium state
271308 )
272309 }
273310 writeCounter --
274311 _ , err = etcdCli .Put (ctx , k , strconv .Itoa (writeCounter ))
275312 if err != nil {
276313 // Commited no value to etcd so it's fine.
314+ // Manually reach equilibrium state
315+ if err == context .Canceled {
316+ return lock .m2 .Unlock (ctxNc )
317+ }
277318 return multierr .Combine (
278319 err ,
279320 lock .m2 .Unlock (ctxNc ),
0 commit comments