All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.stabilizer.tests.concurrent.lock.LockTest Maven / Gradle / Ivy

The newest version!
package com.hazelcast.stabilizer.tests.concurrent.lock;

import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IAtomicLong;
import com.hazelcast.core.ILock;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.stabilizer.tests.TestContext;
import com.hazelcast.stabilizer.tests.TestRunner;
import com.hazelcast.stabilizer.tests.annotations.Run;
import com.hazelcast.stabilizer.tests.annotations.Setup;
import com.hazelcast.stabilizer.tests.annotations.Teardown;
import com.hazelcast.stabilizer.tests.annotations.Verify;
import com.hazelcast.stabilizer.tests.annotations.Warmup;
import com.hazelcast.stabilizer.tests.utils.ThreadSpawner;

import java.util.Random;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class LockTest {

    private final static ILogger log = Logger.getLogger(LockTest.class);

    public int lockCount = 500;
    public int threadCount = 10;
    public int initialAmount = 1000;
    public int amount = 50;
    public int logFrequency = 1000;

    private IAtomicLong lockCounter;
    private IAtomicLong totalMoney;
    private HazelcastInstance targetInstance;
    public String basename = "lock";
    private TestContext testContext;

    @Setup
    public void setup(TestContext testContext) throws Exception {
        this.testContext = testContext;
        targetInstance = testContext.getTargetInstance();

        lockCounter = targetInstance.getAtomicLong(testContext.getTestId() + ":LockCounter");
        totalMoney = targetInstance.getAtomicLong(testContext.getTestId() + ":TotalMoney");
    }

    @Warmup(global = true)
    public void warmup() throws Exception {
        for (int k = 0; k < lockCount; k++) {
            long key = lockCounter.getAndIncrement();
            targetInstance.getLock(getLockId(key));
            IAtomicLong account = targetInstance.getAtomicLong(getAccountId(key));
            account.set(initialAmount);
            totalMoney.addAndGet(initialAmount);
        }
    }

    @Run
    public void run() {
        ThreadSpawner spawner = new ThreadSpawner(testContext.getTestId());
        for (int k = 0; k < threadCount; k++) {
            spawner.spawn(new Worker());
        }
        spawner.awaitCompletion();
    }

    private String getLockId(long key) {
        return basename + "-" + testContext.getTestId() + "-" + key;
    }

    private String getAccountId(long key) {
        return basename + "-" + testContext.getTestId() + "-" + key;
    }

    @Verify
    public void verify() {
        long actual = 0;
        for (long k = 0; k < lockCounter.get(); k++) {
            ILock lock = targetInstance.getLock(getLockId(k));
            assertFalse("Lock should be unlocked", lock.isLocked());

            IAtomicLong account = targetInstance.getAtomicLong(getAccountId(k));
            assertTrue("Amount can't be smaller than zero on account", account.get() >= 0);
            actual += account.get();
        }

        long expected = totalMoney.get();
        assertEquals("Money was lost/created", expected, actual);
    }

    @Teardown
    public void teardown() throws Exception {
        lockCounter.destroy();
        totalMoney.destroy();

        for (long k = 0; k < lockCounter.get(); k++) {
            targetInstance.getLock(getLockId(k)).destroy();
            targetInstance.getAtomicLong(getAccountId(k)).destroy();
        }
    }

    private class Worker implements Runnable {
        private final Random random = new Random();

        @Override
        public void run() {
            long iteration = 0;
            while (!testContext.isStopped()) {
                long key1 = getRandomAccountKey();
                long key2 = getRandomAccountKey();
                int a = random.nextInt(amount);

                IAtomicLong account1 = targetInstance.getAtomicLong(getAccountId(key1));
                ILock lock1 = targetInstance.getLock(getLockId(key1));
                IAtomicLong account2 = targetInstance.getAtomicLong(getAccountId(key2));
                ILock lock2 = targetInstance.getLock(getLockId(key2));

                if (!lock1.tryLock()) {
                    continue;
                }

                try {
                    if (!lock2.tryLock()) {
                        continue;
                    }

                    try {
                        if (account1.get() < 0 || account2.get() < 0) {
                            throw new RuntimeException("Amount on account can't be smaller than 0");
                        }

                        if (account1.get() < a) {
                            continue;
                        }

                        account1.set(account1.get() - a);
                        account2.set(account2.get() + a);
                    } finally {
                        lock2.unlock();
                    }

                } finally {
                    lock1.unlock();
                }

                if (iteration % logFrequency == 0) {
                    log.info(Thread.currentThread().getName() + " At iteration: " + iteration);
                }

                iteration++;
            }

            totalMoney.addAndGet(iteration);
        }

        private long getRandomAccountKey() {
            long key = random.nextLong() % lockCounter.get();

            if (key < 0) key = -key;
            return key;
        }
    }

    public static void main(String[] args) throws Throwable {
        LockTest test = new LockTest();
        new TestRunner(test).withDuration(10).run();
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy