82
82
* @author Vedran Pavic
83
83
* @author Unseok Kim
84
84
* @author Anton Gabov
85
+ * @author Eddie Cho
85
86
*
86
87
* @since 4.0
87
88
*
@@ -95,7 +96,7 @@ public final class RedisLockRegistry implements ExpirableLockRegistry, Disposabl
95
96
private static final int DEFAULT_CAPACITY = 100_000 ;
96
97
97
98
private final Map <String , RedisLock > locks =
98
- new LinkedHashMap <String , RedisLock >(16 , 0.75F , true ) {
99
+ new LinkedHashMap <>(16 , 0.75F , true ) {
99
100
100
101
@ Override
101
102
protected boolean removeEldestEntry (Entry <String , RedisLock > eldest ) {
@@ -331,12 +332,12 @@ public long getLockedAt() {
331
332
/**
332
333
* Unlock the lock using the unlink method in redis.
333
334
*/
334
- protected abstract void removeLockKeyInnerUnlink ();
335
+ protected abstract boolean removeLockKeyInnerUnlink ();
335
336
336
337
/**
337
338
* Unlock the lock using the delete method in redis.
338
339
*/
339
- protected abstract void removeLockKeyInnerDelete ();
340
+ protected abstract boolean removeLockKeyInnerDelete ();
340
341
341
342
@ Override
342
343
public final void lock () {
@@ -442,11 +443,6 @@ public final void unlock() {
442
443
return ;
443
444
}
444
445
try {
445
- if (!isAcquiredInThisProcess ()) {
446
- throw new IllegalStateException ("Lock was released in the store due to expiration. " +
447
- "The integrity of data protected by this lock may have been compromised." );
448
- }
449
-
450
446
if (Thread .currentThread ().isInterrupted ()) {
451
447
RedisLockRegistry .this .executor .execute (this ::removeLockKey );
452
448
}
@@ -469,7 +465,11 @@ public final void unlock() {
469
465
private void removeLockKey () {
470
466
if (RedisLockRegistry .this .unlinkAvailable ) {
471
467
try {
472
- removeLockKeyInnerUnlink ();
468
+ boolean unlinkResult = removeLockKeyInnerUnlink ();
469
+ if (!unlinkResult ) {
470
+ throw new IllegalStateException ("Lock was released in the store due to expiration. " +
471
+ "The integrity of data protected by this lock may have been compromised." );
472
+ }
473
473
return ;
474
474
}
475
475
catch (Exception ex ) {
@@ -484,7 +484,10 @@ private void removeLockKey() {
484
484
}
485
485
}
486
486
}
487
- removeLockKeyInnerDelete ();
487
+ if (!removeLockKeyInnerDelete ()) {
488
+ throw new IllegalStateException ("Lock was released in the store due to expiration. " +
489
+ "The integrity of data protected by this lock may have been compromised." );
490
+ }
488
491
}
489
492
490
493
@ Override
@@ -547,19 +550,23 @@ private RedisLockRegistry getOuterType() {
547
550
548
551
private final class RedisPubSubLock extends RedisLock {
549
552
550
- private static final String UNLINK_UNLOCK_SCRIPT =
551
- "if (redis.call('unlink', KEYS[1]) == 1) then " +
552
- "redis.call('publish', ARGV[1], KEYS[1]) " +
553
- "return true " +
554
- "end " +
555
- "return false" ;
556
-
557
- private static final String DELETE_UNLOCK_SCRIPT =
558
- "if (redis.call('del', KEYS[1]) == 1) then " +
559
- "redis.call('publish', ARGV[1], KEYS[1]) " +
560
- "return true " +
561
- "end " +
562
- "return false" ;
553
+ private static final String UNLINK_UNLOCK_SCRIPT = """
554
+ local lockClientId = redis.call('GET', KEYS[1])
555
+ if (lockClientId == ARGV[1] and redis.call('UNLINK', KEYS[1]) == 1) then
556
+ redis.call('PUBLISH', ARGV[2], KEYS[1])
557
+ return true
558
+ end
559
+ return false
560
+ """ ;
561
+
562
+ private static final String DELETE_UNLOCK_SCRIPT = """
563
+ local lockClientId = redis.call('GET', KEYS[1])
564
+ if (lockClientId == ARGV[1] and redis.call('DEL', KEYS[1]) == 1) then
565
+ redis.call('PUBLISH', ARGV[2], KEYS[1])
566
+ return true
567
+ end
568
+ return false
569
+ """ ;
563
570
564
571
private static final RedisScript <Boolean >
565
572
UNLINK_UNLOCK_REDIS_SCRIPT = new DefaultRedisScript <>(UNLINK_UNLOCK_SCRIPT , Boolean .class );
@@ -577,18 +584,19 @@ protected boolean tryRedisLockInner(long time) throws ExecutionException, Interr
577
584
}
578
585
579
586
@ Override
580
- protected void removeLockKeyInnerUnlink () {
581
- RedisLockRegistry .this .redisTemplate .execute (
582
- UNLINK_UNLOCK_REDIS_SCRIPT , Collections .singletonList (this .lockKey ),
583
- RedisLockRegistry .this .unLockChannelKey );
587
+ protected boolean removeLockKeyInnerUnlink () {
588
+ return removeLockKeyWithScript (UNLINK_UNLOCK_REDIS_SCRIPT );
584
589
}
585
590
586
591
@ Override
587
- protected void removeLockKeyInnerDelete () {
588
- RedisLockRegistry .this .redisTemplate .execute (
589
- DELETE_UNLOCK_REDIS_SCRIPT , Collections .singletonList (this .lockKey ),
590
- RedisLockRegistry .this .unLockChannelKey );
592
+ protected boolean removeLockKeyInnerDelete () {
593
+ return removeLockKeyWithScript (DELETE_UNLOCK_REDIS_SCRIPT );
594
+ }
591
595
596
+ private boolean removeLockKeyWithScript (RedisScript <Boolean > redisScript ) {
597
+ return Boolean .TRUE .equals (RedisLockRegistry .this .redisTemplate .execute (
598
+ redisScript , Collections .singletonList (this .lockKey ),
599
+ RedisLockRegistry .this .clientId , RedisLockRegistry .this .unLockChannelKey ));
592
600
}
593
601
594
602
private boolean subscribeLock (long time ) throws ExecutionException , InterruptedException {
@@ -678,6 +686,30 @@ private void unlockNotify(String lockKey) {
678
686
679
687
private final class RedisSpinLock extends RedisLock {
680
688
689
+ private static final String UNLINK_UNLOCK_SCRIPT = """
690
+ local lockClientId = redis.call('GET', KEYS[1])
691
+ if lockClientId == ARGV[1] then
692
+ redis.call('UNLINK', KEYS[1])
693
+ return true
694
+ end
695
+ return false
696
+ """ ;
697
+
698
+ private static final String DELETE_UNLOCK_SCRIPT = """
699
+ local lockClientId = redis.call('GET', KEYS[1])
700
+ if lockClientId == ARGV[1] then
701
+ redis.call('DEL', KEYS[1])
702
+ return true
703
+ end
704
+ return false
705
+ """ ;
706
+
707
+ private static final RedisScript <Boolean >
708
+ UNLINK_UNLOCK_REDIS_SCRIPT = new DefaultRedisScript <>(UNLINK_UNLOCK_SCRIPT , Boolean .class );
709
+
710
+ private static final RedisScript <Boolean >
711
+ DELETE_UNLOCK_REDIS_SCRIPT = new DefaultRedisScript <>(DELETE_UNLOCK_SCRIPT , Boolean .class );
712
+
681
713
private RedisSpinLock (String path ) {
682
714
super (path );
683
715
}
@@ -702,13 +734,19 @@ protected boolean tryRedisLockInner(long time) throws InterruptedException {
702
734
}
703
735
704
736
@ Override
705
- protected void removeLockKeyInnerUnlink () {
706
- RedisLockRegistry . this . redisTemplate . unlink ( this . lockKey );
737
+ protected boolean removeLockKeyInnerUnlink () {
738
+ return removeLockKeyWithScript ( UNLINK_UNLOCK_REDIS_SCRIPT );
707
739
}
708
740
709
741
@ Override
710
- protected void removeLockKeyInnerDelete () {
711
- RedisLockRegistry .this .redisTemplate .delete (this .lockKey );
742
+ protected boolean removeLockKeyInnerDelete () {
743
+ return removeLockKeyWithScript (DELETE_UNLOCK_REDIS_SCRIPT );
744
+ }
745
+
746
+ private boolean removeLockKeyWithScript (RedisScript <Boolean > redisScript ) {
747
+ return Boolean .TRUE .equals (RedisLockRegistry .this .redisTemplate .execute (
748
+ redisScript , Collections .singletonList (this .lockKey ),
749
+ RedisLockRegistry .this .clientId ));
712
750
}
713
751
714
752
}
0 commit comments