LockManagerTest.java
/*
** Module :LockManagerTest.java
** Abstract :
**
** Copyright (c) 2005-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- -T- --JPRM-- ----------------Description-----------------
** 001 SIY 20050304 ADD @20364 Created initial version.
** 002 SIY 20050429 CHG @21020 Fixed formatting.
** 003 SIY 20080627 CHG @38972 Minor changes for more convenient results
** checking.
** 004 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.directory;
import com.goldencode.p2j.util.logging.*;
import java.util.Random;
/**
* Class LockManagerTest performs careful testing of the LockManager.
*
* @author SIY
* @version 1.0
*/
class LockManagerTest
{
/** Logger */
private static final CentralLogger LOG = CentralLogger.get(LockManagerTest.class);
/** Names of the lock types */
private static String[] lockNames = new String[]
{ "RO", "RW", "RX", "WX" };
/** Number of passes for each test */
private static final int numPasses = 100;
/** List of IDs to lock for the R/O locks */
private static String[] pathLocksRO = new String[]
{
"/security/users",
"/resources/entry/one",
"/configuration/configC"
};
/** List of IDs to lock for the R/W locks */
private static String[] pathLocksRW = new String[]
{
"/resources/entry",
"/security/users/john",
"/configuration/configB"
};
/** List of IDs to lock for the R/X locks */
private static String[] pathLocksRX = new String[]
{
"/configuration/configA",
"/security",
"/resources/entry/two"
};
/**
* Sleep for specified amount of time. Basically this is just a wrapper for
* the Thread.sleep() with all exceptions handled.
*
* @param millis
* Sleep interval in milliseconds.
*/
static void sleep(int millis)
{
try
{
Thread.sleep(millis);
}
catch (Exception e)
{
LOG.warning("", e);
}
}
/**
* This class is used to check setting/getting of R/O locks.
*/
static class LockTester
implements Runnable
{
/** Thread ID */
int tid;
/** LockManager which will be tested */
private LockManager lockManager;
/** List of paths to use */
private String[] locksList;
/** Lock type to generate */
private int type;
/**
* Construct an instance of LockTester.
*
* @param tid
* Thread ID.
* @param man
* A reference to LockManager for test.
* @param locksList
* An array of IDs for test.
* @param type
* Lock type.
*/
public LockTester(int tid, LockManager man, String[] locksList, int type)
{
this.tid = tid;
this.lockManager = man;
this.locksList = locksList;
this.type = type;
}
/**
* Perform test.
*
* @see java.lang.Runnable#run()
*/
public void run()
{
Random rnd = new Random();
String text = null;
lockManager.dumpLocks("Thread start " + tid);
LOG.info("Starting " + tid);
for (int i = 0; i < numPasses; i++)
{
int num = rnd.nextInt(locksList.length);
text = new String(locksList[num] + " type:" + lockNames[type]
+ " TID:" + tid + " pass: " + i);
//lockManager.dumpLocks("at start of iteration " + text);
try
{
System.out.println("locking " + text);
Object lock = lockManager.enterLock(locksList[num], type);
System.out.println("locked " + text);
//Sleep for some time
sleep(rnd.nextInt(100));
if (type == LockManager.LOCK_RX)
{
System.out.println("upgrading " + text);
lockManager.upgradeLock(lock);
System.out.println("upgraded " + text);
sleep(rnd.nextInt(100));
}
System.out.println("releasing " + text);
lockManager.releaseLock(lock);
System.out.println("released " + text);
}
catch (Exception e)
{
LOG.warning("", e);
}
}
lockManager.dumpLocks("Thread stop " + tid);
LOG.info("Finished " + tid);
}
}
/**
* Main application entry point.
*
* @param args
* Array of command line parameters.
*/
public static void main(String[] args)
{
//Create an instance of LockManager
LockManager man = new LockManager();
//Simplest tests:
System.out.println("Test set #1 (simple R/O locks)");
Object l0 = man.enterLock("/a", LockManager.LOCK_RO);
Object l1 = man.enterLock("/b", LockManager.LOCK_RO);
Object l2 = man.enterLock("/c", LockManager.LOCK_RO);
Object l3 = man.enterLock("/b", LockManager.LOCK_RO);
Object l4 = man.enterLock("/a", LockManager.LOCK_RO);
Object l5 = man.enterLock("/b", LockManager.LOCK_RO);
Object l6 = man.enterLock("/c", LockManager.LOCK_RO);
Object l7 = man.enterLock("/b", LockManager.LOCK_RO);
man.dumpLocks("After adding locks");
man.releaseLock(l0);
man.releaseLock(l1);
man.releaseLock(l2);
man.releaseLock(l3);
man.releaseLock(l4);
man.releaseLock(l5);
man.releaseLock(l6);
man.releaseLock(l7);
man.dumpLocks("After releasing locks");
System.out.println("Test set #2 (simple R/O and R/W locks)");
l0 = man.enterLock("/a", LockManager.LOCK_RO);
l1 = man.enterLock("/b", LockManager.LOCK_RW);
l2 = man.enterLock("/c", LockManager.LOCK_RO);
l3 = man.enterLock("/b", LockManager.LOCK_RO);
l4 = man.enterLock("/a", LockManager.LOCK_RW);
l5 = man.enterLock("/b", LockManager.LOCK_RW);
l6 = man.enterLock("/c", LockManager.LOCK_RW);
l7 = man.enterLock("/b", LockManager.LOCK_RW);
man.dumpLocks("After adding locks");
man.releaseLock(l0);
man.releaseLock(l1);
man.releaseLock(l2);
man.releaseLock(l3);
man.releaseLock(l4);
man.releaseLock(l5);
man.releaseLock(l6);
man.releaseLock(l7);
man.dumpLocks("After releasing locks");
System.out.println("Test set #3 (mix of R/X and R/O locks)");
l0 = man.enterLock("/a", LockManager.LOCK_RX);
l1 = man.enterLock("/a", LockManager.LOCK_RO);
l2 = man.enterLock("/a", LockManager.LOCK_RO);
l3 = man.enterLock("/a", LockManager.LOCK_RO);
man.dumpLocks("After adding locks");
man.releaseLock(l3);
man.releaseLock(l1);
man.releaseLock(l0);
man.releaseLock(l2);
man.dumpLocks("After releasing locks");
//Create a number of various lock testers
System.out.println("Test set #4 (heavy multi-threaded access)");
LockTester[] tests =
{
//Direct tests: each type with its own set of lock IDs,
//Two instances of each type to enforce conflicts
new LockTester(1, man, pathLocksRO, LockManager.LOCK_RO),
new LockTester(2, man, pathLocksRO, LockManager.LOCK_RO),
new LockTester(3, man, pathLocksRW, LockManager.LOCK_RW),
new LockTester(4, man, pathLocksRW, LockManager.LOCK_RW),
new LockTester(5, man, pathLocksRX, LockManager.LOCK_RX),
new LockTester(6, man, pathLocksRX, LockManager.LOCK_RX),
//"Crossover" tests: each lock type with other set of lock IDs
new LockTester(7, man, pathLocksRW, LockManager.LOCK_RO),
new LockTester(8, man, pathLocksRX, LockManager.LOCK_RO),
new LockTester(9, man, pathLocksRO, LockManager.LOCK_RW),
new LockTester(10, man, pathLocksRX, LockManager.LOCK_RW),
new LockTester(11, man, pathLocksRO, LockManager.LOCK_RX),
new LockTester(12, man, pathLocksRW, LockManager.LOCK_RX)
};
Thread[] threads = new Thread[tests.length];
int i;
for (i = 0; i < threads.length; i++)
threads[i] = new Thread(tests[i]);
for (i = 0; i < threads.length; i++)
threads[i].start();
for (i = 0; i < threads.length; i++)
{
try
{
threads[i].join();
}
catch (Exception e)
{
LOG.warning("", e);
}
}
man.dumpLocks("After finishing threads");
}
}