/* * 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.test06; import java.util.Enumeration; import java.util.Random; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.exolab.castor.jdo.Database; import org.exolab.castor.jdo.LockNotGrantedException; import org.exolab.castor.jdo.OQLQuery; import org.exolab.castor.jdo.PersistenceException; import org.exolab.castor.jdo.QueryException; import org.exolab.castor.jdo.QueryResults; import org.exolab.castor.jdo.TransactionAbortedException; import org.exolab.castor.jdo.TransactionNotInProgressException; import org.junit.Ignore; @Ignore public class RaceThread 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(RaceThread.class); private TestRaceCondition _parent; private Database _db; private RaceSync[] _race; private int _trials; private Random _random; private boolean _isDone; private Exception _fatal; RaceThread(final TestRaceCondition parent, final Database db, final RaceSync[] race, final int trials) { _parent = parent; _db = db; _race = race; _trials = trials; _random = new Random(); } public void run() { try { LOG.info("start testing"); out: for (int j = 0; j < _trials; j++) { some: for (int i = 0; i < _race.length; i++) { boolean isOk = false; int count = 0; // select and inc the jdo object. while (!isOk) { try { isOk = process(i); } catch (TransactionAbortedException ex) { // this exception should happen one in a while. count++; rollbackExpected(_db, ex); if (count > 10) { break some; } } catch (LockNotGrantedException ex) { count++; rollbackExpected(_db, ex); if (count > 10) { break some; } } catch (QueryException ex) { rollbackUnexpected(_db, ex, "Unexcepted exception: "); break out; } catch (TransactionNotInProgressException ex) { rollbackUnexpected(_db, ex, "Unexcepted exception: "); break out; } catch (PersistenceException ex) { rollbackUnexpected(_db, ex, "Unexcepted exception: "); break out; } catch (NoSuchElementException ex) { rollbackUnexpected(_db, ex, "Element not found (leakage): "); break out; } catch (Exception ex) { rollbackUnexpected(_db, ex, "Element not found (other): "); break out; } } // inc the control value (objects are thread safe) _race[i].incValue1(); // make some non-deterministicity. otherwise, we are // just lining up thread and won't discover problem. try { Thread.sleep((long) (100 * _random.nextDouble())); } catch (InterruptedException ex) { LOG.error(ex); break out; } } } } catch (Exception ex) { _fatal = ex; } finally { try { _isDone = true; _parent.getMain().join(); } catch (Exception ee) { if (_fatal != null) { _fatal = ee; } } } } private boolean process(final int i) throws Exception { if ((i % 4) == 0) { _db.begin(); LOG.debug("trying Query.execute()"); OQLQuery oql = _db.getOQLQuery("SELECT object FROM " + TestRaceCondition.getClassName() + " object WHERE id = $1"); oql.bind(i); QueryResults enumeration = oql.execute(); if (enumeration.hasMore()) { Race tr = (Race) enumeration.next(); tr.incValue1(); _db.commit(); return true; } LOG.error("Error: element not found!! missed in cache?\n"); rollback(_db); throw new NoSuchElementException("No element found (a)."); } else if ((i % 4) == 1) { _db.begin(); LOG.debug("trying Query.execute()"); OQLQuery oql = _db.getOQLQuery("SELECT object FROM " + TestRaceCondition.getClassName() + " object WHERE id = $1"); oql.bind(i); Enumeration<?> enumeration = oql.execute(); if (enumeration.hasMoreElements()) { Race tr = (Race) enumeration.nextElement(); tr.incValue1(); _db.commit(); return true; } LOG.error("Error: element not found!! missed in cache?\n"); rollback(_db); throw new NoSuchElementException("No element found (b)."); } else if ((i % 4) == 2) { _db.begin(); LOG.debug("trying Database.load()"); Race tr = (Race) _db.load(TestRaceCondition.getClassType(), new Integer(i), Database.SHARED); if (tr != null) { tr.incValue1(); _db.commit(); return true; } LOG.error("Error: element not found!! missed in cache?\n"); rollback(_db); throw new NoSuchElementException("No element found (c)."); } else if ((i % 4) == 3) { _db.begin(); LOG.debug("trying Database.load()"); Race tr = (Race) _db.load(TestRaceCondition.getClassType(), new Integer(i), Database.EXCLUSIVE); if (tr != null) { tr.incValue1(); _db.commit(); return true; } LOG.error("Error: element not found!! missed in cache?\n"); rollback(_db); throw new NoSuchElementException("No element found (c)."); } else { throw new IllegalArgumentException("??????????????"); } } private void rollbackExpected(final Database db, final Exception ex) { LOG.info("Excepted exception: ", ex); rollback(db); } private void rollbackUnexpected(final Database db, final Exception ex, final String msg) { LOG.error("Thread will be killed. " + msg, ex); rollback(db); TestRaceCondition.setLeak(true); } private void rollback(final Database db) { if (db.isActive()) { try { db.rollback(); } catch (Exception ex) { } } } public boolean isDone() { return _isDone; } public Exception getException() { return _fatal; } }