/*
* Copyright 2009 Udai Gupta, Ralf Joachim
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.castor.cpa.test.test07;
import java.util.Random;
import junit.framework.Assert;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.exolab.castor.jdo.Database;
import org.exolab.castor.jdo.JDOManager;
import org.exolab.castor.jdo.LockNotGrantedException;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.jdo.TransactionAbortedException;
import org.exolab.castor.jdo.TransactionNotInProgressException;
import org.junit.Ignore;
/**
* This is write thread that continuously create, load and modify,
* load and test if the modification is succeed, load and remove
* data objects and create again. This threads is the only thread
* that modifies data objects. If any inconsistency detected, for
* examples, modification is not persisted, deleted object reappears,
* created object disappeared, we can confirm there is problem in
* the concurrent engine of Castor JDO.
*/
@Ignore
public class CreateDeleteThread extends Thread {
/**
* The <a href="http://jakarta.apache.org/commons/logging/">Jakarta
* Commons Logging</a> instance used for all logging.
*/
private static final Log LOG = LogFactory.getLog(CreateDeleteThread.class);
private Database _db;
private int _cachetype;
private int _trials;
private boolean _isDone;
private Random _random;
/** Number of retrials attempt to load per each trial */
public static final int NUM_OF_RETRIAL = 20;
/** The base time in milliseconds between each attempts */
public static final int SLEEP_BASE_TIME = 100;
CreateDeleteThread(final TestCacheLeakage parent,
final JDOManager jdo,
final int cachetype, final int trials) throws Exception {
_db = jdo.getDatabase();
_cachetype = cachetype;
_trials = trials;
_random = new Random();
}
public void run() {
try {
LOG.info("start testing");
Race tr;
Race testrace;
boolean succeed;
int trials;
out:
for (int i = 0; i < _trials; i++) {
// create, modified, delete object, depending on the
// current cache type
try {
switch (_cachetype) {
case 0:
testrace = new RaceCount();
testrace.setId(5);
break;
case 1:
testrace = new RaceTime();
testrace.setId(5);
break;
case 2:
testrace = new RaceNone();
testrace.setId(5);
break;
case 3:
testrace = new RaceUnlimited();
testrace.setId(5);
break;
default:
testrace = null;
}
_db.begin();
_db.create(testrace);
// may throw DuplicateIdentityException
_db.commit();
// load it and modify it
succeed = false;
trials = 0;
while (!succeed && trials < NUM_OF_RETRIAL) {
trials++;
try {
_db.begin();
tr = (Race) _db.load(TestCacheLeakage.getClassType(),
Race.DEFAULT_ID);
// may throw ObjectNotFoundException
// or LockNotGrantedException
tr.incValue1();
_db.commit();
succeed = true;
} catch (LockNotGrantedException ex) {
succeed = false;
rollbackAndSleep(trials);
} catch (TransactionAbortedException ex) {
succeed = false;
rollbackAndSleep(trials);
}
}
if (_db.isActive()) { _db.rollback(); }
// load it and release it
succeed = false;
trials = 0;
while (!succeed && trials < NUM_OF_RETRIAL) {
trials++;
try {
_db.begin();
tr = (Race) _db.load(TestCacheLeakage.getClassType(),
Race.DEFAULT_ID);
// may throw ObjectNotFoundException
// or LockNotGrantedException
_db.commit();
succeed = true;
} catch (LockNotGrantedException ex) {
succeed = false;
rollbackAndSleep(trials);
}
}
if (_db.isActive()) { _db.rollback(); }
// load it and delete it
succeed = false;
trials = 0;
while (!succeed && trials < NUM_OF_RETRIAL) {
trials++;
try {
_db.begin();
tr = (Race) _db.load(TestCacheLeakage.getClassType(),
Race.DEFAULT_ID);
// may throw ObjectNotFoundException
// or LockNotGrantedException
_db.remove(tr);
_db.commit();
succeed = true;
} catch (LockNotGrantedException ex) {
succeed = false;
rollbackAndSleep(trials);
} catch (TransactionAbortedException ex) {
succeed = false;
rollbackAndSleep(trials);
}
}
if (_db.isActive()) { _db.rollback(); }
if (!succeed) {
throw new Exception(
"Transaction can't lock the object within "
+ trials + " trials");
}
} catch (TransactionNotInProgressException ex) {
LOG.error("Thread <CreateDelete> will be killed. "
+ "Unexcepted exception: ", ex);
rollbackWhenActive();
TestCacheLeakage.setErrLeak(true);
break out;
} catch (PersistenceException ex) {
LOG.error("Thread <CreateDelete> will be killed. "
+ "Unexcepted exception: ", ex);
rollbackWhenActive();
TestCacheLeakage.setErrLeak(true);
break out;
} catch (Exception ex) {
LOG.error("Thread <CreateDelete> will be killed. "
+ "Element not found (other): ", ex);
rollbackWhenActive();
TestCacheLeakage.setErrLeak(true);
break out;
}
}
} finally {
_isDone = true;
try {
_db.close();
} catch (PersistenceException ex) {
Assert.fail(ex.toString());
}
}
}
private void rollbackAndSleep(final int trials)
throws TransactionNotInProgressException, InterruptedException {
_db.rollback();
// ethernet way of retry
Thread.sleep((long) ((SLEEP_BASE_TIME ^ trials)
* _random.nextDouble()));
}
private void rollbackWhenActive() {
if (_db.isActive()) {
try { _db.rollback(); } catch (Exception ee) { }
}
}
public boolean isDone() {
return _isDone;
}
}