/**
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.runtime.query;
import org.objectweb.speedo.SpeedoTestHelper;
import org.objectweb.speedo.pobjects.basic.BasicA;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
/**
*
*
* @author S.Chassande-Barrioz
*/
public class TestCreateDeleteDuringQueries extends SpeedoTestHelper {
private static long queryExecTime = 0;
private static long nbqueryok = 0;
private static long nbcreatedone = 0;
private static long nbdeletedone = 0;
private static long errors = 0;
private static long nbprint = 500;
private static int nbRunnerThread = 0;
public static final List pos = new ArrayList();
public final List removed = new ArrayList();
public final static int[] finishedThreads = new int[1];
private synchronized static void queryError(Logger logger, Throwable t) {
logger.log(BasicLevel.ERROR, "", t);
errors ++;
}
private synchronized static void queryOk(Logger logger, int threadId) {
nbqueryok++;
if ((nbqueryok % nbprint) == 0) {
printStat(logger, threadId);
}
}
private static void printStat(Logger logger, int threadId) {
int size = 0;
synchronized (pos) {
size = pos.size();
}
logger.log(BasicLevel.INFO, "Thread " + threadId + ": "
+ " / Que:" + nbqueryok
+ " / Cre:" + nbcreatedone
+ " / Del:" + nbdeletedone
+ " / PO:" + size
+ " / delta:" + (nbcreatedone - nbdeletedone - size)
+ " / Err:" + errors
+ " / F:" + finishedThreads[0] + "/" + nbRunnerThread
);
}
private synchronized static void creationDone(Logger logger, int threadId) {
nbcreatedone++;
if ((nbcreatedone % nbprint) == 0) {
printStat(logger, threadId);
}
}
private synchronized static void deletionDone(Logger logger, int threadId) {
nbdeletedone++;
if ((nbdeletedone % nbprint) == 0) {
printStat(logger, threadId);
}
}
public TestCreateDeleteDuringQueries() {
super("TestCreateDeleteDuringQueries");
}
public TestCreateDeleteDuringQueries(String n) {
super(n);
}
protected String getLoggerName() {
return SpeedoTestHelper.LOG_NAME + ".query.TestCreateDeleteDuringQueries";
}
public void testCreateDeleteDuringQueries1() {
final int createNbThread = getIntProperty(getLoggerName() +".create.nbthread", 5);
final int createNbLoop = getIntProperty(getLoggerName() +".create.loop", 1000);
final int deleteNbThread = getIntProperty(getLoggerName() +".delete.nbthread", 5);
final int deleteNbLoop = getIntProperty(getLoggerName() +".delete.loop", 1000);
final int queryNbThread = getIntProperty(getLoggerName() +".query.nbthread", 3);
testCreateDeleteDuringQueries1(
createNbThread,
createNbLoop,
deleteNbThread,
deleteNbLoop,
queryNbThread);
}
public void testCreateDeleteDuringQueries1(
final int createNbThread,
final int createNbLoop,
final int deleteNbThread,
final int deleteNbLoop,
final int queryNbThread) {
logger.log(BasicLevel.INFO, "TestCreateDeleteDuringQueries1: "
+ "\n\t-create: " + createNbThread + " thread(s) will do " + createNbLoop + " action(s)"
+ "\n\t-delete: " + deleteNbThread + " thread(s) will do " + deleteNbLoop + " action(s)"
+ "\n\t-query: " + queryNbThread + " thread(s)"
);
int nbTotalThread = createNbThread + deleteNbThread + queryNbThread;
nbRunnerThread = createNbThread + deleteNbThread;
Thread[] ts = new Thread[nbTotalThread];
finishedThreads[0] = 0;
int thcounter = 0;
for(int threadType=0; threadType<3; threadType++) {
switch (threadType) {
case 0:
for(int i=0; i<createNbThread; i++) {
final int threadId = thcounter;
ts[thcounter] = new Thread(
new Runnable () {
public void run () {
try {
for (int k = 0; k< createNbLoop; k++) {
create(threadId);
}
} finally {
logger.log(BasicLevel.DEBUG, "thread: " + threadId + " has finished to create");
synchronized (finishedThreads) {
finishedThreads[0]++;
}
}
}
}
);
thcounter++;
}
break;
case 1:
for(int i=0; i<deleteNbThread; i++) {
final int threadId = thcounter;
ts[thcounter] = new Thread(
new Runnable () {
public void run () {
try {
for (int k = 0; k < createNbLoop; k++) {
delete(threadId);
}
} finally {
logger.log(BasicLevel.DEBUG, "thread: " + threadId + " has finished to delete");
synchronized (finishedThreads) {
finishedThreads[0]++;
}
}
}
}
);
thcounter++;
}
break;
case 2:
for(int i=0; i<queryNbThread; i++) {
final int threadId = thcounter;
ts[thcounter] = new Thread(
new Runnable () {
public void run () {
int fts = 0;
do {
synchronized (finishedThreads) {
fts = finishedThreads[0];
}
query(threadId);
} while(fts < (createNbThread + deleteNbThread));
}
}
);
thcounter++;
}
break;
}
}
//shuffle the array of thread
List l = Arrays.asList(ts);
//Collections.shuffle(l);
ts = (Thread[]) l.toArray(new Thread[ts.length]);
//Start threads
long exectime = System.currentTimeMillis();
for(int i=0; i<nbTotalThread; i++) {
ts[i].start();
}
try {
for(int i=0; i<nbTotalThread; i++) {
ts[i].join();
}
} catch (InterruptedException e) {
fail(e.getMessage());
}
exectime = System.currentTimeMillis() - exectime;
long nbRunQuery = nbqueryok + errors;
logger.log(BasicLevel.INFO, "Query successed: "
+ ((nbqueryok * 100) / nbRunQuery) + "% ("
+ nbqueryok + "/" + nbRunQuery + ", "
+ (nbRunQuery - nbqueryok) + " error)");
logger.log(BasicLevel.INFO, "Query average execution time: "
+ (queryExecTime / nbqueryok) +"ms");
logger.log(BasicLevel.INFO, "Rate: " + ((nbqueryok * 1000) / exectime) + " query/sec");
if (errors > 0) {
fail(errors + " errors occured!");
}
}
boolean run = true;
Object o = new Object();
private void stop() {
synchronized(o) {
run = false;
}
}
private synchronized void start() {
synchronized(o) {
run = true;
o.notifyAll();
}
}
private void again() {
synchronized(o) {
while(!run) {
try {
o.wait();
} catch (InterruptedException e) {
}
}
}
}
public void create(final int threadId) {
again();
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
BasicA po = new BasicA();
pm.makePersistent(po);
po.setUndeclaredField(pm.getObjectId(po).toString());
pm.currentTransaction().commit();
pm.close();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
creationDone(logger, threadId);
synchronized (pos) {
pos.add(po);
pos.notifyAll();
}
}
public void delete(final int threadId) {
again();
BasicA po = null;
synchronized (pos) {
while(pos.size() == 0) {
try {
pos.wait();
} catch (InterruptedException e) {
}
}
po = (BasicA) pos.remove(0);
}
if (po != null) {
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
po.writeF1();
Object oid = pm.getObjectId(po);
pm.deletePersistent(po);
synchronized (removed) {
removed.add(oid);
}
pm.currentTransaction().commit();
pm.close();
deletionDone(logger, threadId);
}
}
public void query(final int threadId) {
again();
PersistenceManager pm = pmf.getPersistenceManager();
pm.currentTransaction().begin();
Query q = null;
ArrayList oids = new ArrayList();
Object po = null;
try {
q = pm.newQuery(BasicA.class);
Collection res = (Collection) q.execute();
for (Iterator iter = res.iterator(); iter.hasNext();) {
po = iter.next();
assertNotNull("Result element is null", po);
Object oid = pm.getObjectId(po);
boolean alreadyInRemoved = false;
synchronized (removed) {
alreadyInRemoved = removed.contains(oid);
}
oids.add(oid);
assertTrue("Object already removed !!!!", !alreadyInRemoved);
po = null;
}
q.closeAll();
q = null;
pm.currentTransaction().commit();
pm.close();
pm = null;
queryOk(logger, threadId);
} catch(Throwable t) {
//stop();
queryError(logger, t);
try {
JDOHelper.isPersistent(po);
} catch(Throwable _t) {
}
if (q != null) {
q.closeAll();
}
if (pm != null) {
if (pm.currentTransaction().isActive()) {
pm.currentTransaction().rollback();
}
pm.close();
pm = null;
}
}
oids.clear();
}
}