Search in sources :

Example 76 with RLock

use of org.redisson.api.RLock in project redisson by redisson.

the class RedissonFairLockTest method testIsLocked.

@Test
public void testIsLocked() {
    RLock lock = redisson.getFairLock("lock");
    Assertions.assertFalse(lock.isLocked());
    lock.lock();
    Assertions.assertTrue(lock.isLocked());
    lock.unlock();
    Assertions.assertFalse(lock.isLocked());
}
Also used : RLock(org.redisson.api.RLock) Test(org.junit.jupiter.api.Test)

Example 77 with RLock

use of org.redisson.api.RLock in project redisson by redisson.

the class RedissonFairLockTest method testMultipleLocks.

@Test
public void testMultipleLocks() throws InterruptedException {
    ExecutorService executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 1000L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
    Config cfg = createConfig();
    cfg.useSingleServer().setSubscriptionsPerConnection(100);
    RedissonClient redisson = Redisson.create(cfg);
    AtomicInteger acquiredLocks = new AtomicInteger();
    for (int i = 0; i < 500; i++) {
        executorService.submit(new Runnable() {

            @Override
            public void run() {
                RLock test = redisson.getFairLock("lock");
                try {
                    test.lock(5, TimeUnit.SECONDS);
                    try {
                        // 200ms
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    acquiredLocks.incrementAndGet();
                } finally {
                    test.unlock();
                }
            }
        });
    }
    executorService.shutdown();
    assertThat(executorService.awaitTermination(3, TimeUnit.MINUTES)).isTrue();
    assertThat(acquiredLocks.get()).isEqualTo(500);
    redisson.shutdown();
}
Also used : RedissonClient(org.redisson.api.RedissonClient) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Config(org.redisson.config.Config) RLock(org.redisson.api.RLock) Test(org.junit.jupiter.api.Test)

Example 78 with RLock

use of org.redisson.api.RLock in project redisson by redisson.

the class RedissonFairLockTest method testWaitTimeoutDrift.

@Test
public void testWaitTimeoutDrift() throws Exception {
    int leaseTimeSeconds = 30;
    RLock lock = redisson.getFairLock("test-fair-lock");
    AtomicBoolean lastThreadTryingToLock = new AtomicBoolean(false);
    // create a scenario where the same 3 threads keep on trying to get a lock
    // to exacerbate the problem, use a very short wait time and a long lease time
    // this will end up setting the queue timeout score to a value far away in the future
    ExecutorService executor = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 50; i++) {
        final int finalI = i;
        executor.submit(() -> {
            log.info("running " + finalI + " in thread " + Thread.currentThread().getId());
            try {
                if (lock.tryLock(500, leaseTimeSeconds * 1000, TimeUnit.MILLISECONDS)) {
                    log.info("Lock taken by thread " + Thread.currentThread().getId());
                    Thread.sleep(10000);
                    try {
                        // this could fail before use sleep for the same value as the lock expiry, that's fine
                        // for the purpose of this test
                        lock.unlock();
                        log.info("Lock released by thread " + Thread.currentThread().getId());
                    } catch (Exception ignored) {
                    }
                }
            } catch (InterruptedException ex) {
                log.warn("Interrupted " + Thread.currentThread().getId());
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        });
        // attempting to lock do so in a staggered pattern. This delay will be carried over by the thread pool.
        if (i < 3) {
            Thread.sleep(50);
        }
    }
    // we now launch one more thread and kill it before it manages to fail and clean up
    // that thread will end up with a timeout that will prevent any others from taking the lock for a long time
    executor.submit(() -> {
        log.info("Final thread trying to take the lock with thread id: " + Thread.currentThread().getId());
        try {
            lastThreadTryingToLock.set(true);
            if (lock.tryLock(30000, 30000, TimeUnit.MILLISECONDS)) {
                log.info("Lock taken by final thread " + Thread.currentThread().getId());
                Thread.sleep(1000);
                lock.unlock();
                log.info("Lock released by final thread " + Thread.currentThread().getId());
            }
        } catch (InterruptedException ex) {
            log.warn("Interrupted " + Thread.currentThread().getId());
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
    });
    // now we wait for all others threads to stop trying, and only the last thread is running
    while (!lastThreadTryingToLock.get()) {
        Thread.sleep(100);
    }
    // try to kill that last thread, and don't let it clean up after itself
    executor.shutdownNow();
    // force the lock to unlock just in case
    try {
        lock.forceUnlock();
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
    if (lock.isLocked()) {
        Assertions.fail("Lock should have been unlocked by now");
    }
    // check the timeout scores - they should all be within a reasonable amount of time from now
    List<Long> queue = redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_ONLY, "local result = {}; " + "local timeouts = redis.call('zrange', KEYS[1], 0, 99, 'WITHSCORES'); " + "for i=1,#timeouts,2 do " + "table.insert(result, timeouts[i+1]); " + "end; " + "return result; ", RScript.ReturnType.MULTI, Collections.singletonList("redisson_lock_timeout:{test-fair-lock}"));
    int i = 0;
    for (Long timeout : queue) {
        long epiry = ((timeout - new Date().getTime()) / 1000);
        log.info("Item " + (i++) + " expires in " + epiry + " seconds");
        // the Redisson library uses this 60000*5ms delay in the code
        if (epiry > leaseTimeSeconds + 60 * 5) {
            Assertions.fail("It would take more than " + leaseTimeSeconds + "s to get the lock!");
        }
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RLock(org.redisson.api.RLock) Date(java.util.Date) Test(org.junit.jupiter.api.Test)

Example 79 with RLock

use of org.redisson.api.RLock in project redisson by redisson.

the class RedissonFairLockTest method testLockAcquiredTimeoutDrift.

@Test
public void testLockAcquiredTimeoutDrift() throws Exception {
    int leaseTimeSeconds = 30;
    RLock lock = redisson.getFairLock("test-fair-lock");
    // create a scenario where the same 3 threads keep on trying to get a lock
    // to exacerbate the problem, use a very short wait time and a long lease time
    // this will end up setting the queue timeout score to a value far away in the future
    ExecutorService executor = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 3; i++) {
        final int finalI = i;
        executor.submit(() -> {
            log.info("running " + finalI + " in thread " + Thread.currentThread().getId());
            try {
                if (lock.tryLock(3000, leaseTimeSeconds * 1000, TimeUnit.MILLISECONDS)) {
                    log.info("Lock taken by thread " + Thread.currentThread().getId());
                    Thread.sleep(100);
                    try {
                        // this could fail before use sleep for the same value as the lock expiry, that's fine
                        // for the purpose of this test
                        lock.unlock();
                        log.info("Lock released by thread " + Thread.currentThread().getId());
                    } catch (Exception ignored) {
                    }
                }
            } catch (InterruptedException ex) {
                log.warn("Interrupted " + Thread.currentThread().getId());
            } catch (Exception ex) {
                log.error(ex.getMessage(), ex);
            }
        });
        // for the first 3 threads, add a 50ms delay. This is to recreate the worst case scenario, where all threads
        // attempting to lock do so in a staggered pattern. This delay will be carried over by the thread pool.
        Thread.sleep(50);
    }
    AtomicBoolean lastThreadTryingToLock = new AtomicBoolean(false);
    // we now launch one more thread and kill it before it manages to fail and clean up
    // that thread will end up with a timeout that will prevent any others from taking the lock for a long time
    executor.submit(() -> {
        log.info("Final thread trying to take the lock with thread id: " + Thread.currentThread().getId());
        try {
            lastThreadTryingToLock.set(true);
            if (lock.tryLock(30000, 30000, TimeUnit.MILLISECONDS)) {
                log.info("Lock taken by final thread " + Thread.currentThread().getId());
                Thread.sleep(1000);
                lock.unlock();
                log.info("Lock released by final thread " + Thread.currentThread().getId());
            }
        } catch (InterruptedException ex) {
            log.warn("Interrupted");
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
    });
    // now we wait for all others threads to stop trying, and only the last thread is running
    while (!lastThreadTryingToLock.get()) {
        Thread.sleep(100);
    }
    // try to kill that last thread, and don't let it clean up after itself
    executor.shutdownNow();
    // force the lock to unlock just in case
    try {
        lock.forceUnlock();
    } catch (Exception e) {
        log.error(e.getMessage(), e);
    }
    if (lock.isLocked()) {
        Assertions.fail("Lock should have been unlocked by now");
    }
    // check the timeout scores - they should all be within a reasonable amount of time from now
    List<Long> queue = redisson.getScript(LongCodec.INSTANCE).eval(RScript.Mode.READ_ONLY, "local result = {}; " + "local timeouts = redis.call('zrange', KEYS[1], 0, 99, 'WITHSCORES'); " + "for i=1,#timeouts,2 do " + "table.insert(result, timeouts[i+1]); " + "end; " + "return result; ", RScript.ReturnType.MULTI, Collections.singletonList("redisson_lock_timeout:{test-fair-lock}"));
    int i = 0;
    for (Long timeout : queue) {
        long epiry = ((timeout - new Date().getTime()) / 1000);
        log.info("Item " + (i++) + " expires in " + epiry + " seconds");
        // the Redisson library uses this 5000ms delay in the code
        if (epiry > leaseTimeSeconds + 60 * 5) {
            Assertions.fail("It would take more than " + leaseTimeSeconds + "s to get the lock!");
        }
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) RLock(org.redisson.api.RLock) Date(java.util.Date) Test(org.junit.jupiter.api.Test)

Example 80 with RLock

use of org.redisson.api.RLock in project redisson by redisson.

the class RedissonFairLockTest method testGetHoldCount.

@Test
public void testGetHoldCount() {
    RLock lock = redisson.getFairLock("lock");
    Assertions.assertEquals(0, lock.getHoldCount());
    lock.lock();
    Assertions.assertEquals(1, lock.getHoldCount());
    lock.unlock();
    Assertions.assertEquals(0, lock.getHoldCount());
    lock.lock();
    lock.lock();
    Assertions.assertEquals(2, lock.getHoldCount());
    lock.unlock();
    Assertions.assertEquals(1, lock.getHoldCount());
    lock.unlock();
    Assertions.assertEquals(0, lock.getHoldCount());
}
Also used : RLock(org.redisson.api.RLock) Test(org.junit.jupiter.api.Test)

Aggregations

RLock (org.redisson.api.RLock)113 Test (org.junit.jupiter.api.Test)77 RedissonClient (org.redisson.api.RedissonClient)21 RReadWriteLock (org.redisson.api.RReadWriteLock)18 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)13 RedisProcess (org.redisson.RedisRunner.RedisProcess)12 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)11 CacheLoaderException (javax.cache.integration.CacheLoaderException)10 CacheWriterException (javax.cache.integration.CacheWriterException)10 EntryProcessorException (javax.cache.processor.EntryProcessorException)10 Config (org.redisson.config.Config)10 ExecutorService (java.util.concurrent.ExecutorService)8 Test (org.junit.Test)6 RedissonObject (org.redisson.RedissonObject)4 RSemaphore (org.redisson.api.RSemaphore)4 SecureRandom (java.security.SecureRandom)3 Date (java.util.Date)3 Random (java.util.Random)3 CountDownLatch (java.util.concurrent.CountDownLatch)3 Lock (java.util.concurrent.locks.Lock)3